組込みのJDKアクセス権タイプについてと、各アクセス権の付与の関連リスクについて情報を示します。正常実行のためにアクセス権を有効にする必要があるメソッドについての情報、およびメソッドごとの必要なアクセス権のリストです。
アクセス権は、システム・リソースへのアクセスを表します。アプレット(またはセキュリティ・マネージャとともに実行するアプリケーション)が、リソースへのアクセスを許可されるためには、アクセスを試みるコードに対し、該当するアクセス権を明示的に与える必要があります。
一般に、アクセス権には名前(「ターゲット名」とも呼ばれる)があり、場合によっては、カンマで区切られた1つ以上のアクションのリストを持つこともあります。
たとえば、次のコードでは、/tmp
ディレクトリのabc
という名前のファイルへの読取りアクセスを表すFilePermission
オブジェクトを作成します。
perm = new java.io.FilePermission("/tmp/abc", "read");
ここでは、ターゲット名が/tmp/abc
で、アクション文字列がread
になります。
重要:
前述の文によって、アクセス権オブジェクトが作成されます。アクセス権オブジェクトは、システム・リソースを表しますが、システム・リソースへのアクセスを許可することはありません。アクセス権オブジェクトは、実効性のあるポリシーに基づいて作成され、コードへ割り当てられ(「付与」され)ます。アクセス権オブジェクトが、あるコードに割り当てられると、そのコードはアクセス権オブジェクトで指定されたシステム・リソースへ、指定された方法でアクセスするアクセス権が付与されます。現在のセキュリティ・マネージャが、アクセス判断を行う際に、アクセス権オブジェクトを作成することもあります。この場合、ターゲットのアクセス権オブジェクトは、要求されたアクセスに基づいて作成されます。さらに、ターゲットのアクセス権オブジェクトは、要求を行うコードに付与され、かつ要求を行うコードが保持する、アクセス権オブジェクトに照らしてチェックされます。"JavaPolicy"
Policy実装では、1つまたは複数のポリシー構成ファイルからポリシーを指定できます。ポリシー・ファイルは、指定したコード・ソースのコードにどのアクセス権を許可するかを指定します。たとえば、/home/sysadmin
ディレクトリのコードに対して/tmp/abc
ファイルへの読取りアクセスを許可する場合、ポリシー・ファイルのエントリは次のようになります。grant codeBase "file:/home/sysadmin/" { permission java.io.FilePermission "/tmp/abc", "read"; };ポリシー・ファイルの場所、およびポリシー・ファイルにより付与するアクセス権の詳細は、デフォルトのPolicyの実装とポリシー・ファイルの構文を参照してください。
組込みのJDKアクセス権タイプ、および各アクセス権の付与のリスクのリストを示します。
NIO関連のターゲット名です。
selectorProvider charsetProviderこれらのRuntimePermissionは、java.nio.channel.spi.SelectorProviderまたはjava.nio.charset.spi.CharsetProviderをサブクラス化して実装するクラスに付与する必要があります。アクセス権は、抽象基底クラス・コンストラクタの呼出し時にチェックされます。これらのアクセス権は、重要なプロバイダ・メカニズムを実装するクラスの信頼性を保証します。詳細は、
java.nio.channels.spi.SelectorProvider
java.nio.channels.spi.CharsetProvider
を参照してください。アクセス権が必要なすべてのメソッドと、各メソッドが呼び出す対応するSecurityManager
メソッドのリストを示します。
注意:
このドキュメントで示されるすべてのメソッドのリストは完全なものではなく、アクセス権が必要な一部のメソッドは含まれていません。SecurityException
をスローするメソッドと必要なアクセス権の追加情報は、APIドキュメント
を参照してください。SecurityManager
メソッドのデフォルトの実装では、SecurityManagerメソッド列の対応するエントリで示されているアクセス権が現在有効なポリシーで与えられている場合だけ、メソッド列で示したメソッドを呼び出すことができます。
例1-1 SecurityManager checkPermissionメソッド
java.awt.Toolkit
クラスのgetSystemEventQueue
メソッドは、結果的にSecurityManagerメソッドcheckPermission
を呼び出します。これは、呼出しスタック上のコードに次のアクセス権が与えられている場合にのみ成功します。java.awt.AWTPermission "accessEventQueue";
メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
java.awt.Toolkit getSystemEventQueue(); |
checkPermission |
java.awt.AWTPermission "accessEventQueue"; |
次の表記規則は、アクセス権名中の文字列{foo}
はfoo
の実行時の値で置き換えられるという意味です。
メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
some.package.class public static void someMethod(String foo); |
checkXXX |
SomePermission "{foo}"; |
例1-2 SecurityManager checkReadメソッド
java.io.FileInputStream
クラスのFileInputStream
メソッドは、結果的にSecurityManagerメソッドcheckRead
を呼び出します。これは、呼出しスタック上のコードに次のアクセス権が与えられている場合にのみ成功します。メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
java.io.FileInputStream FileInputStream(String name) |
checkRead(String) |
java.io.FilePermission "{name}", "read"; |
FileInputStream
メソッド(この場合はコンストラクタ)を、次のように引数name
に/test/MyTestFile
を指定して呼び出したとします。
FileInputStream("/test/MyTestFile");
この呼出しは、現在のポリシーで次のアクセス権が設定され、/test/MyTestFile
ファイルへの読取りアクセスが許可されていないと行えません。
java.io.FilePermission "/test/MyTestFile", "read";
より正確には、アクセス権は、このように明示的に設定されているか、次のように、別のアクセス権により暗黙に設定されている必要があります。
java.io.FilePermission "/test/*", "read";
「/test
」ディレクトリに含まれる任意のファイルへの読取りアクセスが許可されています。
例1-3 SecurityManager checkAcceptメソッド
中カッコで囲まれた項目が、特定のメソッド引数の名前と同一ではなく、関係のある値を表す場合もあります。
メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
java.net.DatagramSocket public synchronized void receive(DatagramPacket p); |
checkAccept({host}, {port}) |
java.net.SocketPermission "{host}:{port}", "accept"; |
ここでは、適切なホストおよびポートの値がreceive
メソッドにより計算されて、checkAccept
に渡されます。
ほとんどの場合、呼び出されるSecurityManagerメソッドの名前のみが一覧表示されます。メソッドは、複数ある同名のメソッドのいずれかであり、引数の型も一覧表示されます。たとえば、checkRead(String)
やcheckRead(FileDescriptor)
などがあります。引数が関係するその他の場合にも、引数は一覧表示されます。
メソッドおよびそのアクセス権
次の表は、パッケージ名順になっています。最初にjava.awt
パッケージ内のクラスのメソッド、次にjava.io
パッケージ内のクラスのメソッド、という順番です。
表1-6 メソッドおよびそのアクセス権
メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
java.awt.Graphics2d public abstract void setComposite(Composite comp) |
checkPermission | このGraphics2Dコンテキストが表示画面上のComponentに描画中であり、かつCompositeがAlphaCompositeクラスのインスタンスではなく、カスタム・オブジェクトの場合、java.awt.AWTPermission "readDisplayPixels"。注: setCompositeメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。こうした条件下では、メソッドの実際の実装ごとに、java.awt.AWTPermission("readDisplayPixels")アクセス権でjava.lang.SecurityManager checkPermissionメソッドを呼び出すべきである。 |
java.awt.Robot public Robot() public Robot(GraphicsDevice screen) |
checkPermission | java.awt.AWTPermission "createRobot" |
java.awt.Toolkit public void addAWTEventListener( AWTEventListener listener, long eventMask) public void removeAWTEventListener( AWTEventListener listener) |
checkPermission | java.awt.AWTPermission "listenToAllAWTEvents" |
java.awt.Toolkit public abstract PrintJob getPrintJob( Frame frame, String jobtitle, Properties props) |
checkPrintJobAccess | java.lang.RuntimePermission "queuePrintJob" 注: getPrintJobメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。このメソッドの実際の各実装部分では、java.lang.SecurityManagerのcheckPrintJobAccessメソッドを呼び出すべきであり、これは、アクセス権java.lang.RuntimePermission "queuePrintJob"が現在許可されている場合にのみ成功する。 |
java.awt.Toolkit public abstract Clipboard getSystemClipboard() |
checkPermission | java.awt.AWTPermission "accessClipboard" 注: getSystemClipboardメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。このメソッドの実際の各実装部分では、checkPermissionメソッドを呼び出すべきであり、これは、アクセス権java.awt.AWTPermission "accessClipboard"が現在許可されている場合にのみ成功する。 |
java.awt.Toolkit public final EventQueue getSystemEventQueue() |
checkPermission | java.awt.AWTPermission "accessEventQueue" |
java.awt.Window Window() |
checkPermission | java.awt.AWTPermission "showWindowWithoutWarningBanner"が設定されていると、ウィンドウが表示されるときに、そのウィンドウがアプレットによって作成されていることを警告するバナーは表示されない。設定されていない場合は、バナーが表示される。 |
java.beans.Beans public static void setDesignTime( boolean isDesignTime) public static void setGuiAvailable( boolean isGuiAvailable) java.beans.Introspector public static synchronized void setBeanInfoSearchPath(String path[]) java.beans.PropertyEditorManager public static void registerEditor( Class targetType, Class editorClass) public static synchronized void setEditorSearchPath(String path[]) |
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
java.io.File public boolean delete() public void deleteOnExit() |
checkDelete(String) | java.io.FilePermission "{name}", "delete" |
java.io.FileInputStream FileInputStream(FileDescriptor fdObj) |
checkRead(FileDescriptor) | java.lang.RuntimePermission "readFileDescriptor" |
java.io.FileInputStream FileInputStream(String name) FileInputStream(File file) java.io.File public boolean exists() public boolean canRead() public boolean isFile() public boolean isDirectory() public boolean isHidden() public long lastModified() public long length() public String[] list() public String[] list( FilenameFilter filter) public File[] listFiles() public File[] listFiles( FilenameFilter filter) public File[] listFiles( FileFilter filter) java.io.RandomAccessFile RandomAccessFile(String name, String mode) RandomAccessFile(File file, String mode) (where mode is "r" in both of these) |
checkRead(String) | java.io.FilePermission "{name}", "read" |
java.io.FileOutputStream FileOutputStream(FileDescriptor fdObj) |
checkWrite(FileDescriptor) | java.lang.RuntimePermission "writeFileDescriptor" |
java.io.FileOutputStream FileOutputStream(File file) FileOutputStream(String name) FileOutputStream(String name, boolean append) java.io.File public boolean canWrite() public boolean createNewFile() public static File createTempFile( String prefix, String suffix) public static File createTempFile( String prefix, String suffix, File directory) public boolean mkdir() public boolean mkdirs() public boolean renameTo(File dest) public boolean setLastModified(long time) public boolean setReadOnly() |
checkWrite(String) | java.io.FilePermission "{name}", "write" |
java.io.ObjectInputStream protected final boolean enableResolveObject(boolean enable); java.io.ObjectOutputStream protected final boolean enableReplaceObject(boolean enable) |
checkPermission | java.io.SerializablePermission "enableSubstitution" |
java.io.ObjectInputStream protected ObjectInputStream() java.io.ObjectOutputStream protected ObjectOutputStream() |
checkPermission | java.io.SerializablePermission "enableSubclassImplementation" |
java.io.RandomAccessFile RandomAccessFile(String name, String mode) (where mode is "rw") |
checkRead(String) and checkWrite(String) | java.io.FilePermission "{name}", "read,write" |
java.lang.Class public static Class forName( String name, boolean initialize, ClassLoader loader) |
checkPermission | loader がnullで、呼出し側のクラス・ローダーはnullでない場合、java.lang.RuntimePermission("getClassLoader") になる。 |
java.lang.Class public ClassLoader getClassLoader() |
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、クラス・ローダーが要求されているクラスのクラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。 |
java.lang.Class public Class[] getDeclaredClasses() public Field[] getDeclaredFields() public Method[] getDeclaredMethods() public Constructor[] getDeclaredConstructors() public Field getDeclaredField( String name) public Method getDeclaredMethod(...) public Constructor getDeclaredConstructor(...) |
checkMemberAccess(this, Member.DECLARED)、およびこのクラスがパッケージ内にある場合はcheckPackageAccess({pkgName}) | 「この」クラスのクラス・ローダーが呼出し側のクラス・ローダーと同一である場合は、デフォルトのcheckMemberAccessはどのようなアクセス権も必要としない。同一でない場合は、java.lang.RuntimePermission "accessDeclaredMembers"が必要。このクラスがパッケージ内にある場合、java.lang.RuntimePermission "accessClassInPackage.{pkgName}"も必要。 |
java.lang.Class public Class[] getClasses() public Field[] getFields() public Method[] getMethods() public Constructor[] getConstructors() public Field getField(String name) public Method getMethod(...) public Constructor getConstructor(...) |
checkMemberAccess(this, Member.PUBLIC)、およびこのクラスがパッケージ内にある場合はcheckPackageAccess({pkgName}) | アクセス・タイプがMember.PUBLICの場合、デフォルトのcheckMemberAccessはどのようなアクセス権も必要としない。このクラスがパッケージ内にある場合、java.lang.RuntimePermission "accessClassInPackage.{pkgName}"が必要。 |
java.lang.Class public ProtectionDomain getProtectionDomain() |
checkPermission | java.lang.RuntimePermission "getProtectionDomain" |
java.lang.ClassLoader ClassLoader() ClassLoader(ClassLoader parent) |
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
java.lang.ClassLoader public static ClassLoader getSystemClassLoader() public ClassLoader getParent() |
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、クラス・ローダーが要求されているクラスのクラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。 |
java.lang.Runtime public Process exec(String command) public Process exec(String command, String envp[]) public Process exec(String cmdarray[]) public Process exec(String cmdarray[], String envp[]) |
checkExec | java.io.FilePermission "{command}", "execute" |
java.lang.Runtime public void exit(int status) public static void runFinalizersOnExit(boolean value) java.lang.System public static void exit(int status) public static void runFinalizersOnExit(boolean value) |
checkExit(status)。このとき、runFinalizersOnExitに対してstatusは0 | java.lang.RuntimePermission "exitVM.{status}" |
java.lang.Runtime public void addShutdownHook(Thread hook) public boolean removeShutdownHook(Thread hook) |
checkPermission | java.lang.RuntimePermission "shutdownHooks" |
java.lang.Runtime public void load(String lib) public void loadLibrary(String lib) java.lang.System public static void load(String filename) public static void loadLibrary( String libname) |
checkLink({libName})ただし、{libName}はlib、filenameまたはlibname引数 | java.lang.RuntimePermission "loadLibrary.{libName}" |
java.lang.SecurityManager methods |
checkPermission | 表1-7を参照してください。 |
java.lang.System public static Properties getProperties() public static void setProperties(Properties props) |
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
java.lang.System public static String getProperty(String key) public static String getProperty(String key, String def) |
checkPropertyAccess | java.util.PropertyPermission "{key}", "read" |
java.lang.System public static void setIn(InputStream in) public static void setOut(PrintStream out) public static void setErr(PrintStream err) |
checkPermission | java.lang.RuntimePermission "setIO" |
java.lang.System public static String setProperty(String key, String value) |
checkPermission | java.util.PropertyPermission "{key}", "write" |
java.lang.System public static synchronized void setSecurityManager(SecurityManager s) |
checkPermission | java.lang.RuntimePermission "setSecurityManager" |
java.lang.Thread public ClassLoader getContextClassLoader() |
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、コンテキスト・クラス・ローダーが要求されているスレッドのコンテキスト・クラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。 |
java.lang.Thread public void setContextClassLoader (ClassLoader cl) |
checkPermission | java.lang.RuntimePermission "setContextClassLoader" |
java.lang.Thread public final void checkAccess() public void interrupt() public final void suspend() public final void resume() public final void setPriority (int newPriority) public final void setName(String name) public final void setDaemon(boolean on) |
checkAccess(this) | java.lang.RuntimePermission "modifyThread" |
java.lang.Thread public static int enumerate(Thread tarray[]) |
checkAccess({threadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
java.lang.Thread public final void stop() |
checkAccess(this)。現在のスレッドが自分以外のスレッドを停止させようとしている場合は、checkPermissionも呼び出される。 | java.lang.RuntimePermission "modifyThread"。 現在のスレッドが自分以外のスレッドを停止させようとしている場合、 |
java.lang.Thread public final synchronized void stop(Throwable obj) |
checkAccess(this)。現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスでない場合は、checkPermissionも呼び出される。 | java.lang.RuntimePermission "modifyThread"。 現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスではない場合は、 |
java.lang.Thread Thread() Thread(Runnable target) Thread(String name) Thread(Runnable target, String name) java.lang.ThreadGroup ThreadGroup(String name) ThreadGroup(ThreadGroup parent, String name) |
checkAccess({parentThreadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
java.lang.Thread Thread(ThreadGroup group, ...) java.lang.ThreadGroup public final void checkAccess() public int enumerate(Thread list[]) public int enumerate(Thread list[], boolean recurse) public int enumerate(ThreadGroup list[]) public int enumerate(ThreadGroup list[], boolean recurse) public final ThreadGroup getParent() public final void setDaemon(boolean daemon) public final void setMaxPriority(int pri) public final void suspend() public final void resume() public final void destroy() |
ThreadGroupメソッドの場合はcheckAccess(this)、Threadメソッドの場合はcheckAccess(group) | java.lang.RuntimePermission "modifyThreadGroup" |
java.lang.ThreadGroup public final void interrupt() |
checkAccess(this) | java.lang.RuntimePermission "modifyThreadGroup" が必要。スレッド・グループ内とそのすべてのサブグループ内のスレッドごとにjava.lang.Thread interrupt()メソッドが呼び出されるため、java.lang.RuntimePermission "modifyThread" も必要。Thread interrupt()メソッドを参照。 |
java.lang.ThreadGroup public final void stop() |
checkAccess(this) | java.lang.RuntimePermission "modifyThreadGroup" が必要。java.lang.Threadのstop()メソッドは、そのスレッド・グループ内およびそのすべてのサブグループ内のスレッドごとに呼び出されるので、java.lang.RuntimePermission "modifyThread" および場合によってはjava.lang.RuntimePermission "stopThread" も必要。Threadのstop()メソッドを参照。 |
java.lang.reflect.AccessibleObject public static void setAccessible(...) public void setAccessible(...) |
checkPermission | java.lang.reflect.ReflectPermission "suppressAccessChecks" |
java.net.Authenticator public static PasswordAuthentication requestPasswordAuthentication( InetAddress addr, int port, String protocol, String prompt, String scheme) |
checkPermission | java.net.NetPermission "requestPasswordAuthentication" |
java.net.Authenticator public static void setDefault(Authenticator a) |
checkPermission | java.net.NetPermission "setDefaultAuthenticator" |
java.net.MulticastSocket public void joinGroup(InetAddress mcastaddr) public void leaveGroup(InetAddress mcastaddr) |
checkMulticast(InetAddress) | java.net.SocketPermission( mcastaddr.getHostAddress(), "accept,connect") |
java.net.DatagramSocket public void send(DatagramPacket p) |
checkMulticast(p.getAddress())または checkConnect( p.getAddress().getHostAddress(), p.getPort()) |
if (p.getAddress().isMulticastAddress()) { java.net.SocketPermission( (p.getAddress()).getHostAddress(), "accept,connect") } else {port = p.getPort(); host = p.getAddress().getHostAddress(); if (port == -1) java.net.SocketPermission "{host}","resolve"; else java.net.SocketPermission "{host}:{port}","connect" |
java.net.MulticastSocket public synchronized void send(DatagramPacket p, byte ttl) |
checkMulticast(p.getAddress(), ttl)または checkConnect( p.getAddress().getHostAddress(), p.getPort()) |
if (p.getAddress().isMulticastAddress()) { java.net.SocketPermission( (p.getAddress()).getHostAddress(), "accept,connect") } else { port = p.getPort(); host = p.getAddress().getHostAddress(); if (port == -1) java.net.SocketPermission "{host}","resolve"; else java.net.SocketPermission "{host}:{port}","connect" } |
java.net.InetAddress public String getHostName() public static InetAddress[] getAllByName(String host) public static InetAddress getLocalHost() java.net.DatagramSocket public InetAddress getLocalAddress() |
checkConnect({host}, -1) | java.net.SocketPermission "{host}", "resolve" |
java.net.ServerSocket ServerSocket(...) java.net.DatagramSocket DatagramSocket(...) java.net.MulticastSocket MulticastSocket(...) |
checkListen({port}) | java.net.SocketPermission "localhost:{port}","listen"; |
java.net.ServerSocket public Socket accept() protected final void implAccept(Socket s) |
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
java.net.ServerSocket public static synchronized void setSocketFactory(...) java.net.Socket public static synchronized void setSocketImplFactory(...) java.net.URL public static synchronized void setURLStreamHandlerFactory(...) java.net.URLConnection public static synchronized void setContentHandlerFactory(...) public static void setFileNameMap(FileNameMap map) java.net.HttpURLConnection public static void setFollowRedirects(boolean set) java.rmi.activation.ActivationGroup public static synchronized ActivationGroup createGroup(...) public static synchronized void setSystem(ActivationSystem system) java.rmi.server.RMISocketFactory public synchronized static void setSocketFactory(...) |
checkSetFactory | java.lang.RuntimePermission "setFactory" |
java.net.Socket Socket(...) |
checkConnect({host}, {port}) | java.net.SocketPermission "{host}:{port}", "connect" |
java.net.DatagramSocket public synchronized void receive(DatagramPacket p) |
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
java.net.URL URL(...) |
checkPermission | java.net.NetPermission "specifyStreamHandler" |
java.net.URLClassLoader URLClassLoader(...) |
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
java.security.AccessControlContext public AccessControlContext(AccessControlContext acc, DomainCombiner combiner) public DomainCombiner getDomainCombiner() |
checkPermission | java.security.SecurityPermission "createAccessControlContext" |
java.security.Identity public void addCertificate(...) |
checkSecurityAccess( "addIdentityCertificate") | java.security.SecurityPermission "addIdentityCertificate" |
java.security.Identity public void removeCertificate(...) |
checkSecurityAccess( "removeIdentityCertificate") | java.security.SecurityPermission "removeIdentityCertificate" |
java.security.Identity public void setInfo(String info) |
checkSecurityAccess( "setIdentityInfo") | java.security.SecurityPermission "setIdentityInfo" |
java.security.Identity public void setPublicKey(PublicKey key) |
checkSecurityAccess( "setIdentityPublicKey") | java.security.SecurityPermission "setIdentityPublicKey" |
java.security.Identity public String toString(...) |
checkSecurityAccess( "printIdentity") | java.security.SecurityPermission "printIdentity" |
java.security.IdentityScope protected static void setSystemScope() |
checkSecurityAccess( "setSystemScope") | java.security.SecurityPermission "setSystemScope" |
java.security.Permission public void checkGuard(Object object) |
checkPermission(this) | このアクセス権オブジェクトはチェックされたアクセス権である |
java.security.Policy public static Policy getPolicy() |
checkPermission | java.security.SecurityPermission "getPolicy" |
java.security.Policy public static void setPolicy(Policy policy) |
checkPermission | java.security.SecurityPermission "setPolicy" |
java.security.Policy public static Policy getInstance(String type, SpiParameter params) getInstance(String type, SpiParameter params, String provider) getInstance(String type, SpiParameter params, Provider provider) |
checkPermission | java.security.SecurityPermission "createPolicy.{type}" |
java.security.Provider public synchronized void clear() |
checkSecurityAccess( "clearProviderProperties."+{name}) | java.security.SecurityPermission "clearProviderProperties.{name}" (nameはプロバイダ名)。 |
java.security.Provider public synchronized Object put(Object key, Object value) |
checkSecurityAccess( "putProviderProperty."+{name}) | java.security.SecurityPermission "putProviderProperty.{name}" (nameはプロバイダ名)。 |
java.security.Provider public synchronized Object remove(Object key) |
checkSecurityAccess( "removeProviderProperty."+{name}) | java.security.SecurityPermission "removeProviderProperty.{name}" (nameはプロバイダ名)。 |
java.security.SecureClassLoader SecureClassLoader(...) |
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
java.security.Security public static void getProperty(String key) |
checkPermission | java.security.SecurityPermission "getProperty.{key}" |
java.security.Security public static int addProvider(Provider provider) public static int insertProviderAt(Provider provider, int position); |
checkSecurityAccess( "insertProvider."+provider.getName()) | java.security.SecurityPermission "insertProvider.{name}" |
java.security.Security public static void removeProvider(String name) |
checkSecurityAccess( "removeProvider."+name) | java.security.SecurityPermission "removeProvider.{name}" |
java.security.Security public static void setProperty(String key, String datum) |
checkSecurityAccess( "setProperty."+key) | java.security.SecurityPermission "setProperty.{key}" |
java.security.Signer public PrivateKey getPrivateKey() |
checkSecurityAccess( "getSignerPrivateKey") | java.security.SecurityPermission "getSignerPrivateKey" |
java.security.Signer public final void setKeyPair(KeyPair pair) |
checkSecurityAccess( "setSignerKeypair") | java.security.SecurityPermission "setSignerKeypair" |
java.sql.DriverManager public static synchronized void setLogWriter(PrintWriter out) |
checkPermission | java.sql.SQLPermission "setLog" |
java.sql.DriverManager public static synchronized void setLogStream(PrintWriter out) |
checkPermission | java.sql.SQLPermission "setLog" |
java.util.Locale public static synchronized void setDefault(Locale newLocale) |
checkPermission | java.util.PropertyPermission "user.language","write" |
java.util.zip.ZipFile ZipFile(String name) |
checkRead | java.io.FilePermission "{name}","read" |
javax.security.auth.Subject public static Subject getSubject(final AccessControlContext acc) |
checkPermission | javax.security.auth.AuthPermission "getSubject" |
javax.security.auth.Subject public void setReadOnly() |
checkPermission | javax.security.auth.AuthPermission "setReadOnly" |
javax.security.auth.Subject public static Object doAs(final Subject subject, final PrivilegedAction action) |
checkPermission | javax.security.auth.AuthPermission "doAs" |
javax.security.auth.Subject public static Object doAs(final Subject subject, final PrivilegedExceptionAction action) throws java.security.PrivilegedActionException |
checkPermission | javax.security.auth.AuthPermission "doAs" |
javax.security.auth.Subject public static Object doAsPrivileged(final Subject subject, final PrivilegedAction action, final AccessControlContext acc) |
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
javax.security.auth.Subject public static Object doAsPrivileged(final Subject subject, final PrivilegedExceptionAction action, final AccessControlContext acc) throws java.security.PrivilegedActionException |
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
javax.security.auth.SubjectDomainCombiner public Subject getSubject() |
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
javax.security.auth.SubjectDomainCombiner public Subject getSubject() |
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
javax.security.auth.login.LoginContext public LoginContext(String name) throws LoginException |
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
javax.security.auth.login.LoginContext public LoginContext(String name, Subject subject) throws LoginException |
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
javax.security.auth.login.LoginContext public LoginContext(String name, CallbackHandler callbackHandler) throws LoginException |
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
javax.security.auth.login.LoginContext public LoginContext(String name, Subject subject, CallbackHandler callbackHandler) throws LoginException |
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
javax.security.auth.login.Configuration public static Configuration getConfiguration() |
checkPermission | javax.security.auth.AuthPermission "getLoginConfiguration" |
javax.security.auth.login.Configuration public static void setConfiguration(Configuration configuration) |
checkPermission | javax.security.auth.AuthPermission "setLoginConfiguration" |
javax.security.auth.login.Configuration public static void refresh() |
checkPermission | javax.security.auth.AuthPermission "refreshLoginConfiguration" |
javax.security.auth.login.Configuration public static Configuration getInstance(String type, SpiParameter params) getInstance(String type, SpiParameter params, String provider) getInstance(String type, SpiParameter params, Provider provider) |
checkPermission | javax.security.auth.AuthPermission "createLoginConfiguration.{type}" |
java.lang.SecurityManager
メソッドのデフォルトの実装によってチェックされるアクセス権のリストを示します。
指定された各check
メソッドはSecurityManager
checkPermission
メソッドを指定されたアクセス権で呼び出します(コンテキスト引数を取るcheckConnect
およびcheckRead
メソッドを除く)。これらのメソッドは、AccessControlContext
コンテキストを想定し、コンテキストのcheckPermission
メソッドを指定されたアクセス権で呼び出します。
表1-7 java.lang.SecurityManagerのメソッドおよびアクセス権
メソッド | アクセス権 |
---|---|
public void checkAccept(String host, int port); | java.net.SocketPermission "{host}:{port}", "accept"; |
public void checkAccess(Thread t); | java.lang.RuntimePermission "modifyThread"; |
public void checkAccess(ThreadGroup g); | java.lang.RuntimePermission "modifyThreadGroup"; |
public void checkAwtEventQueueAccess(); 注意: このメソッドは推奨されていません。かわりに次を使用してください。public void checkPermission(Permission perm); |
java.awt.AWTPermission "accessEventQueue"; |
public void checkConnect(String host, int port); | if (port == -1) java.net.SocketPermission "{host}","resolve"; else java.net.SocketPermission "{host}:{port}","connect"; |
public void checkConnect(String host, int port, Object context); | if (port == -1) java.net.SocketPermission "{host}","resolve"; else java.net.SocketPermission "{host}:{port}","connect"; |
public void checkCreateClassLoader(); | java.lang.RuntimePermission "createClassLoader"; |
public void checkDelete(String file); | java.io.FilePermission "{file}", "delete"; |
public void checkExec(String cmd); | if cmd is an absolute path:java.io.FilePermission "{cmd}", "execute"; else java.io.FilePermission "<<ALL_FILES>>", "execute"; |
public void checkExit(int status); | java.lang.RuntimePermission "exitVM.{status}"; |
public void checkLink(String lib); | java.lang.RuntimePermission "loadLibrary.{lib}"; |
public void checkListen(int port); | java.net.SocketPermission "localhost:{port}","listen"; |
public void checkMemberAccess(Class clazz, int which); 注意: このメソッドは推奨されていません。かわりに次を使用してください。public void checkPermission(Permission perm); |
if (which != Member.PUBLIC) { if (currentClassLoader() != clazz.getClassLoader()) { checkPermission( new java.lang.RuntimePermission("accessDeclaredMembers")); } } |
public void checkMulticast(InetAddress maddr); | java.net.SocketPermission(maddr.getHostAddress(),"accept,connect"); |
public void checkMulticast(InetAddress maddr, byte ttl); 注意: このメソッドは推奨されていません。かわりに次を使用してください。public void checkPermission(Permission perm); |
java.net.SocketPermission(maddr.getHostAddress(),"accept,connect"); |
public void checkPackageAccess(String pkg); | java.lang.RuntimePermission "accessClassInPackage.{pkg}"; |
public void checkPackageDefinition(String pkg); | java.lang.RuntimePermission "defineClassInPackage.{pkg}"; |
public void checkPrintJobAccess(); | java.lang.RuntimePermission "queuePrintJob"; |
public void checkPropertiesAccess(); | java.util.PropertyPermission "*", "read,write"; |
public void checkPropertyAccess(String key); | java.util.PropertyPermission "{key}", "read,write"; |
public void checkRead(FileDescriptor fd); | java.lang.RuntimePermission "readFileDescriptor"; |
public void checkRead(String file); | java.io.FilePermission "{file}", "read"; |
public void checkRead(String file, Object context); | java.io.FilePermission "{file}", "read"; |
public void checkSecurityAccess(String target); | java.security.SecurityPermission "{target}"; |
public void checkSetFactory(); | java.lang.RuntimePermission "setFactory"; |
public void checkSystemClipboardAccess(); 注意: このメソッドは推奨されていません。かわりに次を使用してください。public void checkPermission(Permission perm); |
java.awt.AWTPermission "accessClipboard"; |
public boolean checkTopLevelWindow(Object window); 注意: このメソッドは推奨されていません。かわりに次を使用してください。public void checkPermission(Permission perm); |
java.awt.AWTPermission "showWindowWithoutWarningBanner"; |
public void checkWrite(FileDescriptor fd); | java.lang.RuntimePermission "writeFileDescriptor"; |
public void checkWrite(String file); | java.io.FilePermission "{file}", "write"; |
public SecurityManager(); | java.lang.RuntimePermission "createSecurityManager"; |
Javaプログラミング言語のアプリケーション環境のポリシーは、様々なソースを出所とするコードがどのようなアクセス権を使用できるかを指定し、様々なプリンシパルとして実行するもので、Policyオブジェクトによって表されます。具体的には、Policy
クラス(java.security
パッケージ内)内のabstractメソッドの実装を提供するPolicy
サブクラスによって表されます。
Policyオブジェクトが使用するポリシー情報がどこに置かれるかは、Policyの実装によります。Policyのリファレンス実装では、ポリシー情報を静的なポリシー構成ファイルから得ます。
このドキュメントの残りの部分では、Policyのリファレンス実装と、それによって読み取られるポリシー・ファイルで使用する構文について説明します。
任意のテキスト・エディタでポリシー・ファイルを作成します。
Policyのリファレンス実装では、1つまたは複数のポリシー構成ファイルからポリシーを指定できます。ポリシー構成ファイルでは、指定されたコード・ソースからのコードに対してどのようなアクセス権を与え、指定されたプリンシパルとして実行するかを指定します。各構成ファイルは、UTF-8方式でエンコードする必要があります。
デフォルトでは、システム全体のポリシー・ファイルが1つと、ユーザー・ポリシー・ファイル(オプション)が1つ存在します。デフォルトでは、常に、プラットフォーム・クラス・ローダーによってロードされるJDKモジュールまたはその祖先で必要なアクセス権が付与されます。
Policyのリファレンス実装は、そのgetPermissionsメソッドがはじめて呼び出されたとき、あるいは、そのrefreshメソッドが呼び出されたときに初期化されます。初期化時には、ポリシー構成ファイル(ポリシー・ファイルの構文を参照)の解析が行われた後、その情報がPolicyオブジェクトに読み込まれます。
デフォルトでは、システム全体のポリシー・ファイルが1つと、ユーザー・ポリシー・ファイル(オプション)が1つ存在します。Policyが初期化されると、まずシステム・ポリシーがロードされ、次に、ロードされたシステム・ポリシーにユーザー・ポリシーが追加されます。どちらのポリシーも存在しない場合は、組込みポリシーが使われます。この組込みポリシーは、JREとともにインストールしたjava.policy
ファイルと同じです。
システム・ポリシー・ファイルの場所
デフォルトでは、システム・ポリシー・ファイルは<java-home>/conf/security/java.policy
です。
システムのポリシー・ファイルは、システム全体にわたってコードにアクセス権を与えます。JDKに含まれているjava.policy
ファイルは、すべてのユーザーに動的ポートでの待機を許可し、すべてのコードに、セキュリティにかかわらない特定の標準プロパティ(os.name
プロパティやfile.separator
プロパティなど)の読取りを許可します。
ユーザー・ポリシー・ファイルの場所
デフォルトでは、ユーザー・ポリシー・ファイルは<user-home>/.java.policy
です。
ポリシー・ファイルの場所と形式の構成
ポリシー・ファイルの場所は、セキュリティ・プロパティ・ファイル<java-home>/conf/security/java.security
で指定されています。
ポリシー・ファイルの場所は、次のような形式の名前を持つプロパティの値として指定されています。
policy.url.n
ここで、n
は数値です。次に示す形式の行で、それぞれのプロパティの値を指定します。
policy.url.n=URL
ここで、URL
はURLの指定を表します。たとえば、デフォルトのシステムおよびユーザー・ポリシー・ファイルは、セキュリティ・プロパティ・ファイルに次のように指定されています。:
policy.url.1=file:${java.home}/conf/security/java.policy policy.url.2=file:${user.home}/.java.policy
(${java.home}
を使用してjava.home
プロパティの値を指定するなど、特別な構文でプロパティの値を指定する方法については、プロパティの展開を参照。)
URLをいくつも指定して(http://
形式のものを含む)、該当するポリシー・ファイルをすべてロードすることもできます。また、上に示したポリシー・ファイルの指定のうち、2番目のポリシー・ファイルの指定をコメント・アウトするか、あるいは修正すれば、デフォルト・ユーザー・ポリシー・ファイルの読込みを無効にすることができます。
アルゴリズムは、policy.url.1
から処理を開始して、番号を1つずつ増やしながら、URLが見つからなくなるまで処理を続けます。したがって、policy.url.1
とpolicy.url.3
がある場合、policy.url.3
は読み込まれません。
例1-4 実行時に新しいポリシー・ファイルを指定する
アプリケーションを実行するときに、追加のポリシー・ファイルや別のポリシー・ファイルを指定することもできます。これは、
コマンド行引数を使用して-Djava.security.policy
java.security.policy
プロパティの値を設定することで実行できます。たとえば、次のコマンドを入力した場合(ここで、someURL
はポリシー・ファイルの場所を指定するURL)、指定したポリシー・ファイルが、セキュリティ・プロパティ・ファイルに指定されているすべてのポリシー・ファイルに加えてロードされます。
java-Djava.security.manager
-Djava.security.policy
=someURL SomeApp
次に示すとおり、URLは通常のURLでも、単純に現在のディレクトリのポリシー・ファイルの名前でもかまいません。:
java -Djava.security.manager -Djava.security.policy=mypolicy SomeApp
-Djava.security.manager
オプションによってデフォルト・セキュリティ・マネージャがインストールされるので、このアプリケーションに対してはポリシーのチェックが行われます。アプリケーションSomeAppがセキュリティ・マネージャをインストールする場合は、この引数は必要ありません。
次のコマンドを使用した場合(等号が2つ使用されていることに注意)、指定されたポリシー・ファイルのみが使用され、セキュリティ・プロパティ・ファイルに示されたポリシー・ファイルはすべて無視されます。
java-Djava.security.manager
-Djava.security.policy
==someURL SomeApp
注意:
セキュリティ・プロパティ・ファイル内のpolicy.allowSystemProperty
プロパティがfalseに設定されている場合、-Djava.security.policy
オプションのポリシー・ファイル値は無視されます。デフォルトは、trueです。セキュリティ・プロパティ・ファイル(JDKのconf/security
ディレクトリのjava.security
ファイル)を編集すれば、Policyのリファレンス実装を変更できます。
新しいポリシー・クラスを作成し、Policyのリファレンス実装クラスと置き換えることもできます。この場合は、Policy抽象クラスのサブクラスを作成し、getPermissionsメソッド(必要に応じてその他のメソッドも)を実装します。
java.security
で設定できるプロパティの例を次に示します。
policy.provider=PolicyClassName
PolicyClassNameには、目的のPolicy
実装クラスを完全修飾名で指定します。
デフォルトのセキュリティ・プロパティ・ファイルでは、このプロパティは次のように指定されています。
policy.provider=sun.security.provider.PolicyFile
カスタマイズするには、次のように、このプロパティに別のクラスを指定します。
policy.provider=com.mycom.MyPolicy
インストールしたJDKのポリシー構成ファイルでは、指定されたコード・ソースからのコードに対し、どのようなアクセス権(システム・リソースへのアクセスの種類)を与え、指定したプリンシパルとして実行するかを指定します。
アプレット(またはセキュリティ・マネージャの下で動作しているアプリケーション)が、ファイルの読み書きなど、セキュリティ保護された操作を行うためには、その操作を行うためのアクセス権が与えられている必要があります。Policyのリファレンス実装では、ポリシー構成ファイルの付与エントリによって、そのアクセス権を与える必要があります。詳細は、以降の説明とJavaセキュリティ・アーキテクチャ仕様を参照してください。(ただし、同じ(URLの)場所にあるファイルと、その場所のサブディレクトリにあるファイルの読取りアクセス権は、常に自動的に与えられます。したがって、そのようなアクセス権については、明示的に指定する必要はありません。)
ポリシー構成ファイルは、エントリのリストで構成されます。1つのkeystoreエントリと、0以上のgrantエントリを持たせることができます。
キーストアの作成と管理には、keytoolユーティリティを使います。
キーストアは、非公開鍵と、対応する公開鍵を認証するX.509証明書チェーンなどのデジタル証明書が格納されたデータベースです。キーストアの作成と管理には、keytoolユーティリティを使用します。ポリシー構成ファイルで指定されているキーストアは、そのファイルのgrantエントリで指定されている署名者の公開鍵を照合するために使用されます。署名者の別名を指定しているgrantエントリがある場合、またはプリンシパルの別名を指定しているgrantエントリがある場合は、ポリシー構成ファイルに必ずkeystoreエントリを置きます。
このとき、ポリシー・ファイル内で有効なkeystore
/keystorePasswordURL
エントリは1つのみです。最初のエントリ以外の後続エントリは無視されます。このエントリは、ファイルのgrantエントリ外部の任意の場所に配置できます。構文は次のとおりです。
keystore "some_keystore_url", "keystore_type", "keystore_provider"; keystorePasswordURL "some_password_url";
各構成要素は次のとおりです。
注意:
some_keystore_url
からの入力ストリームはKeyStore.loadメソッドに渡されます。
URLとしてNONEが指定されている場合は、nullのストリームがKeyStore.loadメソッドに渡されます。NONEは、キーストアがファイルベースでない場合にURLで指定してください。たとえば、ハードウェア・トークン・デバイスに置かれている場合などです。
URLは、ポリシー・ファイルがある場所からの相対位置を表します。たとえば、セキュリティ・プロパティ・ファイルの中でポリシー・ファイルが次のように指定されているとします。
policy.url.1=http://foo.example.com/fum/some.policy
また、このポリシー・ファイルには、次のエントリがあるとします。
keystore ".keystore";
この場合、キーストアは次の場所からロードされます。
http://foo.example.com/fum/.keystore
URLに絶対位置を指定することもできます。
キーストアのタイプは、キーストア情報の格納形式とデータ形式を定義するとともに、キーストア内の非公開鍵とキーストア自体の整合性を保護するために使われるアルゴリズムを定義します。デフォルトのタイプは、PKCS12という独自のキーストア・タイプです。したがって、キーストアのタイプがPKCS12であれば、キーストア・エントリを指定する必要はありません。
付与エントリは、アクセス権を付与するコードを指定するために使用されます。
実行されるコードは、常に、特定の「コード・ソース」(CodeSource
型のオブジェクトによって表される)から来ると考えられます。コード・ソースは、コードの出所を表す場所(URL)だけでなく、コードの署名に使われた非公開鍵に対応する公開鍵を含んだ証明書への参照も含みます。コード・ソース内の証明書は、ユーザーのキーストアからのシンボリックな別名によって参照されます。コードはさらに、特定のプリンシパル(Principal
型のオブジェクトによって表される)またはプリンシパルのグループとして実行されると考えられます。
各付与エントリには、オプションのcodeBase
とsignedBy
、およびプリンシパルの名前と値のペアのあとに、アクセス権を付与するコードを指定する1つ以上の「アクセス権エントリ」が含まれます。付与エントリの基本形式は、次のとおりです。
grant signedBy "signer_names", codeBase "URL", principal principal_class_name "principal_name", principal principal_class_name "principal_name", ... { permission permission_class_name "target_name", "action", signedBy "signer_names"; permission permission_class_name "target_name", "action", signedBy "signer_names"; ... };
上の形式でイタリック体になっていない項目は、示されているとおりに指定します。ただし、大文字と小文字は区別されず、また、以降で説明するように、いくつかの項目はオプションです。イタリックで示されている項目は、可変の項目です。
付与エントリは、grant
で始まります。
signedBy
、codeBase
、およびprincipal
の値はオプションです。また、これらのフィールドの順序は問われません。
signedBy
の値は、キーストアに格納された証明書の別名を示します。証明書内の公開鍵は、コードのデジタル署名の検証に使われます。別名によって指定されたキーストア・エントリ内の公開鍵に対応する、非公開鍵で署名されたコードに、アクセス権を付与します。
signedBy
の値には、複数の別名をカンマで区切って指定できます。たとえば、"Adam,Eve,Charles"のように指定できます。この場合は、各要素がORではなくANDで結ばれ、「Adam、EveおよびCharlesによって署名された」という意味になります。より厳密には、「Adamによって署名されたコード」とは、「Adamという別名が付けられたエントリを持つキーストアにある公開鍵証明書に対応する、非公開鍵を使って署名されたJARファイルに含まれている、クラス・ファイル内のコード」という意味です。
signedBy
フィールドはオプションです。省略した場合は、「任意の署名者」という意味になります。コードに署名が付いているかどうか、だれが署名しているかは問われなくなります。
プリンシパルの値はclass_name
とprincipal_name
のペアを指定します。このペアは、実行中のスレッドのプリンシパル・セット内にある必要があります。プリンシパル・セットは、Subjectによって実行するコードに関連付けられます。
principal_class_name
にワイルドカード値(*)を設定することで、任意のPrincipal
クラスに一致させることができます。さらに、principal_name
にワイルドカード値(*)を設定することで、任意のPrincipal
名に一致させることができます。principal_class_name
またはprincipal_name
に*を設定するときは、*を引用符で囲まないでください。また、ワイルドカードのプリンシパル・クラスを指定する場合は、ワイルドカードのプリンシパル名も指定する必要があります。
プリンシパル・フィールドは省略可能です。省略した場合は、「任意のプリンシパル」という意味になります。
プリンシパルのclass_name/principal_nameペア
は単一引用符で囲まれた文字列として指定され、キーストアの別名として扱われます。
キーストアは別名を経由してX509証明書を調査し、問い合わせます。キーストアがある場合、プリンシパルclass_nameは自動的にjavax.security.auth.x500.X500Principal
として扱われ、principal_name
は自動的に証明書のサブジェクト識別名として扱われます。X509証明書のマッピングが見つからない場合は、grantエントリはすべて無視されます。
codeBase
の値は、コードが置かれる場所を示します。この場所からコードにアクセス権を付与します。codeBase
エントリを省略した場合は、「任意のコード」という意味になり、コードの出所は問われません。
注意:
codeBase
の値はURLであるため、コード・ソースがWindowsシステム上にある場合であっても、ディレクトリのセパレータには、バックスラッシュではなく、必ずスラッシュを使用します。したがって、Windowsシステム上でコードの場所がC:\somepath\api\
の場合、codeBase
ポリシー・エントリは次のように指定します。grant codeBase "file:/C:/somepath/api/" { ... };
codeBase
値の正確な意味は、末尾の文字によって異なります。末尾が/
のcodeBase
は、指定されたディレクトリ内のすべてのクラス・ファイル(JARファイルを除く)を示します。末尾が/*
のcodeBase
は、そのディレクトリ内にあるすべてのファイル(クラス・ファイルとJARファイルの両方)を示します。末尾が/-
のcodeBase
は、指定されたディレクトリとその下の全サブディレクトリ内のすべてのファイル(クラス・ファイルとJARファイルの両方)を示します。次の表では、様々なケースを示します。
表1-8 キーストア別名
ダウンロードされたコードのcodebase URL | ポリシーのcodebase URL | 一致するかどうか |
---|---|---|
www.example.com/people/gong/ | www.example.com/people/gong | はい |
www.example.com/people/gong/ | www.example.com/people/gong/ | はい |
www.example.com/people/gong/ | www.example.com/people/gong/* | はい |
www.example.com/people/gong/ | www.example.com/people/gong/- | はい |
www.example.com/people/gong/appl.jar | www.example.com/people/gong/ | いいえ |
www.example.com/people/gong/appl.jar | www.example.com/people/gong/- | はい |
www.example.com/people/gong/appl.jar | www.example.com/people/gong/* | はい |
www.example.com/people/gong/appl.jar | www.example.com/people/- | はい |
www.example.com/people/gong/appl.jar | www.example.com/people/* | いいえ |
www.example.com/people/gong/ | www.example.com/people/- | はい |
www.example.com/people/gong/ | www.example.com/people/* | いいえ |
アクセス権エントリは、順序どおり(permission
、permission_class_name、"target_name"、"action"およびsignedBy
"signer_names)に指定されます。
アクセス権エントリは、単語permission
で始まります。前述のテンプレートにある単語permission_class_name
は、実際にはjava.io.FilePermission
やjava.lang.RuntimePermission
などの特定のアクセス権タイプになります。
java.io.FilePermission
(どのような種類のファイル・アクセスを許可するかを指定)など、多くのアクセス権タイプでは"action"が必須です。java.lang.RuntimePermission
などのカテゴリでは不要なため、必須ではありません。permission_class_nameの後の"target_name
"値で指定されたアクセス権が与えられるか、アクセス権が与えられないかのどちらかになります。
アクセス権エントリのsignedBy
の名前と値のペアは省略可能です。この値が存在する場合は、署名付きアクセス権であることを示します。つまり、そのアクセス権を与えられるようにするためには、アクセス権クラスそれ自体が、指定された別名によって署名されていなければなりません。たとえば、次のような付与エントリがあるとします。
grant { permission Foo "foobar", signedBy "FooSoft"; };
この場合、このアクセス権タイプFooが与えられるのは、あるJARファイルにアクセス権Foo.class
が置かれていて、そのJARファイルが、別名FooSoftにより指定された証明書内の公開鍵に対応する非公開鍵によって署名されているときか、Foo.class
がシステム・クラスであるときです(システム・クラスはポリシーによる制限を受けないため)。
アクセス権エントリの各項目は、指定された順序(permission
、permission_class_name、"target_name"、"action"、およびsignedBy
"signer_names")で並んでいる必要があります。各エントリはセミコロンで終わります。
識別子(permission
、signedBy
、codeBase
など)では大文字と小文字は区別されませんが、permission_class_nameと、値として引き渡される文字列については大文字と小文字が区別されます。
Windowsシステムでのファイル・パス仕様には、実際の1つバックスラッシュごとに、2つのバックスラッシュを含める必要があります。
注意:
java.io.FilePermission
を指定する場合、"target_name"はファイル・パスになります。Windowsシステムでは、ファイル・パスをcodeBase URLではなく直接文字列で指定する場合は、パス中のバックスラッシュは、次のように2つ重ねて指定する必要があります。
grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };
これは、文字列はトークナイザ(java.io.StreamTokenizer
)によって処理され、トークナイザは\をエスケープ文字列と解釈するため(たとえば、\nは改行を表す)、バックスラッシュそのものを表すには、バックスラッシュを2つ重ねる必要があるからです。トークナイザは、上記のファイル・パス文字列の処理を終えると、二重のバックスラッシュを単一のバックスラッシュに変換し、最終的には次のようになります。
"C:\users\cathy\foo.bat"
codeBase
値およびsignedBy
値の異なる構成を含むポリシー構成ファイルの例を示します。様々なプリンシパル・ベースのエントリおよびKeyStore値を使用するgrant文の例です。
例1-5 ポリシー構成ファイルの例
ポリシー構成ファイルから取り出した2つのエントリの例を次に示します。
// If the code is signed by "Duke", grant it read/write access to all // files in /tmp: grant signedBy "Duke" { permission java.io.FilePermission "/tmp/*", "read,write"; }; // Grant everyone the following permission: grant { permission java.util.PropertyPermission "java.vendor", "read"; };
例1-6 ポリシー構成ファイルの例
/home/sysadmin/
"ディレクトリにある、署名されたJARファイルからコードがロードされた。sysadmin
によって参照される公開鍵で認証される。grant signedBy "sysadmin", codeBase "file:/home/sysadmin/*" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; permission java.security.SecurityPermission "Security.setProperty.*"; };
例1-7 codeBaseがない場合の例
コード・ソースを指定するコンポーネントは、どちらも(または両方を)省略可能です。codeBase
を省略した例を次に示します。
grant signedBy "sysadmin" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };
このポリシーが有効な場合、sysadmin
によって署名されたJARファイルに含まれるコードは、JARファイルの出所に関係なく、プロバイダの追加と削除を行えます。
例1-8 signedByを使用しない例
grant codeBase "file:/home/sysadmin/-" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };
この場合、ローカル・ファイル・システムの"/home/sysadmin/
"ディレクトリに置かれたコードは、プロバイダの追加と削除を行うことができます。コードに署名は必要ありません。
例1-9 codeBaseまたはsignedByを使用しない例
grant { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };
この例では、コード・ソースを指定する要素がどちらも省略されています。したがって、出所がどこか、署名が付いているか、だれの署名が付いているかに関係なく、どのコードでもプロバイダの追加と削除が行えます。
例1-10 X500Principalとして実行する例
grant principal javax.security.auth.x500.X500Principal "cn=Alice" { permission java.io.FilePermission "/home/Alice", "read, write"; };
これにより、X500Principalのアクセス権cn=Alice
として実行するコードは/home/Alice
を読み取ることも書き込むことも可能になります。
例1-11 識別名を使用せずにX500Principalとして実行する例
grant principal javax.security.auth.x500.X500Principal * { permission java.io.FilePermission "/tmp", "read, write"; };
これにより、X500Principalのアクセス権(識別名に関係なく)として実行するコードは/tmp
を読み取ることも書き込むことも可能になります。
例1-12 CodeBaseおよびX500Principal情報を使用するGrant文
grant codebase "http://www.games.example.com", signedBy "Duke", principal javax.security.auth.x500.X500Principal "cn=Alice" { permission java.io.FilePermission "/tmp/games", "read, write"; };
これにより、"Duke
"によって署名され、"www.games.example.com
"からダウンロードされたコードが"cn=Alice
"によって実行されると、"/tmp/games
"ディレクトリへの読取り権と書出し権が与えられます。
例1-13 キーストア別名を使用するGrant文
keystore "http://foo.example.com/blah/.keystore"; grant principal "alice" { permission java.io.FilePermission "/tmp/games", "read, write"; };
alice
"は次のアクセス権に置き換えられます。javax.security.auth.x500.X500Principal "cn=Alice"ただし、キーストア別名
alice
に関連付けられたX.509証明書に、サブジェクトの識別名cn=Alice
があることが前提となります。これにより、X500Principalのアクセス権"cn=Alice
"によって実行されるコードに、"/tmp/games
"ディレクトリへの読取り権と書出し権が与えられます。ポリシー・ファイルとセキュリティ・プロパティ・ファイルでは、プロパティの展開が可能です。
プロパティの展開は、シェルでの変数の展開に似ています。ポリシー・ファイルまたはセキュリティ・プロパティ・ファイルに次のような文字列がある場合、
${some.property}
この文字列はシステム・プロパティの値に展開されます。次に例を示します。
permission java.io.FilePermission "${user.home}", "read";
この場合、"${user.home}
"は、システム・プロパティ"user.home"の値に展開されます。そのプロパティの値が"/home/cathy
"である場合、上の記述は下の記述と同じになります
permission java.io.FilePermission "/home/cathy", "read";プラットフォームにより異なるポリシー・ファイルを使いやすくするために、
${/}
という特殊な表記(${file.separator}
の簡略形)も使用できます。この表現を使用して、次のような指定が可能です。 permission java.io.FilePermission "${user.home}${/}*", "read";
user.home
プロパティの値が/home/cathy
で、プラットフォームがSolaris、LinuxまたはmacOSである場合、これは次のように変換されます。permission java.io.FilePermission "/home/cathy/*", "read";Windowsシステムで、"
user.home
"の値がC:\users\cathy
であれば、次のように変換されます。 permission java.io.FilePermission "C:\users\cathy\*", "read";特殊なケースとして、コード・ベースのプロパティを次のように記述すると、
grant codeBase "file:${java.home}/lib/ext/"file.separator文字は自動的に
/
に変換されます。したがって、Windowsシステムでは次のように変換されます。 grant codeBase "file:C:/jdk1.4/lib/ext/"
java.home
がC:\jdk1.4\
に設定されている場合でも、コードベース文字列で${/}
を使用する必要はありません(使用しないでください)。プロパティの展開は、ポリシー・ファイル内で、二重引用符で囲まれた文字列が使用できる場所であればどこでも行われます。これには、"signer_names"、"URL"、"target_name"、"action"の各フィールドが含まれます。プロパティの展開が許可されるかどうかは、セキュリティ・プロパティ・ファイルの"policy.expandProperties
"プロパティの値によって決まります。このプロパティの値がtrue (デフォルト)の場合は、展開が許可されます。注意:
ネストされたプロパティは使用できません。次に例を示します。"${user.${foo}}"この例では、"
foo
"プロパティが"home
"に設定されている場合であっても、エラーになります。これは、プロパティ構文解析プログラムはネストされたプロパティを認識しないためです。プロパティ構文解析プログラムは、最初の${
を見つけると、次に最初の}
を探し、その結果(この場合は${user.$foo}
)をプロパティと解釈しようとします。しかし、そのようなプロパティがない場合はエラーになります。 注意:
付与エントリ、アクセス権エントリまたはキーストア・エントリで展開できないプロパティがある場合、そのエントリは無視されます。たとえば、次のようにシステム・プロパティ"foo
"が定義されていない場合、grant codeBase "${foo}" { permission ...; permission ...; };
このgrantエントリ内のpermissionはすべて無視されます。また、次のような場合、
grant { permission Foo "${foo}"; permission Bar "barTarget"; };"
permission Foo...
"エントリだけが無視されます。また、次のように指定されている場合、 keystore "${foo}";
この場合は、keystoreエントリが無視されます。
Windowsシステムでのファイル・パス仕様には、実際の1つバックスラッシュごとに、2つのバックスラッシュを含める必要があります。
Windowsシステムでは、ファイル・パスをcodeBase URLではなく直接文字列で指定する場合は、パス中のバックスラッシュは、次のように2つ重ねて指定する必要があります。
grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };
これは、文字列はトークナイザ(java.io.StreamTokenizer
)によって処理され、トークナイザは\
をエスケープ文字列と解釈するため(たとえば、\n
は改行を表す)、バックスラッシュそのものを表すには、バックスラッシュを2つ重ねる必要があるからです。トークナイザは、上記のファイル・パス文字列の処理を終えると、二重のバックスラッシュを単一のバックスラッシュに変換し、最終的には次のようになります。
"C:\users\cathy\foo.bat"
文字列中のプロパティの展開は、トークナイザがその文字列の処理を完了したあとに行われます。たとえば、次のような文字列があるとします。
"${user.home}\\foo.bat"
トークナイザは、この文字列中の二重のバックスラッシュを単一のバックスラッシュに変換し、結果は次のようになります。
"${user.home}\foo.bat"次に、
${user.home}
プロパティが展開されて次のようになります。 "C:\users\cathy\foo.bat"ここでは、"
user.home
"の値をC:\users\cathy
としています。もちろん、プラットフォームに依存しないために、明示的にスラッシュを使うのではなく、${/}
プロパティを使って次のように指定する方が望ましいと言えます。 "${user.home}${/}foo.bat"
正規パスは、リンクやショートカットを含まないパスです。FilePermission
オブジェクトでパス名正規化を実行すると、パフォーマンスに悪影響を与える可能性があります。
JDK 9より前は、2つのFilePermission
オブジェクトが比較されるときに、パス名が正規化されました。これにより、プログラムで、ポリシー・ファイル内でFilePermission
オブジェクトに付与されている名前とは異なる名前を使用してファイルにアクセスできました(そのオブジェクトが同じファイルを指している場合)。正規化では、基にあるファイル・システムにアクセスする必要があったため、非常に低速になる場合がありました。
JDK 9では、パス名正規化はデフォルトでは無効になっています。これは、一方が絶対パスを使用し他方が相対パスを使用する場合、一方がシンボリック・リンクを使用し他方がターゲットを使用する場合、または一方がWindowsロング・ネームを使用し他方がDOS形式の8.3ネームを使用する場合は、2つのFilePermission
オブジェクトが互いに等しくないということです。これは、それらすべてがファイル・システム内の同じファイルを指している場合でも当てはまります。
したがって、ポリシー・ファイル内のFilePermission
オブジェクトにパス名が付与されている場合、プログラムでも同じパス名形式を使用してそのファイルにアクセスする必要があります。たとえば、ポリシー・ファイル内のパス名でシンボリック・リンクが使用されている場合、プログラムでもそのシンボリック・リンクを使用する必要があります。ターゲット・パス名でファイルにアクセスすると、アクセス権チェックに失敗します。
互換性レイヤー
相対パスのFilePermission
オブジェクトの付与により(逆に)アプリケーションに絶対パスでのファイルへのアクセスが許可されるように、互換性レイヤーが追加されています。これは、デフォルトのPolicyプロバイダおよび制限付きdoPrivileged
呼出しで機能します。
たとえば、相対パス名がa
のファイル上のFilePermission
オブジェクトは、絶対パス名が/pwd/a
(pwd
は現在の作業ディレクトリ)の同一ファイル上のFilePermission
オブジェクトを意味するわけではなくなりました。セキュリティ・マネージャが有効になっている場合は、a
を読み取るFilePermission
オブジェクトをコードに付与すると、そのコードで/pwd/a
も読み取ることができます。
互換性レイヤーは、シンボリック・リンクとターゲット、Windowsロング・ネームとDOS形式8.3ネーム、または同じ名前に正規化できる他の様々な名前形式の間の変換には対応していません。
パス名正規化のカスタマイズ
表1-9のシステム・プロパティは、FilePermission
パス名正規化のカスタマイズに使用できます。java.lang.Systemプロパティの指定方法を参照してください。表1-9 パス名正規化をカスタマイズするシステム・プロパティ
システム・プロパティ | デフォルト値 | 説明 |
---|---|---|
jdk.io.permissionsUseCanonicalPath |
false | このシステム・プロパティは、
|
jdk.security.filePermCompat |
false | このシステム・プロパティは、サードパーティのPolicyの実装をサポートするように互換性レイヤーを拡張するために使用できます。
|
ポリシー・ファイルは、2つのプロトコル(ポリシー・ファイル内の拡張形式self
とalias
)を使用して拡張できます。
${{protocol:protocol_data}}
${{protocol}}
デフォルトのポリシー・ファイルの実装では、次の2つのプロトコルがサポートされます。
${{self}}
プロトコルself
は、${{self}}
文字列全体を1つ以上のプリンシパル・クラスとプリンシパル名のペアに置き換えることを示します。実際に実行される置換えは、permissionを含むgrant節の内容によって決まります。
grant節にプリンシパルの情報が含まれていない場合は、permissionは無視されます。プリンシパルベースのgrant節のコンテキストでは、ターゲット名に${{self}}
を含むpermissionのみが有効です。たとえば、次のgrant節内のBarPermission
は常に無視されます。
grant codebase "www.example.com", signedby "duke" { permission BarPermission "... ${{self}} ..."; };grant句にプリンシパル情報が含まれている場合は、
${{self}}
がそのプリンシパル情報に置き換えられます。たとえば、次のgrant句のBarPermission
内の${{self}}
は、javax.security.auth.x500.X500Principal "cn=Duke"
に置き換えられます。 grant principal javax.security.auth.x500.X500Principal "cn=Duke" { permission BarPermission "... ${{self}} ..."; };grant句内にカンマで区切られたプリンシパルのリストがある場合、
${{self}}
は、そのカンマで区切られたプリンシパルのリストに置き換えられます。grant句内のプリンシパル・クラスとプリンシパル名がどちらもワイルドカードになっている場合、${{self}}
は、現在のAccessControlContext
内のSubject
に関連付けられたすべてのプリンシパルに置き換えられます。 次の例は、self
とキーストア別名の置換の両方を含むシナリオを示しています。
keystore "http://foo.example.com/blah/.keystore"; grant principal "duke" { permission BarPermission "... ${{self}} ..."; };上の例では、最初に
duke
がjavax.security.auth.x500.X500Principal "cn=Duke"
に展開されます。ただし、KeyStore
別名duke
に関連付けられたX.509証明書にサブジェクト識別名cn=Duke
があることが前提となります。次に、${{self}}
が、grant節内で展開されたその同じプリンシパル情報に置き換えられます。javax.security.auth.x500.X500Principal "cn=Duke"
${{alias:alias_name}}
プロトコルalias
は、java.security.KeyStore別名の置換を示します。KeyStoreエントリに指定されたKeyStore
が使用されます。alias_nameは、KeyStore
の別名を表します。${{alias:alias_name}}
は、javax.security.auth.x500.X500Principal "DN"
に置き換えられます。このDNは、alias_nameに属する証明書のサブジェクト識別名を表します。次に例を示します。
keystore "http://foo.example.com/blah/.keystore"; grant codebase "www.example.com" { permission BarPermission "... ${{alias:duke}} ..."; };上の例では、別名dukeに関連付けられているX.509証明書は、
KeyStore
のfoo.example.com/blah/.keystoreから取得されます。dukeの証明書がサブジェクト識別名としてo=dukeOrg, cn=duke
を指定し、${{alias:duke}}
がjavax.security.auth.x500.X500Principal "o=dukeOrg, cn=duke"
で置き換えられるものとします。 次のエラー条件に該当する場合、アクセス権エントリは無視されます。
doPrivileged API、および特権機能の使用方法を説明します。
特権ブロック内から値を返す必要がない場合は、doPrivileged
の呼出しは例1-14のようにできます。
ラムダ式を使ってdoPrivileged
を呼び出す場合は、ラムダ式をPrivilegedAction<Void>
型として明示的にキャストします。doPrivileged
メソッドには、PrivilegedExceptionAction
型のオブジェクトを取るバージョンも存在します。例外の処理を参照してください。
PrivilegedAction
は、型パラメータで指定された型の値を返すrun
という名前の単一抽象メソッドを持つ関数型インタフェースです。
この例では、run
メソッドの戻り値は無視されています。特権コードを構成する実際の要素によっては、内部クラスの処理のために若干の変更が必要になる場合があります。たとえば、特権コードが例外をスローしたりローカル変数にアクセスしたりする場合は、後で説明する変更が必要になります。
特権構造の使用には細心の注意を払って、特権コード・セクションをできるだけ小さくしてください。つまり、run
メソッドの中のコードは、特権付きで実行する必要のあるコードのみに制限し、より一般的な処理はrun
メソッドの外側で行うようにします。また、doPrivileged
の呼出しは、特権を有効にする必要があるコードの中で行うようにします。それ自体がdoPrivileged
を呼び出すようなユーティリティ・クラスは、セキュリティ・ホールとなる危険があるため、作成しないでください。前の例で示したように、直接呼び出さなくても、PrivilegedAction
クラスのためのユーティリティ・クラスを記述できます。Javaプログラミング言語のセキュア・コーディング・ガイドラインのガイドライン9-3: java.security.AccessController.doPrivileged
の安全な呼出しを参照してください。
例1-14 特権ブロックのサンプル・コード
次のコードは、次の3つの方法で特権コードを指定します。インタフェースPrivilegedAction
を実装するクラスで。
匿名クラスで。
ラムダ式で。
import java.security.*; public class NoReturnNoException { class MyAction implements PrivilegedAction<Void> { public Void run() { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } } public void somemethod() { MyAction mya = new MyAction(); // Become privileged: AccessController.doPrivileged(mya); // Anonymous class AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } }); // Lambda expression AccessController.doPrivileged((PrivilegedAction<Void>) () -> { // Privileged code goes here, for example: System.loadLibrary("awt"); return null; // nothing to return } ); } public static void main(String... args) { NoReturnNoException myApplication = new NoReturnNoException(); myApplication.somemethod(); } }
値を返すサンプル・コードを示します。
次に、値を返す必要がある場合の例を示します。
System.out.println( AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("user.name") ) );
ラムダ式または匿名の内部クラスを使う場合は、アクセスするローカル変数がすべてfinal
または事実上のfinalである必要があります。
次に例を示します。
String lib = "awt"; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { System.loadLibrary(lib); return null; // nothing to return } ); AccessController.doPrivileged(new PrivilegedAction<Void>() { public Object run() { System.loadLibrary(lib); return null; // nothing to return } });
変数lib
は、その値が変更されていないため、事実上のfinalです。たとえば、変数lib
の宣言の後に次の代入文を追加するとします。
lib = "swing";
コンパイラは、ラムダ式と匿名クラスの両方にあるSystem.loadLibrary
の呼出しを検出したときに、次のエラーを生成します。
error: local variables referenced from a lambda expression must be final or effectively final
error: local variables referenced from an inner class must be final or effectively final
詳細は、「ローカル・クラス」の「包含クラスのメンバーへのアクセス」を参照してください。
繰返し設定されるなどの理由で、既存の変数を事実上のfinalとして宣言できない場合は、doPrivileged
メソッドを呼び出す直前に新しいfinal
変数を作成し、その変数を他方の変数と等しいものとして設定します。次に例を示します。
String lib; // The lib variable gets set multiple times so you can't make it // effectively final. // Create a final String that you can use inside of the run method final String fLib = lib; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { System.loadLibrary(fLib); return null; // nothing to return } );
run
メソッド内で実行された処理によってチェック例外(メソッドのthrows
節にリストする必要がある例外)がスローされた場合は、PrivilegedAction
インタフェースではなく、PrivilegedExceptionAction
インタフェースを使用する必要があります。
例1-15 例外処理の例
チェック例外がrun
メソッドの実行中にスローされる場合は、この例で示したようにPrivilegedActionException
のラッパー例外に置いてからスローし、記述したコードを使用してキャッチします。
public void processSomefile() throws IOException { try { Path path = FileSystems.getDefault().getPath("somefile"); BufferedReader br = AccessController.doPrivileged( (PrivilegedExceptionAction<BufferedReader>) () -> Files.newBufferedReader(path) ); // ... read from file and do something } catch (PrivilegedActionException e) { // e.getException() should be an instance of IOException // as only checked exceptions will be wrapped in a // PrivilegedActionException. throw (IOException) e.getException(); } }
doPrivileged
のバリアントには3つのパラメータがあり、そのうちの1つは特権のサブセットを指定するために使用します。
JDK 8では、他のアクセス権をチェックするためのスタックの完全なトラバースを禁止せずにコード内でコードの特権のサブセットを表明できる、doPrivileged
のバリアントを使用できます。このdoPrivileged
のバリアントには3つのパラメータがあり、そのうちの1つはこの特権のサブセットを指定するために使用します。たとえば、次のコード例はシステム・プロパティを取得するための特権を表明しています。
// Returns the value of the specified property. All code // is allowed to read the app.version and app.vendor // properties. public String getProperty(final String prop) { return AccessController.doPrivileged( (PrivilegedAction<String>) () -> System.getProperty(prop), null, new java.util.PropertyPermission("app.version", "read"), new java.util.PropertyPermission("app.vendor", "read") ); }
このバージョンのdoPrivileged
の1つ目のパラメータは、java.security.PrivilegedAction
型です。この例では、1つ目のパラメータは関数型インタフェースPrivilegedAction
を実装するラムダ式です。このインタフェースのrun
メソッドは、パラメータprop
で指定されたシステム・プロパティの値を返します。
このバージョンのdoPrivileged
の2つ目のパラメータは、AccessControlContext
型です。場合によっては、異なるコンテキスト(ワーカー・スレッドなど)で追加のセキュリティ・チェックを実行する必要があります。AccessControlContext.getContext
メソッドを使用して、特定の呼出しコンテキストからAccessControlContext
インスタンスを取得できます。このパラメータに(この例のように)null
を指定すると、doPrivileged
の呼出し時に追加のセキュリティ・チェックが実行されません。
このバージョンのdoPrivileged
の3つ目のパラメータは、可変引数パラメータである
型です。つまり、1つ以上のPermission
...Permission
パラメータを指定するか、またはPermission[]
のようにしてPermission
オブジェクトの配列を指定できます。この例では、doPrivileged
を呼び出すことでapp.version
プロパティとapp.vendor
プロパティを取得できます。
このdoPrivileged
の3つのパラメータ・バリアントは、最小特権のモードまたは追加特権のモードで使用できます。
doPrivileged
メソッドの典型的な使用例は、現在のメソッドの呼出し側に必要なすべてのアクセス権がなくても、これを呼び出すことで、そのメソッドでアクセス権のチェックを必要とする1つ以上のアクションを実行できるようにする場合です。
たとえば、現在のメソッドが内部実装に固有の目的でファイルを開いたり、ネットワーク要求を実行したりする必要がある場合があります。
JDK 8より前のバージョンでは、doPrivileged
メソッドの呼出しには2つのパラメータしかありませんでした。これらは、呼出し側のメソッドに一時的な特権を付与し、アクセスをチェックするための通常の完全なスタックのトラバーサルを、必要なアクセス権がないクラスで定義されたメソッドに到達する可能性がある呼出しスタックまで継続せずに、そのクラスに到達したときに停止することで機能しました。通常、doPrivileged
を呼び出しているクラスは、そのコード・パスでは不要な追加のアクセス権を持っている可能性があり、それらは一部の呼出し側クラスにもない可能性があります。
通常、これらの追加権限は実行時に使用されません。doPrivileged
を使ってこれらを昇格させないことで、意図しないアクションを実行する可能性がある不正なコードの利用を防ぐことができます。これは特に、PrivilegedAction
が通常より複雑な場合や、時間の経過とともに独立して発展する可能性があるクラスやパッケージの境界の外側にあるコードを呼び出す場合に当てはまります。
3つのパラメータを持つdoPrivileged
のバリアントは、必要とされる予定がないアクセス権を不必要に昇格しないため、一般により安全に使用できます。ただし、実行時の効率が低いため、単純なコード・パスやパフォーマンス重視のコード・パスでは使用されない場合があります。
現在のメソッドをコーディングするときには、アクションを実行するために呼出し側のメソッドのアクセス権を一時的に拡張できます。
たとえば、フレームワークのI/O APIに、特定のデータ形式のファイルを開くための汎用メソッドが含まれる場合があります。このAPIは、通常のファイル・パス・パラメータを取り、それを使って基盤となるFileInputStream
を開くときに、呼出し側のコードのアクセス権を使用します。ただし、これによってすべての呼出し側が標準のデモ用サンプルを含む特別なディレクトリ内のデータ・ファイルを開くこともできるようになる可能性があります。
このAPIの呼出し側には、読取りアクセス用のFilePermission
を直接付与できます。ただし、呼出し側のコードのセキュリティ・ポリシーの更新が不便または不可能になる可能性があります。たとえば、呼出し側のコードがサンドボックス内で実行されるアプレットである可能性があります。
これを実装する1つの方法は、コード内で受け取ったパスをチェックし、それが特別なディレクトリ内のファイルを参照しているかどうかを判定することです。参照している場合は、doPrivileged
を呼び出してすべてのアクセス権を有効にしてから、PrivilegedAction
の内部でファイルを開きます。ファイルが特別なディレクトリに含まれていない場合は、コード内でdoPrivileged
を使用せずにファイルを開きます。
この手法では、実装は要求されたファイル・パスを慎重に扱い、それが特別な共有ディレクトリを参照しているかどうかを判定する必要があります。doPrivileged
を呼び出す前にファイル・パスを正規化して、パスが特別なディレクトリ内のファイルを参照しているかどうかを判定する前に、すべての相対パスが処理されるように(およびuser.dir
システム・プロパティを読み取るためのアクセス権がチェックされるように)する必要があります。また、特別なディレクトリの外側に抜ける意図を持つ悪質な"../"パス要素を防止する必要もあります。
より簡単かつ適切な実装では、3つ目のパラメータを持つdoPrivileged
のバリアントを使用します。特別なディレクトリへの読取りアクセスを含むFilePermission
を3つ目のパラメータとして渡します。その後、PrivilegedAction
の内部でファイルの操作を行います。この実装はより簡単で、セキュリティ上の欠陥を含む可能性がかなり低くなります。
コードを特権付きとしてマークすると、信頼できるコードは、それを呼び出しているコードが直接利用できるものより多くのリソースに、一時的にアクセスできるようになります。
JDKのインストール・ポリシーにより、特定のコード・ソースに基づくコードに対して許可されるアクセス権、つまりシステム・リソースに対するアクセスの種類が決まります。CodeSource
型のコード・ソースは、基本的に、コードの場所(URL)と、コードへの署名に使われている非公開鍵に対応する公開鍵を含む証明書の参照(コードが署名されている場合)で、構成されています。
ポリシーは、Policy
オブジェクトによって表されます。具体的には、Policy
クラス(java.security
パッケージ内)内のabstractメソッドの実装を提供するPolicy
サブクラスによって表されます。
Policy
オブジェクトが使用するポリシー情報がどこに置かれるかは、Policy
の実装によります。Policy
のリファレンス実装では、ポリシー情報をポリシー構成ファイルから得ます。デフォルトのPolicy
のリファレンス実装とそこで読み取られるポリシー・ファイルで使用する構文については、「Policyのデフォルト実装とポリシー・ファイルの構文」を参照してください。ポリシー・ツールを使用した(必須の構文を知る必要のない)ポリシー・ファイルの作成方法の詳細は、ポリシー・ツールを参照してください。
そのとき有効になっているセキュリティ・ポリシーでの決定に従って、CodeSource
インスタンスと、そのCodeSource
に基づくコードに対して付与されているアクセス権は、保護ドメインに包含されます。したがって、同じ鍵で署名された同じURLにあるクラスは一般に同じドメインに置かれ、クラスは1つの保護ドメインのみに所属します。(ただし、同じ鍵で署名され、同じURLにあっても、別のクラス・ローダー・インスタンスでロードされたクラスは、一般に別のドメインに置かれます。)同じアクセス権を与えられていても、別のコード・ソースが基になっているクラスは、別のドメインに属します。
現在、JDKとともに提供されるすべてのクラスには、ロード時にすべてのアクセス権が与えられます(これは将来のリリースで変更される可能性があります)。これらのクラスのほとんどは、固有のシステム・ドメインに置かれます。さらに、拡張クラス・ローダーは<java_home>/jre/lib/ext
ディレクトリに含まれているJARファイルのコードを別々のドメインにロードしますが(これらのJARファイル内のコードには固有のURLがあるため)、これらのドメインはJDKとともに提供されるクラスのために予約された固有のシステム・ドメインとは独立しています。
アプレットまたはアプリケーションは、それぞれのコード・ソースによって決められるドメイン内で動作します。アプレット(またはセキュリティ・マネージャの下で動作しているアプリケーション)がセキュリティ保護された操作(ファイルの読み書きなど)を行うためには、その操作を行うためのアクセス権がアプレットまたはアプリケーションに与えられている必要があります。
より具体的には、リソースにアクセスしようとする場合は常に、その地点に至るまでに実行スレッドがたどってきたすべてのコードが、そのリソース・アクセスのためのアクセス権を持っている必要があります。ただし、スレッドの中に特権付きのマークが付けられたコードがある場合は除きます。つまり、複数の呼出し側のチェーンが存在する実行のスレッドで、アクセス制御のチェックが行われる場合を考えます。(保護ドメインの境界を横断する可能性のある複数のメソッドの呼出しのような場合です。)最後の呼出し側がAccessController
のcheckPermission
メソッドを呼び出すとき、要求されたアクセスの許可または拒否を決定する基本的なアルゴリズムは、次のようになります。呼出しチェーンのいずれかの呼出し側のコードに、要求されたアクセス権がない場合、AccessControlException
がスローされます。ただし、このアクセス権を与えられているコードの呼出し側に特権付きのマークが付けられていて、この呼出し側からその後(直接または間接的に)呼び出されるすべての部分がこのアクセス権を持っている場合、この例外はスローされません。
注意:
AccessController.checkPermission
メソッドは、通常、check
という語で始まる特定のSecurityManager
メソッド(checkConnect
など)の呼出しによって、またはSecurityManager.checkPermission
メソッドによって間接的に呼び出されます。通常、これらのチェックはSecurityManager
がインストールされている場合にのみ行われます。AccessController.checkPermission
メソッドによってチェックされるコードは、最初にSystem.getSecurityManager
メソッドがnullを返すかどうかをチェックします。コードを特権付きとしてマークすると、信頼できるコードは、それを呼び出しているコードが直接利用できるものより多くのリソースに、一時的にアクセスできるようになります。これは、次のような場合に必要になります。たとえば、あるアプリケーションがフォントが入ったファイルへの直接アクセスを許可されていないときに、ドキュメントを表示するシステム・ユーティリティがユーザーに代わってそのフォントを取得する必要がある場合などです。このシステム・ユーティリティは、フォントを取得するために特権付きになる必要があります。
doPrivileged
メソッドは、java.lang.reflect.Method.invoke
を使用して反射的に呼び出すことができます。
doPrivileged
メソッドは、java.lang.reflect.Method.invoke
メソッドを使ってリフレクションとして呼び出すことができます。この場合、特権モードで与えられる特権は、Method.invoke
の特権ではなく、それによって呼び出されるリフレクションでないコードの特権です。このようにしないと、システム特権が誤って(または悪意を持って)ユーザー・コードに与えられてしまう危険があります。既存のAPIでリフレクションを使う場合にも、同様の要件が適用されます。