记⼀次https访问握⼿失败(handshakefailure)
⽂章作者:luxianghao
免责声明:⽂章内容仅代表个⼈观点,如有不当,欢迎指正。
---
事情起因
某⽇,突然之前ok的访问不ok了,具体情况如下
[root@host tmp]# wget ample/
--2016-12-22 12:57:34-- ample/
52.222.238.45, 52.222.238.96, 52.222.238.218, ...
Connecting to example|52.222.238.45|: connected.
OpenSSL: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
Unable to establish SSL connection.
尝试⽤curl,浏览器访问
很意外,竟然访问成功了
那么基本可以排除不是证书的问题了,⽽且把curl的verbose/debug模式打开也看到,ssl认证是ok的,如下
还没见过这种情况,google之,
看到如下链接中有类似的情况:⽼版本的wget(before1.12)因不⽀持SNI,导致不能验证证书
那么开始⽤⾼版本的wget(1.15)测试,成功访问
100%
[============================================================================================================================================================= 22 --.-K/s in 0s
2016-12-31 15:54:42 (5.58 MB/s) - ‘’ saved [22/22]
root@host~$
This is a test object.
什么是SNI
SNI是Server Name Indication的简称,即服务器名称指⽰,其作⽤是
允许在相同的IP地址和TCP端⼝号的服务器上使⽤多个证书,⽽不必所有⽹站都使⽤同⼀个证书。
上⾯的中也明确的给了什么软件的什么版本⽀持SNI,由于我们服务的⽤户⽤的Java客户端,
对于java来说1.7及其以后的版本是⽀持SNI的,so, 我们继续验证测试
⾸先⽤Java1.6测试:
然后⽤Java1.7测试
[root@host java]# /opt/soft/jdk1.7/bin/javac TestGetPost.java
⽤Java1.8测试结果同1.7
Java测试代码
[root@host java]# cat TestGetPost.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.URL;
import java.URLConnection;
import java.util.List;
import java.util.Map;
public class TestGetPost {
/
**
* 向指定URL发送GET⽅法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlName = url + "?" + param;
URL realUrl = new URL(urlName);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通⽤的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
/
/ 建⽴实际的连接
// 获取所有响应头字段
Map<String, List<String>> map = HeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + (key));
}
// 定义BufferedReader输⼊流来读取URL的响应
in = new BufferedReader(
new InputStream()));
String line;
while ((line = in.readLine()) != null) {
result += "/n" + line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使⽤finally块来关闭输⼊流
finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* 向指定URL发送POST⽅法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通⽤的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
// 发送POST请求必须设置如下两⾏
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new OutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输⼊流来读取URL的响应
in = new BufferedReader(
new InputStream()));
String line;
while ((line = in.readLine()) != null) {
result += "/n" + line;
}
} catch (Exception e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
// 使⽤finally块来关闭输出流、输⼊流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/curl命令发送post请求带参数
/ 提供主⽅法,测试发送GET请求和POST请求
public static void main(String args[])
{
//发送GET请求
String str = new String("ample/");
String s = TestGetPost.sendGet(str,null);
System.out.println(str);
System.out.println(s);
}
}
结论
⾄此,基本可以确认是客户端不⽀持SNI是造成https访问失败的原因了,但也不排除是其他原因造成,待续。。。。。。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论