2012年11月28日水曜日

アクセス権のない場所にあるリソース

java.class.pathに設定した場所からは、たとえFilePermissionがなかったとしてもClassLoaderのfindClass()を使ってクラスをロードすることができる。それではgetResource()やgetResourceAsStream()で直接データを取得することはできるのだろうか?と疑問に思って、SunのJDK (JDK1.6)で実験してみた。
実験内容と結果
import java.io.*;
import java.net.*;

public class ResourceTest
{
public static void main(String[] args)throws Exception
{
ClassLoader cl = ResourceTest.class.getClassLoader();
URL url = cl.getResource(args[0]);
System.out.println("URL=" + url);
InputStream ins = cl.getResourceAsStream(args[0]);
ins.close();
}
}
このプログラムは、引数に指定した名前を持つリソースのURLを表示後、InputStreamを取得している。
たとえば、以下のように引数を指定して起動すると、java/lang/Objec.classを読み取ることができる。
java ResourceTest java/lang/Object.class
実行結果
URL=jar:file:/C:/Program%20Files/Java/jre6/lib/rt.jar!/java/lang/Object.class
rt.jarに対するURLを取得できている。
しかし、以下のようにSecurityManagerを設定した場合には、
java -Djava.security.manager ResourceTest java/lang/Object.class
nullが返ってきてアクセスできない。
URL=null
Exception in thread "main" java.lang.NullPointerException
at ResourceTest.main(ResourceTest.java:12)
ClassLoaderクラスのgetResource()メソッドとgetResourceAsStream()メソッドはどちらもnullを返してくる。
結論
SecurityManagerが設定されている場合、java.class.path(およびブートストラップクラスパス)内のリソースをClassLoader.getResource()呼び出し時にアクセスチェックが行われているらしい。
アクセス権違反が検出された場合、AccessControlExceptionは発生せず、単純にnullが返ってくる。
疑問
この動作は仕様なのか?少なくともJDKのドキュメント(ClassLoader (Java Platform SE 6)、SecureClassLoader (Java Platform SE 6)、URLClassLoader (Java Platform SE 6)には記載されていない。
追記)仕様だった。以下の場所に記述がある。
http://www.j2ee.me/javase/ja/6/docs/ja/technotes/guides/lang/resources.html#security
getResource() は、情報へのアクセスを提供するため、セキュリティーの規則が適切に定義および構築されている必要があります。セキュリティー上の配慮により、あるセキュリティーコンテキストであるリソースへのアクセスが許可されていない場合は、getResource() メソッドは、あたかもそのリソースが存在しないかのように失敗する (null を返す) ようになっています。 これは、存在性攻撃に対する配慮です。

0 件のコメント:

コメントを投稿