プライマリ・コンテンツに移動
Java Platform, Standard Editionセキュリティ開発者ガイド
リリース9
E91919-01
目次へ移動
目次

前
次
次へ

Java Development Kit (JDK)でのアクセス権

組込みのJDKアクセス権タイプについてと、各アクセス権の付与の関連リスクについて情報を示します。正常実行のためにアクセス権を有効にする必要があるメソッドについての情報、およびメソッドごとの必要なアクセス権のリストです。

アクセス権は、システム・リソースへのアクセスを表します。アプレット(またはセキュリティ・マネージャとともに実行するアプリケーション)が、リソースへのアクセスを許可されるためには、アクセスを試みるコードに対し、該当するアクセス権を明示的に与える必要があります。

一般に、アクセス権には名前(「ターゲット名」とも呼ばれる)があり、場合によっては、カンマで区切られた1つ以上のアクションのリストを持つこともあります。

たとえば、次のコードでは、/tmpディレクトリのabcという名前のファイルへの読取りアクセスを表すFilePermissionオブジェクトを作成します。

perm = new java.io.FilePermission("/tmp/abc", "read");

ここでは、ターゲット名が/tmp/abcで、アクション文字列がreadになります。

重要:

前述の文によって、アクセス権オブジェクトが作成されます。アクセス権オブジェクトは、システム・リソースを表しますが、システム・リソースへのアクセスを許可することはありません。アクセス権オブジェクトは、実効性のあるポリシーに基づいて作成され、コードへ割り当てられ(「付与」され)ます。アクセス権オブジェクトが、あるコードに割り当てられると、そのコードはアクセス権オブジェクトで指定されたシステム・リソースへ、指定された方法でアクセスするアクセス権が付与されます。現在のセキュリティ・マネージャが、アクセス判断を行う際に、アクセス権オブジェクトを作成することもあります。この場合、ターゲットのアクセス権オブジェクトは、要求されたアクセスに基づいて作成されます。さらに、ターゲットのアクセス権オブジェクトは、要求を行うコードに付与され、かつ要求を行うコードが保持する、アクセス権オブジェクトに照らしてチェックされます。
Javaアプリケーション環境のポリシーは、Policyオブジェクトにより表現されます。"JavaPolicy" Policy実装では、1つまたは複数のポリシー構成ファイルからポリシーを指定できます。ポリシー・ファイルは、指定したコード・ソースのコードにどのアクセス権を許可するかを指定します。たとえば、/home/sysadminディレクトリのコードに対して/tmp/abcファイルへの読取りアクセスを許可する場合、ポリシー・ファイルのエントリは次のようになります。
grant codeBase "file:/home/sysadmin/" {
    permission java.io.FilePermission "/tmp/abc", "read";
};
ポリシー・ファイルの場所、およびポリシー・ファイルにより付与するアクセス権の詳細は、デフォルトのPolicyの実装とポリシー・ファイルの構文を参照してください。
ポリシー・ツールを使用すると、入力や、ポリシー・ファイルの構文規則を記憶する手間を減らすことができます。ポリシー・ツールの使用によるアクセス権の指定の詳細は、ポリシー・ツールを参照してください。ポリシー・ツールを使用すると、入力や、ポリシー・ファイルの構文規則を記憶する手間を減らすことができます。
技術的な観点から言うと、リソースへのアクセスを試みる場合は、実行スレッド上のコードに「特権設定」のマークが付けられていないかぎり、実行スレッドが利用するコードはすべて、そのリソースへのアクセス権を保持する必要があります。特権ブロックのためのAPIを参照してください。

アクセス権の説明とリスク

組込みのJDKアクセス権タイプ、および各アクセス権の付与のリスクのリストを示します。

NIO関連のターゲット

NIO関連のターゲット名です。

JavaSE JDKのリリース1.4では、次の2つのNIOに関するRuntimePermissionターゲットが追加されました。
selectorProvider
charsetProvider
これらのRuntimePermissionは、java.nio.channel.spi.SelectorProviderまたはjava.nio.charset.spi.CharsetProviderをサブクラス化して実装するクラスに付与する必要があります。アクセス権は、抽象基底クラス・コンストラクタの呼出し時にチェックされます。これらのアクセス権は、重要なプロバイダ・メカニズムを実装するクラスの信頼性を保証します。詳細は、java.nio.channels.spi.SelectorProviderjava.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.RuntimePermission "stopThread"も必要。

java.lang.Thread
  public final synchronized void
                    stop(Throwable obj)
checkAccess(this)。現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスでない場合は、checkPermissionも呼び出される。 java.lang.RuntimePermission "modifyThread"。

現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスではない場合は、java.lang.RuntimePermission "stopThread"も必要。

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メソッドのアクセス権チェック

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";

デフォルトのPolicyの実装とポリシー・ファイルの構文

