次のスニペットについて考えてみます。
(この場合、OpenJDK 6b24-1.11.5-0ubuntu1〜12.10.1は、OracleとOpenJDKの両方のすべてのJVM 6および7が同じ動作をするため、無関係に見えます)
SocketPermission toCheck = new SocketPermission("www.google.ca", "resolve");
SocketPermission checker = new SocketPermission("*.ca:80", "connect");
System.out.println("Result: " + checker.implies(toCheck));
checker = new SocketPermission("*.1e100.net:80", "connect");
System.out.println("Result: " + checker.implies(toCheck));
私が得る結果は次のとおりです。
Result: false
Result: true
問題は、JVMが逆引き参照を実行して、アドレスが解決されたドメインと実際に一致することを確認することであると思われます。
www.google.caドメインを掘り下げると、次のことがわかります。
[rotty@rotty-desktop ~]$ dig www.google.ca ANY
; <<>> DiG 9.8.1-P1 <<>> www.google.ca ANY
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48015
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.google.ca. IN ANY
;; ANSWER SECTION:
www.google.ca. 114 IN A 74.125.226.55
www.google.ca. 114 IN A 74.125.226.56
www.google.ca. 114 IN A 74.125.226.63
www.google.ca. 74 IN AAAA 2607:f8b0:400b:801::1018
;; Query time: 27 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Mon Jan 14 17:18:50 2013
;; MSG SIZE rcvd: 107
さらに、結果の最初のアドレスを取得してDNSルックアップを実行すると、次のようになります。
[rotty@rotty-desktop ~]$ nslookup 74.125.226.55
Server: 127.0.1.1
Address: 127.0.1.1#53
Non-authoritative answer:
55.226.125.74.in-addr.arpa name = yyz06s06-in-f23.1e100.net.
Authoritative answers can be found from:
これは問題を明確に示しているようです。権限のない逆引き参照は、ドメインに対して定義された最初の(この場合はローカリティによる)エイリアスを返します。
これは、指定されたドメイン名の基になるアドレスに解決される可能性のある潜在的なエイリアスを知り、宣言する必要があることを意味します。
なぜJVMはそのような一致を必要とするのでしょうか?「解決」プロセスが満たされるには、アドレスが実際に存在するという単純な検証で十分ではないでしょうか。アドレスには、可能な逆マッピングがいくつもある可能性があります。これは実際にどのように機能するでしょうか?
[更新]これが実際にデフォルトのJavaポリシー定義と同じように動作することを明確にするために、次の追加の例を検討してください。
Socket socket = new Socket("www.google.ca", 80);
socket.close();
上記に次のセキュリティポリシーを適用します。
grant {
permission java.net.SocketPermission "*.ca:80", "connect";
//permission java.net.SocketPermission "*.1e100.net:80", "connect";
};
プログラムを次のように実行します。
java -Djava.security.manager -Djava.security.policy=../security.policy Test
結果:
Exception in thread "main" java.security.AccessControlException: access denied ("java.net.SocketPermission" "www.google.ca" "resolve")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
at java.security.AccessController.checkPermission(AccessController.java:560)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1048)
at java.net.InetAddress.getAllByName0(InetAddress.java:1203)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at java.net.InetAddress.getAllByName(InetAddress.java:1063)
at java.net.InetAddress.getByName(InetAddress.java:1013)
at java.net.InetSocketAddress.<init>(InetSocketAddress.java:142)
at java.net.Socket.<init>(Socket.java:208)
at example.security.SocketSecurityExample.test(SocketSecurityExample.java:13)
at example.security.SocketSecurityExample.main(SocketSecurityExample.java:9)
ポリシーファイルを次のように変更します。
grant {
//permission java.net.SocketPermission "*.ca:80", "connect";
permission java.net.SocketPermission "*.1e100.net:80", "connect";
};
コードが適切に実行されます。