我无法为https连接正确设置user-agent
属性。根据我收集的内容,可以通过-Dhttp.agent
VM选项或URLConnection.setRequestProperty()
设置http-header属性。但是,通过VM选项设置user-agent会导致“Java / [version]”附加到http.agent的值。同时setRequestProperty()
仅适用于http连接,而不适用于https(至少在我尝试时)。
java.net.URL url = new java.net.URL( "https://www.google.com" );
java.net.URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0");
conn.connect();
java.io.BufferedReader serverResponse = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()));
System.out.println(serverResponse.readLine());
serverResponse.close();
我通过使用WireShark检查http通信找到/验证了问题。有没有办法解决这个问题?
更新:添加信息
似乎我对通信看起来并不够深入。代码从代理后面运行,因此观察到的通信是针对代理的,通过-Dhttps.proxyHost
设置,而不是目标网站(google.com)。无论如何,在https连接期间,方法为CONNECT
,而不是GET
。这是https通信尝试的wireshark捕获。就像我上面提到的那样,用户代理通过-Dhttp.agent
设置,因为URLConnection.setRequestProperty()
没有效果(user-agent = Java / 1.7.0)。在这种情况下,请注意附加的 Java / 1.7.0 。问题仍然存在,为什么会发生这种情况,我该如何解决这个问题?
CONNECT www.google.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0 Java/1.7.0
Host: www.google.com
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Proxy-Connection: keep-alive
HTTP/1.1 403 Forbidden
X-Bst-Request-Id: MWPwwh:m7d:39175
X-Bst-Info: ch=req,t=1366218861,h=14g,p=4037_7213:1_156,f=PEFilter,r=PEBlockCatchAllRule,c=1905,v=7.8.14771.200 1363881886
Content-Type: text/html; charset=utf-8
Pragma: No-cache
Content-Language: en
Cache-Control: No-cache
Content-Length: 2491
顺便说一下,该请求是被禁止的,因为代理过滤了用户代理, Java / 1.7.0 导致了拒绝。我已将 Java / 1.7.0 附加到http连接的用户代理,代理也拒绝连接。我希望我不会发疯:)。
答案 0 :(得分:12)
我通过使用WireShark检查http通信找到/验证了问题。有什么方法围绕这个
这是不可能的。通过加密协议的偶然观察,SSL套接字上的通信完全变得模糊。使用数据包捕获软件,您将能够查看SSL连接的启动和加密数据包的交换,但这些数据包的内容只能在连接的另一端(服务器)中提取。如果不是这种情况那么整个HTTPS协议就会损坏,因为它的全部意义在于保护来自中间人类型攻击的HTTP通信(在这种情况下) MITM是数据包嗅探器。
.n .... E ... ........... / .. 5..3..9..2..8 .. .............. @ ........................ QL。{。B .... OSR ..!4。$:T ...,..牛逼.... Q ... M..Ql。{... ... LM..L ..... um.M ......秒。 ... N ... P 1 0} .. I..G4.HK.n ...... 8Y ...............è...一个... > ... 0 ... 0 ......... ).S ....... 0 ..*。H.. ..... 0F1.0 ...ü.... US1.0 ...ü。 。 谷歌Inc1“0 ..U .... Google Internet Authority0 .. 130327132822Z。 131231155850Z0h1.0 ...ü.... US1.0。。U. California1.0。。U. Mountain View1.0 ... U. 。 Google Inc1.0 ... U .... www.google.com0..0
从理论上讲,了解您的User-Agent
标题是否实际被排除的唯一方法是您是否可以访问Google服务器,但实际上,HTTPS规范或Java的实现都没有任何内容排除通常通过HTTP发送的标头。
GET / HTTP / 1.1
User-Agent:Mozilla / 5.0(Windows NT 5.1; rv:19.0)Gecko / 20100101 Firefox / 19.0
主持人:www.google.com
接受:text / html,image / gif,image / jpeg,*; q = .2, / ; Q = 0.2
连接:保持活力
两个示例捕获都是使用 完全 相同的代码生成的:
URL url = new URL(target);
URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0");
conn.connect();
BufferedReader serverResponse = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
System.out.println(serverResponse.readLine());
serverResponse.close();
除了HTTPS,目标是“https://www.google.com”,而对于HTTP,它是“http://www.google.com”。
根据您更新的问题,使用-Dhttp.agent
属性 确实 将'Java / version'附加到用户代理标头,如{ {3}}:
http.agent (默认:“Java /< version>”)
定义http请求中User-Agent请求标头中发送的字符串。请注意,字符串“Java /< version>”将附加到属性中提供的字符串(例如,如果使用-Dhttp.agent =“foobar”,则User-Agent标头将包含“foobar Java / 1.5.0” “如果VM的版本是1.5.0)。此属性仅在启动时检查一次。
'违规'代码位于sun.net.www.protocol.http.HttpURLConnection
的静态块初始值设定项中:
static {
// ...
String agent = java.security.AccessController
.doPrivileged(new sun.security.action.GetPropertyAction(
"http.agent"));
if (agent == null) {
agent = "Java/" + version;
} else {
agent = agent + " Java/" + version;
}
userAgent = agent;
// ...
}
围绕这个'问题'的一个淫秽方法是这段代码,我1000%建议你 不 使用:
protected void forceAgentHeader(final String header) throws Exception {
final Class<?> clazz = Class
.forName("sun.net.www.protocol.http.HttpURLConnection");
final Field field = clazz.getField("userAgent");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, header);
}
将此覆盖与https.proxyHost
,https.proxyPort
和http.agent
设置一起使用会得到所需的结果:
连接www.google.com:443 HTTP / 1.1
User-Agent:Mozilla / 5.0(Windows NT 5.1; rv:19.0)Gecko / 20100101 Firefox / 19.0
主持人:www.google.com
接受:text / html,image / gif,image / jpeg,*; q = .2, / ; Q = 0.2
代理连接:保持活着
但是,不要这样做。使用following documentation:
更安全final DefaultHttpClient client = new DefaultHttpClient();
HttpHost proxy = new HttpHost("127.0.0.1", 8888, "http");
HttpHost target = new HttpHost("www.google.com", 443, "https");
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
HttpProtocolParams
.setUserAgent(client.getParams(),
"Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0");
final HttpGet get = new HttpGet("/");
HttpResponse response = client.execute(target, get);
答案 1 :(得分:0)
我通过使用WireShark检查http通信找到/验证了问题。有没有办法解决这个问题?
这里没有问题。无论请求是通过HTTP / HTTPS传输,都设置User-Agent标头。甚至将它设置为像blah blah
这样不合理的东西也适用于HTTPS。当使用的基础协议为 HTTPS 时,会捕获下面显示的标题。
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
User-Agent: blah blah
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
这是触发请求的代码。
// localhost:52999 is a reverse proxy to xxx:443
java.net.URL url = new java.net.URL( "https://localhost:52999/" );
java.net.URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101 Firefox/19.0");
conn.connect();
java.io.BufferedReader serverResponse = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()));
System.out.println(serverResponse.readLine());
serverResponse.close();
通常,无法嗅探HTTPS请求(如提到的@Perception)。通过使用自己的假CA替换根CA的代理来管理请求将允许您查看流量。一种更简单的方法是查看目标服务器的访问日志。但正如您从上面的HTTPS请求代码段中看到的那样,发送的User-Agent
标头是正确的。