日常的英文译语怎么说-2012年四川高考数学


2023年4月20日发(作者:secretary怎么读)SNI问题
昨天晚上碰到个问题,当从HLB迁移到SLB的时候,有些client突然连不通了。报了如下错误。
ClientHandler$(:175)
ker(:1149)
PoolExecutor$(:624)
(:748)nCaused by: ption: Connection reset by peer
0(Native Method)
(:39)
toNativeBuffer(:223)
(:192)
(:379)
es(:253)
通过抓包⽐对,发现HLB上并没有Sever name这⼀项,⽽SLB是有的。

SNI
⾸先我们搞清楚啥是SNI,为啥这个server name会对连接有影响。
SNI(Server Name Indication)是 TLS 的扩展,⽤来解决⼀个服务器拥有多个域名的情况。
在客户端和服务端建⽴ HTTPS 的过程中要先进⾏ TLS 握⼿,握⼿后会将 HTTP 报⽂使⽤协商好的密钥加密传输。
在 TLS 握⼿信息中并没有携带客户端要访问的⽬标地址。这样会导致⼀个问题,如果⼀台服务器有多个虚拟主机,且每个主机的域名不⼀样,使
⽤了不⼀样的证书,该和哪台虚拟主机进⾏通信?这也就解释了为什么SLB需要SNI。
为了解决此问题,产⽣了 SNI,SNI 中⽂名为服务器名称指⽰,是对 SSL/TLS 协议的扩展,允许在单个 IP 地址上承载多个 SSL 证书。SNI 的
实现⽅式是将 HTTP 头插⼊到 SSL 的握⼿中,提交请求的 Host 信息,使得服务器能够切换到正确的域并返回相应的正确证书。
SNI(Server Name Indication)定义在RFC 4366,是⼀项⽤于改善SSL/TLS的技术,在SSLv3/TLSv1中被启⽤。它允许客户端在发起SSL
握⼿请求时(具体说来,是客户端发出SSL请求中的ClientHello阶段),就提交请求的Host信息,使得服务器能够切换到正确的域并返回相应的
证书。在 TLSv1.2(OpenSSL 0.9.8)版本开始⽀持。下⾯是SNI的格式。
Extension: server_name
Type: server_name (0x0000)
Length: 16
Server Name Indication extension
Server Name list length: 14
Server Name Type: host_name (0)
Server Name length: 11
Server Name:

这⾥指定了该 TLS 握⼿的⽬标域名为 。通过 SNI,拥有多虚拟机主机和多域名的服务器就可以正常建⽴ TLS 连接了。
在上述问题,肯是连接没带SNI extension导致的链接失败。
证实服务确实是不⽀持 SNI
⾸先需要说的是,从 JDK 是从 1.7 开始才真正⽀持 SNI,也就是说还在使⽤ 1.6 版本 JDK 的话是⽆论如何都⽆法使⽤ SNI 的。
HttpClient 是从 4古诗词手抄报一等奖 .3.2 开始⽀持 SNI 的。即使你使⽤的是 JDK 1.7 或更新版本的 JDK,但还是使⽤ 4.3.2 以前的 HttpClient 的话,也是
⽆法使⽤ SNI 的。
我们调⽤ Web Hook 的服务使⽤的是 clj-http 0.7.8,这个版本的 clj-http 刚好使⽤的是 4.3.1 的 HttpClient,所以才有了上⾯说的调⽤ Web
Hook 进⾏ SSL 握⼿时没有带着 SNI 导致拿到错误证书。
为了证实 clj-http 0.7.8 在请求 https 服务时,SSL 握⼿没有带着 SNI ,⾸先需要添加 JVM 参数:
-=all
这个参数在调试 SSL 握⼿相关问题时⾮常有⽤,能把完整的握⼿过程,使⽤的证书等都打印出来。测试就是随意发了个 POST 请求到
https: 在打印出来的 ClientHello 阶段有如下信息:
*** ClientHello,雁字回时月满西楼的意思 TLSv1.2
RandomCookie: GMT: 1475193456 bytes = { 187, 13, 85, ...... }
Session ID: {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, .......]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {secp256r1, .......}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512w暴风骤雨 ithECDSA, ......
上⾯内容通过 tcpdump 抓包也能得到,但如果能增加 -=all 这个配置的话还是打印出来会更⽅便⼀点。主要是看到上⾯
Extension 只有三⾏内容,少了:
Extension server_name, server_name: [type=host_name (0), value=]
如果⽀持 SNI 的话是⼀定会打印上⾯这个 Extension 信息的。从⽽证实 clj-http 0.7.8 确实是不⽀持 SNI 的。
那是不是将 clj-http 升级到最新版,HttpClient 也使⽤最新版就可以了呢?
还不⾏。⽬前 HttpClient 对 SNI 的⽀持并不是向前兼容的,⽽是提供了⼀套新的 API 让⽤户使⽤。想要使⽤ SNI 就必须调⽤新的 HttpClient
的 API。clj-http 从 0.7.8 直到最新的发布版 2.3.0 都还在使⽤ HttpClient ⽼版本的 API,只有更新⼀些的还在开发中的 3.4.1 才真正切换到
了新的 API。
这⾥就有疑问了,为什么 JDK ⽀持了 SNI,HttpClient 还得靠增加⼀套 API 来⽀持 SNI 呢?
JDK 对 SNI 的⽀持
为了解开疑问,先来看看 JDK 是怎么⽀持 SNI 的。JDK 要创建 SSL 的 Socket 需要使⽤ ketFactory。
SSLSocketFactory 提供了⼏种构造 Socket 的⽅式:

