不安全证书提示下的请求是否依然基于Tls
好久没有更新Blog了,惭愧惭愧~
今天咱们来聊一个之前总是忽略的问题:
我记得是好几年前,当时https风初见势头,很多大一些的互联网平台都https化的时候,我也跟风的研究并搭建过基于https的网站。不过那个时候证书还是需要花钱买的,所以跟着网上的教材我只能在本地搭建测试环境~
不过这几年随着https证书贫民化,几乎所有网站都切换到了https下,什么?你还不知道如何免费https化?强力推荐使用 Certbot 。
有点跑题了,拉回来拉回来。假如我们使用自签名的证书,用浏览器打开的时候就会碰到上面截图的提示。这其实是浏览器的保护措施,不过它的提示感觉有点“过度”保护了~之前没有深究过,突然想知道,在浏览器提示不安全的私密连接的基础下执意访问呢?是否会退化到http?
不光是自签名证书会碰到这个问题,只要是浏览器验证证书有效性的时候发现问题都会提示不安全,例如证书过期,域名不匹配等。
所以我本地搭建了个测试环境,然后利用抓包工具进行了分析,得到了最终的结论: 不安全的私密连接,依然是基于https的,只是使用的证书由于没有通过验证,所以很可能是中间人的恶意证书
。
本文章不会展开SSL和TLS的历史,也不会科普TLS握手流程,这些都可以在文章底部的参考链接中的文章里找到答案。
得到这个结论并非没有任何意义,假如我们使用 curl
命令或某个语言的http库,请求一个rest服务或基于http的api接口,在服务使用自签名证书的前提下,本次调用到底是否使用证书呢?
$ curl https://192.168.1.142 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 curl: (60) SSL certificate problem: self signed certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
可以看到, curl
默认由于证书验证问题会最终放弃请求。所以我们必须明确告知 curl
忽略证书问题,可以使用这个参数 -k
。
那么如果是某种编程语言呢?我们来看几种语言的http库是什么情况:
php
curl_setopt($cHandler, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($cHandler, CURLOPT_SSL_VERIFYPEER, false);
golang
transCfg := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // ignore expired SSL certificates } client := &http.Client{Transport: transCfg}
nodejs
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
java
try { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build(); String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something") .connectTimeout(1000) .socketTimeout(1000)).returnContent().asString(); } catch (Exception e) { } # source: http://stackoverflow.com/questions/2703161/how-to-ignore-ssl-certificate-errors-in-apache-httpclient-4-0
目前,小弟我只实际抓包过 curl -k
的流程,稍后我会尝试抓一下 golang
的请求看看是否符合预期。
抓包工具
如果你只是在浏览器端或postman测试,使用 fiddler
这款工具即可,简单够用~ 但我没有办法使用它抓到 curl
的包,所以只能拿神器 wireshark
来解决问题了。
不过友情提示,一定要去官方下载 wireshark
最新版(3.03+),安装的时候选择支持监听回环网卡(npcap loopback adapter),否则是无法抓住你本机回环的请求的。
更有意思的是, wireshark
把我本机的内网ip(192.168.1.142)也当做回环地址来处理了,我本以为只要我不是用localhost或127.0.0.1,就应该可以监听到数据包的,结果花了好多时间才。。不说了,都是泪。