考虑以下代码段:
(在这种情况下,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";
};
导致正确执行代码。