Javaプログラミング言語のアプリケーション環境のポリシーは、様々なソースを出所とするコードがどのようなアクセス権を使用できるかを指定し、様々なプリンシパルとして実行するもので、Policyオブジェクトによって表されます。具体的には、Policyクラス(java.securityパッケージ内)内のabstractメソッドの実装を提供するPolicyサブクラスによって表されます。

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.1policy.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です。

Policyの実装の変更

セキュリティ・プロパティ・ファイル(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
キーストアのURLの場所を指定します。
some_password_url
キーストア・パスワードのURLの場所を指定します。
keystore_type
キーストアのタイプを指定します。
keystore_provider
キーストア・プロバイダを指定します。

注意:

  • 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型のオブジェクトによって表される)またはプリンシパルのグループとして実行されると考えられます。

付与エントリには、オプションのcodeBasesignedBy、およびプリンシパルの名前と値のペアのあとに、アクセス権を付与するコードを指定する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、Principal、およびCodeBaseフィールド

signedBycodeBase、およびprincipalの値はオプションです。また、これらのフィールドの順序は問われません。

signedByの値は、キーストアに格納された証明書の別名を示します。証明書内の公開鍵は、コードのデジタル署名の検証に使われます。別名によって指定されたキーストア・エントリ内の公開鍵に対応する、非公開鍵で署名されたコードに、アクセス権を付与します。

signedByの値には、複数の別名をカンマで区切って指定できます。たとえば、"Adam,Eve,Charles"のように指定できます。この場合は、各要素がORではなくANDで結ばれ、「Adam、EveおよびCharlesによって署名された」という意味になります。より厳密には、「Adamによって署名されたコード」とは、「Adamという別名が付けられたエントリを持つキーストアにある公開鍵証明書に対応する、非公開鍵を使って署名されたJARファイルに含まれている、クラス・ファイル内のコード」という意味です。

signedByフィールドはオプションです。省略した場合は、「任意の署名者」という意味になります。コードに署名が付いているかどうか、だれが署名しているかは問われなくなります。

