24
24
< meta property ="og:description " content ="使用 SSL SNI 拦截 SSL 握手攻击一、概述SSL/TLS是用于在网络上进行安全通信的加密协议,各网络公司为保证数据传输的安全性均采用了SSL/TLS通信方式,相校于明文传输方式,SSL/TLS对于计算成本要求更高,尤其是在SSL/TLS握手阶段更是耗费了大量计算资源,攻击者可以轻易利用这一问题对服务端发起SSL/TLS握手攻击,攻击者只需 ">
25
25
< meta property ="og:locale " content ="zh_CN ">
26
26
< meta property ="article:published_time " content ="2024-06-02T13:34:00.000Z ">
27
- < meta property ="article:modified_time " content ="2024-06-03T05:09:25.756Z ">
27
+ < meta property ="article:modified_time " content ="2024-09-26T01:15:07.265Z ">
28
28
< meta property ="article:author " content ="zsxxsz ">
29
29
< meta property ="article:tag " content ="SSL编程 ">
30
30
< meta name ="twitter:card " content ="summary_large_image ">
237
237
< span class ="post-meta mr-2 ">
238
238
< i class ="iconfont icon-chart "> </ i >
239
239
240
- 3.5k 字
240
+ 3.6k 字
241
241
242
242
</ span >
243
243
248
248
249
249
250
250
251
- 30 分钟
251
+ 31 分钟
252
252
253
253
</ span >
254
254
@@ -323,8 +323,8 @@ <h3 id="3-1、SSL-服务端"><a href="#3-1、SSL-服务端" class="headerlink" t
323
323
< figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > < span class ="line "> 2</ span > < br > < span class ="line "> 3</ span > < br > < span class ="line "> 4</ span > < br > < span class ="line "> 5</ span > < br > < span class ="line "> 6</ span > < br > < span class ="line "> 7</ span > < br > < span class ="line "> 8</ span > < br > < span class ="line "> 9</ span > < br > < span class ="line "> 10</ span > < br > < span class ="line "> 11</ span > < br > < span class ="line "> 12</ span > < br > < span class ="line "> 13</ span > < br > < span class ="line "> 14</ span > < br > < span class ="line "> 15</ span > < br > < span class ="line "> 16</ span > < br > < span class ="line "> 17</ span > < br > < span class ="line "> 18</ span > < br > < span class ="line "> 19</ span > < br > < span class ="line "> 20</ span > < br > < span class ="line "> 21</ span > < br > < span class ="line "> 22</ span > < br > < span class ="line "> 23</ span > < br > < span class ="line "> 24</ span > < br > < span class ="line "> 25</ span > < br > < span class ="line "> 26</ span > < br > < span class ="line "> 27</ span > < br > < span class ="line "> 28</ span > < br > < span class ="line "> 29</ span > < br > < span class ="line "> 30</ span > < br > < span class ="line "> 31</ span > < br > < span class ="line "> 32</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> < span class ="hljs-keyword "> class</ span > < span class ="hljs-title class_ "> my_sni_checker</ span > : < span class ="hljs-keyword "> public</ span > acl::ssl_sni_checker {< br > < span class ="hljs-keyword "> public</ span > :< br > < span class ="hljs-built_in "> my_sni_checker</ span > () {}< br > ~< span class ="hljs-built_in "> my_sni_checker</ span > () {}< br > < br > < span class ="hljs-comment "> // @override</ span > < br > < span class ="hljs-function "> < span class ="hljs-type "> bool</ span > < span class ="hljs-title "> check</ span > < span class ="hljs-params "> (acl::sslbase_io* io, < span class ="hljs-type "> const</ span > < span class ="hljs-type "> char</ span > * sni, acl::string& host)</ span > </ span > {< br > < span class ="hljs-keyword "> if</ span > (sni == < span class ="hljs-literal "> NULL</ span > || *sni == < span class ="hljs-number "> 0</ span > ) {< br > < span class ="hljs-comment "> // 如果客户端未提供 SNI 标识字符串则返回错误,禁止进行 SSL 握手. </ span > < br > < span class ="hljs-built_in "> printf</ span > (< span class ="hljs-string "> "No SNI=%p\r\n"</ span > , sni);< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> false</ span > ;< br > }< br > < br > < span class ="hljs-comment "> // 从 SNI 中提取服务端主机域名,并保存,以便 Acl SSL 模块选择本地的 SSL 证书</ span > < br > < span class ="hljs-comment "> // 并进行 SSL 握手。</ span > < br > < span class ="hljs-function "> acl::string < span class ="hljs-title "> buf</ span > < span class ="hljs-params "> (sni)</ span > </ span > ;< br > < span class ="hljs-type "> const</ span > std::vector<acl::string>& tokens = buf.< span class ="hljs-built_in "> split2</ span > (< span class ="hljs-string "> "|"</ span > );< br > < span class ="hljs-keyword "> if</ span > (tokens.< span class ="hljs-built_in "> size</ span > () != < span class ="hljs-number "> 2</ span > ) {< br > < span class ="hljs-built_in "> printf</ span > (< span class ="hljs-string "> "Invalid sni=%s\r\n"</ span > , sni);< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> false</ span > ;< br > }< br > < br > host = tokens[< span class ="hljs-number "> 1</ span > ];< br > < br > < span class ="hljs-comment "> // check_token(tokens[0]); // 应用自行检查加密串的合法性。</ span > < br > < br > < span class ="hljs-built_in "> printf</ span > (< span class ="hljs-string "> "Check sni ok, sni=%s, host=%s\r\n"</ span > , sni,, host.< span class ="hljs-built_in "> c_str</ span > ());< br > < br > < span class ="hljs-comment "> // 返回 true 则允许 Acl SSL 模块可以进一步进行 SSL 握手。</ span > < br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> true</ span > ;< br > }< br > };< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
324
324
325
325
< p > SSL 客户端模块与服务端可以协商一个 sni 的生成规则,比如 sni 字符串类似于 < code > token|host</ code > (比如:xxxxxx|myhost.test.com),期中 token 字段可以是双方私密生成的加密字符串,host 为主机域名。服务端仅针放行符合加密规则的客户端 SSL 连接,其它连接一概拦截。</ p >
326
- < h4 id ="3-1-2、创建僵尸 -SSL-对象中添加 -SNI-验证对象 "> < a href ="#3-1-2、创建僵尸 -SSL-对象中添加 -SNI-验证对象 " class ="headerlink " title ="3.1.2、创建僵尸 SSL 对象中添加 SNI 验证对象 "> </ a > 3.1.2、创建僵尸 SSL 对象中添加 SNI 验证对象</ h4 > < p > 下面代码是创建全局的 SSL 配置管理对象代码:</ p >
327
- < figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> acl::sslbase_conf* ssl_conf = < span class ="hljs-keyword "> new</ span > acl::< span class ="hljs-built_in "> openssl_conf</ span > (< span class ="hljs-literal "> true</ span > );< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
326
+ < h4 id ="3-1-2、创建全局 -SSL-配置对象并绑定 -SNI-验证对象 "> < a href ="#3-1-2、创建全局 -SSL-配置对象并绑定 -SNI-验证对象 " class ="headerlink " title ="3.1.2、创建全局 SSL 配置对象并绑定 SNI 验证对象 "> </ a > 3.1.2、创建全局 SSL 配置对象并绑定 SNI 验证对象</ h4 > < p > 下面代码是创建全局的 SSL 配置管理对象代码:</ p >
327
+ < figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > < span class =" line " > 2 </ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> acl::sslbase_conf* ssl_conf = < span class ="hljs-keyword "> new</ span > acl::< span class ="hljs-built_in "> openssl_conf</ span > (< span class ="hljs-literal "> true</ span > );< br > < span class =" hljs-comment " > // 添加服务端 SSL 证书 </ span > < br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
328
328
329
329
< p > 全局 SSL 配置管理对象创建后,添加 SSL SNI 验证对象:</ p >
330
330
< figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> ssl_conf->< span class ="hljs-built_in "> set_sni_checker</ span > (< span class ="hljs-keyword "> new</ span > < span class ="hljs-built_in "> ssl_sni_checker</ span > ());< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
@@ -333,13 +333,14 @@ <h4 id="3-1-3、与-SSL-客户端进行-SSL-握手"><a href="#3-1-3、与-SSL-
333
333
< figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > < span class ="line "> 2</ span > < br > < span class ="line "> 3</ span > < br > < span class ="line "> 4</ span > < br > < span class ="line "> 5</ span > < br > < span class ="line "> 6</ span > < br > < span class ="line "> 7</ span > < br > < span class ="line "> 8</ span > < br > < span class ="line "> 9</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> < br > < span class ="hljs-function "> < span class ="hljs-type "> bool</ span > < span class ="hljs-title "> ssl_handshake</ span > < span class ="hljs-params "> (acl::sslbase_conf& ssl_conf, acl::socket_stream& conn)</ span > </ span > {< br > acl::sslbase_io* ssl = ssl_conf.< span class ="hljs-built_in "> create</ span > (< span class ="hljs-literal "> false</ span > );< br > < span class ="hljs-keyword "> if</ span > (conn.< span class ="hljs-built_in "> setup_hook</ span > (ssl) == ssl) { < span class ="hljs-comment "> // SSL 握手失败,包括 SSL SNI 查检失败。</ span > < br > ssl->< span class ="hljs-built_in "> destroy</ span > ();< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> false</ span > ;< br > }< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> true</ span > ;< br > }< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
334
334
335
335
< h3 id ="3-2、SSL-客户端 "> < a href ="#3-2、SSL-客户端 " class ="headerlink " title ="3.2、SSL 客户端 "> </ a > 3.2、SSL 客户端</ h3 > < p > 客户端在与服务端建立 TCP 连接后,进行 SSL 握手时需要先设置 SSL SNI 字段,SNI 字段中既有域名信息,又有加密串信息,当服务端收到该 SNI 串时,从中取出加密及域名信息后,先验证加密数据的合法性,验证通过则进行 SSL 握手,否则禁止 SSL 握手,从而避免浪费 CPU 计算资源。下面是 SSL 客户端的简单示例:</ p >
336
- < figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > < span class ="line "> 2</ span > < br > < span class ="line "> 3</ span > < br > < span class ="line "> 4</ span > < br > < span class ="line "> 5</ span > < br > < span class ="line "> 6</ span > < br > < span class ="line "> 7</ span > < br > < span class ="line "> 8</ span > < br > < span class ="line "> 9</ span > < br > < span class ="line "> 10</ span > < br > < span class ="line "> 11</ span > < br > < span class ="line "> 12</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> < br > < span class ="hljs-function "> < span class ="hljs-type "> bool</ span > < span class ="hljs-title "> ssl_handshake</ span > < span class ="hljs-params "> (acl::sslbase_conf& conf, acl::socket_stream& conn)</ span > </ span > {< br > acl::sslbase_io* ssl = conf.< span class ="hljs-built_in "> create</ span > (< span class ="hljs-literal "> false</ span > );< br > < span class ="hljs-type "> const</ span > < span class ="hljs-type "> char</ span > * sni = < span class ="hljs-string "> "crypted_token|mytest.com"</ span > ;< br > ssl->< span class ="hljs-built_in "> set_sni_host</ span > (sni); < span class ="hljs-comment "> // 设置 SNI 字段</ span > < br > < span class ="hljs-keyword "> if</ span > (conn.< span class ="hljs-built_in "> setup_hook</ span > (ssl) == ssl) {< br > < span class ="hljs-comment "> // SSL 握手失败,销毁 SSL IO 对象。</ span > < br > ssl->< span class ="hljs-built_in "> destroy</ span > ();< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> false</ span > ;< br > }< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> true</ span > ;< br > }< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
336
+ < figure class ="highlight c++ "> < table > < tr > < td class ="gutter "> < pre > < span class ="line "> 1</ span > < br > < span class ="line "> 2</ span > < br > < span class ="line "> 3</ span > < br > < span class ="line "> 4</ span > < br > < span class ="line "> 5</ span > < br > < span class ="line "> 6</ span > < br > < span class ="line "> 7</ span > < br > < span class ="line "> 8</ span > < br > < span class ="line "> 9</ span > < br > < span class ="line "> 10</ span > < br > < span class ="line "> 11</ span > < br > < span class ="line "> 12</ span > < br > </ pre > </ td > < td class ="code "> < pre > < code class ="hljs c++ "> < br > < span class ="hljs-function "> < span class ="hljs-type "> bool</ span > < span class ="hljs-title "> ssl_handshake</ span > < span class ="hljs-params "> (acl::sslbase_conf& conf, acl::socket_stream& conn)</ span > </ span > {< br > acl::sslbase_io* ssl = conf.< span class ="hljs-built_in "> create</ span > (< span class ="hljs-literal "> false</ span > );< br > < span class ="hljs-type "> const</ span > < span class ="hljs-type "> char</ span > * sni = < span class ="hljs-string "> "crypted_token|mytest.com"</ span > ; < span class ="hljs-comment "> // 期中的加密token将由服务端验证</ span > < br > ssl->< span class ="hljs-built_in "> set_sni_host</ span > (sni); < span class ="hljs-comment "> // 设置 SNI 字段</ span > < br > < span class ="hljs-keyword "> if</ span > (conn.< span class ="hljs-built_in "> setup_hook</ span > (ssl) == ssl) {< br > < span class ="hljs-comment "> // SSL 握手失败,销毁 SSL IO 对象。</ span > < br > ssl->< span class ="hljs-built_in "> destroy</ span > ();< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> false</ span > ;< br > }< br > < span class ="hljs-keyword "> return</ span > < span class ="hljs-literal "> true</ span > ;< br > }< br > </ code > </ pre > </ td > </ tr > </ table > </ figure >
337
337
338
338
< h3 id ="3-3、参考 "> < a href ="#3-3、参考 " class ="headerlink " title ="3.3、参考 "> </ a > 3.3、参考</ h3 > < ul >
339
339
< li > Acl 库下载: < a target ="_blank " rel ="noopener " href ="https://github.com/acl-dev/acl/ "> https://github.com/acl-dev/acl/</ a > </ li >
340
340
< li > 客户端示例:acl/lib_acl_cpp/samples/ssl/client</ li >
341
341
< li > 服务端示例:acl/lib_acl_cpp/samples/ssl/server</ li >
342
342
< li > 使用SSL中对数据进行加密传输:< a href ="https://acl-dev.cn/2020/01/15/ssl/ "> https://acl-dev.cn/2020/01/15/ssl/</ a > </ li >
343
+ < li > Acl库下载:< a target ="_blank " rel ="noopener " href ="https://github.com/acl-dev/acl/ "> https://github.com/acl-dev/acl/</ a > </ li >
343
344
</ ul >
344
345
345
346
@@ -431,6 +432,12 @@ <h3 id="3-3、参考"><a href="#3-3、参考" class="headerlink" title="3.3、
431
432
< article class ="post-prev col-6 ">
432
433
433
434
435
+ < a href ="/2024/09/24/fiber_qt/ " title ="在 QT 界面编程中使用协程 ">
436
+ < i class ="iconfont icon-arrowleft "> </ i >
437
+ < span class ="hidden-mobile "> 在 QT 界面编程中使用协程</ span >
438
+ < span class ="visible-mobile "> 上一篇</ span >
439
+ </ a >
440
+
434
441
</ article >
435
442
< article class ="post-next col-6 ">
436
443
0 commit comments