Is there a bug in java.net.SocketPermission when d

2019-07-26 01:33发布

问题:

Consider the following snippet:

(in this case OpenJDK 6b24-1.11.5-0ubuntu1~12.10.1, which appears irrelevant since all the JVMs 6&7 both Oracle and OpenJDK have the same behavior)

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

The result I get is:

Result: false
Result: true

The issue seems to be that the JVM does a reverse lookup to verify that the address actually matches against the resolved domain.

A dig lookup of the www.google.ca domain reveals the following:

[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

Furthermore, taking the first address in the result and performing a DNS lookup produces:

[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:

This seems to clearly demonstrate the issue. A non-authoritative reverse lookup returns the first (by locality in this case) alias defined for the domain.

This means that I need to know, and declare, any potential aliases that may resolve to the underlying address of the specified domain name.

Why would the JVM require such a match? Wouldn't a simple validation that an address does in fact exist be enough for the "resolve" process to be satisfied? There may well be any number of possible reverse mappings for the address. How could this ever work in practice?

[Update] In order to clarify that this in fact behaves the same with a default java policy definition, consider the following additional example:

Socket socket = new Socket("www.google.ca", 80);

socket.close();

Applying the following security policy to the above:

grant {
    permission java.net.SocketPermission "*.ca:80", "connect";
    //permission java.net.SocketPermission "*.1e100.net:80", "connect";
};

Executing the program as:

java -Djava.security.manager -Djava.security.policy=../security.policy Test

Results in:

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)

Changing the policy file to:

grant {
    //permission java.net.SocketPermission "*.ca:80", "connect";
    permission java.net.SocketPermission "*.1e100.net:80", "connect";
};

Results in proper execution of the code.

回答1:

That action wouldn't be taken by the JVM when connecting. It constructs a SocketPermission containing the actual hostname/IP address and uses 'implies' to check whether any permission in the .policy file implies that permission.