プリンシパルの値はclass_nameprincipal_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/* いいえ

アクセス権エントリ

アクセス権エントリは、順序どおり(permissionpermission_class_name、"target_name"、"action"およびsignedBy "signer_names)に指定されます。

アクセス権エントリは、単語permissionで始まります。前述のテンプレートにある単語permission_class_nameは、実際にはjava.io.FilePermissionjava.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がシステム・クラスであるときです(システム・クラスはポリシーによる制限を受けないため)。

アクセス権エントリの各項目は、指定された順序(permissionpermission_class_name、"target_name"、"action"、およびsignedBy "signer_names")で並んでいる必要があります。各エントリはセミコロンで終わります。

識別子(permissionsignedBycodeBaseなど)では大文字と小文字は区別されませんが、permission_class_nameと、値として引き渡される文字列については大文字と小文字が区別されます。

Windowsシステムでのファイル・パスの指定

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 ポリシー構成ファイルの例

次のコードは、次の条件を満たすコードのみがSecurityクラス内のメソッドを呼び出して、プロバイダの追加または削除を行ったり、Securityプロパティを設定したりできることを示しています。
  • ローカル・ファイル・システムの"/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.homeC:\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システム、ファイル・パス、およびプロパティの展開

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

このシステム・プロパティは、FilePermissionオブジェクトでのパス名正規化を有効または無効にするために使用できます。

  • FilePermissionパス名正規化を無効にするには、jdk.io.permissionsUseCanonicalPath=falseと設定します。

  • FilePermissionパス名正規化を有効にするには、jdk.io.permissionsUseCanonicalPath=trueと設定します。

jdk.security.filePermCompat false

このシステム・プロパティは、サードパーティのPolicyの実装をサポートするように互換性レイヤーを拡張するために使用できます。

  • このシステム・プロパティを無効にするには、jdk.security.filePermCompat=falseと設定します。

    相対パスのFilePermissionで、アプリケーションが、デフォルトPolicyプロバイダおよび制限付きdoPrivilegedメソッドの絶対パスを使用してファイルにアクセスできるようになります。

  • サードパーティのPolicyの実装をサポートするように互換性レイヤーを拡張するには、jdk.security.filePermCompat=trueと設定します。

    相対パスのFilePermissionで、アプリケーションが、デフォルトPolicyプロバイダ、制限付きdoPrivilegedメソッド、およびサードパーティのPolicyの実装の絶対パスを使用してファイルにアクセスできるようになります。

ポリシー・ファイルにおける一般的な展開

ポリシー・ファイルは、2つのプロトコル(ポリシー・ファイル内の拡張形式selfalias)を使用して拡張できます。

アクセス権名に次の形式の文字列が含まれているとします。
${{protocol:protocol_data}}
このような文字列がアクセス権名に含まれる場合、protocolの値で、実行される展開のタイプが決まり、protocol_dataは空にすることもできます。空の場合は、前述の文字列は次のような単純な形式になります。
${{protocol}}

デフォルトのポリシー・ファイルの実装では、次の2つのプロトコルがサポートされます。

  1. ${{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}} ...";
    };
    
    上の例では、最初にdukejavax.security.auth.x500.X500Principal "cn=Duke"に展開されます。ただし、KeyStore別名dukeに関連付けられたX.509証明書にサブジェクト識別名cn=Dukeがあることが前提となります。次に、${{self}}が、grant節内で展開されたその同じプリンシパル情報に置き換えられます。javax.security.auth.x500.X500Principal "cn=Duke"
  2. ${{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証明書は、KeyStorefoo.example.com/blah/.keystoreから取得されます。dukeの証明書がサブジェクト識別名としてo=dukeOrg, cn=dukeを指定し、${{alias:duke}}javax.security.auth.x500.X500Principal "o=dukeOrg, cn=duke"で置き換えられるものとします。

    次のエラー条件に該当する場合、アクセス権エントリは無視されます。

    • keystoreエントリが指定されていない
    • alias_nameが指定されていない
    • alias_nameの証明書を取得できない
    • 取得される証明書がX.509証明書ではない

特権ブロックのためのAPI

特権コードの意味とその使用目的について説明した後、APIの使用方法を示します。内容は次のとおりです。

doPrivileged APIの使用

特権コードを使う意味

リフレクション

doPrivileged APIの使用

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つ目のパラメータは、可変引数パラメータであるPermission...型です。つまり、1つ以上の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とともに提供されるクラスのために予約された固有のシステム・ドメインとは独立しています。

アプレットまたはアプリケーションは、それぞれのコード・ソースによって決められるドメイン内で動作します。アプレット(またはセキュリティ・マネージャの下で動作しているアプリケーション)がセキュリティ保護された操作(ファイルの読み書きなど)を行うためには、その操作を行うためのアクセス権がアプレットまたはアプリケーションに与えられている必要があります。

より具体的には、リソースにアクセスしようとする場合は常に、その地点に至るまでに実行スレッドがたどってきたすべてのコードが、そのリソース・アクセスのためのアクセス権を持っている必要があります。ただし、スレッドの中に特権付きのマークが付けられたコードがある場合は除きます。つまり、複数の呼出し側のチェーンが存在する実行のスレッドで、アクセス制御のチェックが行われる場合を考えます。(保護ドメインの境界を横断する可能性のある複数のメソッドの呼出しのような場合です。)最後の呼出し側がAccessControllercheckPermissionメソッドを呼び出すとき、要求されたアクセスの許可または拒否を決定する基本的なアルゴリズムは、次のようになります。呼出しチェーンのいずれかの呼出し側のコードに、要求されたアクセス権がない場合、AccessControlExceptionがスローされます。ただし、このアクセス権を与えられているコードの呼出し側に特権付きのマークが付けられていて、この呼出し側からその後(直接または間接的に)呼び出されるすべての部分がこのアクセス権を持っている場合、この例外はスローされません。

注意:

AccessController.checkPermissionメソッドは、通常、checkという語で始まる特定のSecurityManagerメソッド(checkConnectなど)の呼出しによって、またはSecurityManager.checkPermissionメソッドによって間接的に呼び出されます。通常、これらのチェックはSecurityManagerがインストールされている場合にのみ行われます。AccessController.checkPermissionメソッドによってチェックされるコードは、最初にSystem.getSecurityManagerメソッドがnullを返すかどうかをチェックします。

コードを特権付きとしてマークすると、信頼できるコードは、それを呼び出しているコードが直接利用できるものより多くのリソースに、一時的にアクセスできるようになります。これは、次のような場合に必要になります。たとえば、あるアプリケーションがフォントが入ったファイルへの直接アクセスを許可されていないときに、ドキュメントを表示するシステム・ユーティリティがユーザーに代わってそのフォントを取得する必要がある場合などです。このシステム・ユーティリティは、フォントを取得するために特権付きになる必要があります。

リフレクション

doPrivilegedメソッドは、java.lang.reflect.Method.invokeを使用して反射的に呼び出すことができます。

このAPIとリフレクションの相互作用は、注意の必要な微妙な点です。doPrivilegedメソッドは、java.lang.reflect.Method.invokeメソッドを使ってリフレクションとして呼び出すことができます。この場合、特権モードで与えられる特権は、Method.invokeの特権ではなく、それによって呼び出されるリフレクションでないコードの特権です。このようにしないと、システム特権が誤って(または悪意を持って)ユーザー・コードに与えられてしまう危険があります。既存のAPIでリフレクションを使う場合にも、同様の要件が適用されます。