Socket createSocket()
Socket createSocket(String host, int port)
Socket createSocket(String host, int port, InetAddress localhost, int localPort) throws IOException, UnknownHostException;
Socket createSocket(InetAddress address, int port)
Socket createSocket(InetAddress address, int port, InetAddress remoteHost, int remotePort)
Socket createSocket(Socket socket, String host, int port, boolean autoClose)
需要注意:
1. 有 host 参数的都会在创建 Socket 的时候⾃动连接 host
2. 只有直接以 String 传递 host 的⽅式才会在握⼿中使⽤ SNI,以 InetAddress 传递 host 的⽅式握⼿时都不会带着 SNI
3. 第 6 ⾏的 createSocket 很特殊,是传⼊⼀个 Socket (已连接或未连接),然后建⽴⼀个新的 Socket layered over 原来的 Socket,如果
原来的 Socket 没有建⽴连接,则在创建后会⽴即连接 host
第⼆条很关键,但在 JDK ⽂档上竟然完全没有说明。
ketFactory socketfactory = (ketFactory)ault();
SSLSocket sock;
// 握⼿不会带着 SNI
sock = (SSLSocket)Socket();
t(new InetSocketAddress(\"\", 443));
andshake();
// 握⼿不会带着 SNI
sock = (SSLSocket)Socket(ame(\"\"), 443);
andshake();
// 握⼿会带着 SNI
sock = (SSLSocket)Socket(\"\", 443);
andshake();
// 握⼿会带着 SNI
Socket plainSocket = ault().createSocket();
// plainSocket 可以先执⾏ connect,并且这⾥可以传递 InetSocketAddress
// 只要 Layered Socket 创建时⽤的传 String 适合小学生现代诗简短 createSocket 即可
t(new InetSocketAddress(\"\", 443), 30);
// 因为 plainSocket 已经建⽴连接,所以这⾥传递 String Host 只是为了将其填⼊ SNI
sock = Socket(plainSocket, \"\", 443, true);
andshake();
从这⾥也能看出来是否使⽤ SNI 创建连接藏的很隐晦。据说 JDK 不允许传递 InetAddress 的 createSocket 创建出来的 SSLSocket 在 SSL
握⼿时⾃动使⽤ SNI,是因为 InetAddress 构造的时候⽀持 getByName 函数,该函数可以传个 IP ⽽不是 Host。这种情况下⽤户真传个 IP
进来再允许开启 SNI 将这个 IP 放⼊ SNI 中就不符合 SNI 使⽤条件了,因为 SNI 只能填 Host Name。不过感觉理由还是⽐较牵强,总之就是
这个 API 设计的有些诡异,藏得有点深。
HttpClient 对 SNI 的⽀持
为了了解缘由需要看⼀下这个 JIRA 讨论
注意:以下内容基于:
[mponents/httpcore “4.4.5”]
[mponents/httpclient “4.5.2”]
来说。以后内部实现可能还会变化。
在 HttpClient 的框架中,所有 Socket 都是先调⽤ SocketFactory (有新旧两个版本,Factory 和
tionSocketFactory。两个版本都有 createSocket 和 connectSocket) 的 createSocket ⽅法先创
建 Socket,之后对构造出来的 Socket 进⾏配置,添加⽐如 SO_TIMEOUT,SO_REUSEADDR,TCP_NODELAY 等,之后再调⽤
SocketFactory 的 connectSocket ⽅法去和 remote 地址建⽴连接。

在⽼版本的 HttpClient 下,默认都是⽤ ketFactory ⽆参的 createSocket 函数来创建 Socket 的。在完全不改动上层
实现的情况下是⽆法⽀持 SNI 了,所以新建⽴了⼀套 API。
clj-http 0.7.8 翻译为直接使⽤ HttpClient 的代码如下,这个是不⽀持 SNI 的:
SchemeRegistry registry = new SchemeRegistry();
er(new Scheme(\"http\", 80, ketFactory()));
SSLSocketFactory sslFac = ketFactory();
tnameVerifier(_HOSTNAME_VERIFIER);
er(new Scheme(\"https\", 443, sslFac));
BasicClientConnectionManager manager = new BasicClientConnectionManager(registry);
HttpPost post = new HttpPost(\"\");
DefaultHttpClient httpClient = new DefaultHttpClient(manager);
e(post);
clj-http 3.4.1 翻译为直接使⽤ HttpClient 的代码如下:
Registry registry = RegistryBuilder.create()
.register(\"http\", ketFactory())
.register(\"https\", ketFactory())
.build();
BasicHttpClientConnectionManager manager = new BasicHttpClientConnectionManager(registry);
HttpPost post = new HttpPost(\"\");
HttpClient httpClient = ()
.setConnectionManager(manager)
.build();
e(post);
最关键的差别在于⽼的 clj-http 使⽤的是 SSLSocketFactory ⽽新的使⽤的是 SSLConnectionSocketFactory,再就是⽼版本使⽤的是
DefaultHttpClient,新版本使⽤的是 HttpClients 构造出来的 HttpClient 。
DefaultHttpClient 中,处理连接部分的是:
tClientConnectionOperator
⽼版新版不同点
SSLSocketFactorySSLConnectionSocketFactory
DefaultHttpClient
DefaultClientConnectionOperatorDefaultHttpClientConnectionOperator
创建 SSLSocket 的 Factory 不同
使⽤的 HttpClie吟组词语 nt 不同
HttpClient 构建连接的类不同
HttpClients 构造出来的
HttpClient
DefaultClientConnectionOperator 使⽤ SSLSocketFactory 构造 SSLSocket,⽤的是 ketFactory 的⽆参的
createSocket 构造 SSLSocket并且在 SSLSocketFactory 内使⽤创建出来的 SSLSocket 与⽬标 Host 建⽴连接时使⽤的 InetAddress
⽅式传递⽬标 Host Name之后再开始握⼿流程,这就⽆法使⽤ SNI 了。
DefaultHttpClientConnectionOperator 使⽤的 SSLConnectionSocketFactory 先构造出普通的 Socket
SSLConnectionSocketFactory 调⽤ Socket 的 connect 参数先与⽬标服务建⽴连接。注意与 DefaultClientConnectionOperator 的不
同,DefaultClientConnectionOperator 在调⽤ SSLSocketFactory 的 connectSocket 时传⼊的 Socket 就是 SSLSocket,⽽
DefaultHttpClientConnectionOperator 在调⽤ SSLConnectionSocketFactory 的 connectSocket 时传⼊的 socket 只是普通的
Socket。在这个普通的 Socket 与 remote host 建⽴连接之后,通过调⽤ SSLConnectionSocketFactory 内 createLayeredSocket 在普
通 Socket 之上调⽤ ketFactory 的传递 Socket 和普通 String 形式 Host Name 的 createSocket 函数构造出
SSLSocket,之后开始握⼿流程就能使⽤ SNI 了
对于上⽂出现的问题,它并不是由httpclient 发出的,⽽且⼜netty的client 发出的。这就需要Netty的connector 在处理sslsocket 时候按照
JDK的规范来写。⽬前的实现是不能满⾜SNI 握⼿需要的。

代码
客户端直接指定SNI,这⾥是另外⼀种写法
SSLSocketFactory factory = ...
SSLSocket sslSocket = Soc岱宗夫如何齐鲁青未了翻译 ket(\"172.16.10.6\", 443);
// SSLEngine sslEngine = SSLEngine(\"172.16.10.6\", 443);
SNIHostName serverName = new SNIHostName(\"\");
List serverNames = new ArrayList<>(1);
(serverName);
SSLParameters params = Parameters();
verNames(serverNames);
Parameters(params);
// Parameters(params);
server端如果需要⾃⼰enable SNI 校验,需要⾃⼰实现逻辑。但是事实上这个⼯作并不需要,在LB层已经实现了。只是让⼤家参考,如果⾃⼰
写⼤概是什么样⼦。
SSLServerSocket sslServerSocket = ...;
SNIMatcher matcher = SNIMatcher(\"e.(com|org)\");
Collection matchers = new ArrayList<>(1);
(matcher);
SSLParameters params = Parameters();
Matchers(matchers);
Parameters(params);
SSLSocket sslSocket = ();
调试
ssl⽇志打印到控制台。Debug Configrations 中找到使⽤的启动类名称后配置参数。在vm arguments 中添加参数-=ssl

-=ssl
或者
-=all

all turn on all debugging
ssl turn on ssl debugging

The following can be used with ssl:

record enable per-record tracing
handshake print each handshak杜少府是杜甫吗 e message
keygen print key的多音字组词语 generation data
session print session activity
defaultctx print default SSL initialization
sslctx print SSLContext tracing
sessioncache print session cache tracing
keymanager print key manager tracing
trustmanager print trust manager tracing
pluggability print pluggability tracing

handshake debugging can be widened with:
data hex dump of each handshake message
verbose verbose handshake message printing

record debugging can be widened with:
plaintext hex dump of record plaintext
packet print raw SSL/TLS packets

桑的英文怎么说-广购网


更多推荐

CLJ是什么意思在线翻译读音例句