go websocket 问题(Hijacker)

go websocket 问题(Hijacker),第1张

在写websocket包的时候发现一个比较有趣问题!go 使用 TLS验证的时候发现 websocket 使用不了。深入了解发现其中奥秘:go 在执行 TLS 验证时候默认是使用 http2 协议进行的!但是 websocket 是无法支持 http2 协议(暂时),导致这个问题所在的原因!

使用空 map 来使用 http1.x协议

因为默认支持h2,所有我们把降到http1.x。

使用 http.Hijacker 对其进行劫持 net.Conn , 让程序员自己控制使用!其实这个时候已经脱离 http 协议规范!

发现使用 Hijacker 会脱离 http 协议范畴,可以解决h2与websocket的相关问题!

协议: 状态码:101 , Upgrade , Connection, Sec-WebSocket-Accept

实现最简单 websocket 连接!

websocket连接已经建立,有些 sec 是默认添加上去!

根据 http.Listen 进行向下追踪

在 func (srv *Server) Serve(l net.Listener) error 发现原由

对 c.setState 进入分析

发现当 case 是 Hijack【StateHijacked, StateClosed】状态时候执行 trackConn

add 为 false ,对其 delete(s.activeConn,c) 。Hijacker是满足相关条件

所以在 go c.serve(connCtx) 里面不在给 Hijacker 进行操作!导致 http header 无法设置!最后交给程序员自己操作!

go中自带的rpc可以直接复用http server处理请求的那一套流程去创建连接,连接创建完毕后再使用Hijack方法拿到连接。

注: github.com/gorilla/websocket

这包就接入 HIjacker ,直接使用现成包就香~~~~~

本系列文章包含以下内容

本系列文章中大写 C 统一表示客户端,大写 S 表示服务器端。

定义摘自维基百科。

完整性保障很容易理解, C (客户端)与 S (服务器端)通信,客户端发出信息[ 转10000给张三 ],经过网络传输后,由于网络丢包变成了[ 转100块给张三 ],客户端估计会被张三揍哭。因此服务端(收到信息的一方)需要保证收到的信息确实一丝一毫都没变。这就是完整性。

保证完整性通常通过哈希值来实现。比如我们可以设计一种弱鸡的算法,计算字数的个数作为哈希,那么信息变成了[ 转10000块给张三,10 ],其中10就是哈希值,那么如果服务端收到的信息是[ 转100块给张三,10 ],服务端检查到哈希值不正确就知道消息在传输过程中发生了错误。然而如果信息变成了[ 转20000块钱给张三,10 ],这个弱鸡算法就不能帮助服务器检查到这个错误。因此哈希算法基础的要求就是碰撞(给定信息1,构造另一段信息2,使得2的哈希值与1相等)的难度。

什么是安全性呢?

安全性包含两个方面,假定 C 是你, S 是你女朋友。 S 给 C 发信息[ 给我打10000块 ]。 C 的第一反应是什么?是确认 S 真的是你女朋友。因此安全性的第一个方面是确定双方的通信身份。

假如 C 想给 S 回复[ 今晚XXXX不可描述 ], C 需要确认什么?一定是这段信息没人在窃听。这就是安全性的第二个方面。

如何解决第一个问题:C和S如何确定 你真的是你 ? 在 C 和 S 互为男女朋友的情况下,C可以和S约定一下暗号,比如 天王盖地虎 对 小鸡炖蘑菇 ,在每次通信之前先对一下暗号。

如果只有C和S通信,约定暗号自然是可行的。但是如果C或者S不只一个呢。比如有C1,C2,那么如果用同样的暗号,C2知道暗号是什么后就可以欺骗S说自己是C1。如果都约定不同的暗号,那么假如有C1,C2,... ,C10000,那么就有S就需要记住10000个暗号,并且每新来一个C,就需要多记住一个暗号。

S表示,太累了。“给你们一段我的手写体吧,以后你们验证笔迹一样就能确定我是我了”

"笔迹,太容易伪造了吧!", 数学表示,"是时候看我展现真正的实力了!"

困难问题在数学中通常是"讨厌"的存在,数学家们会穷尽毕生去解决。密码学却是数学中的一个有趣的分支,它反其道而行之,核心是去证明某个问题是困难的。什么是困难问题?民科定义就是在 现有的公开的数学 下,要解决这个问题得花成百上千年。专业术语表达是 NP问题 ,或者从安全意义上说 解决这个问题获得的利益小于解决问题付出的代价 。

"嘿嘿嘿,这道题你们做不出来,但是我有后门,我会做"。加密算法站了出来。

先用 非对称加密 (加密密钥和解密密钥不相同)来解决 你真的是你 这个问题。

在非对称算法中,有两个密钥,一个是公钥,一个私钥。通常情况下私钥自己留着,公钥给对外公开。私钥加密后的信息,公钥可以解密还原内容。 由公钥以及已经发生过的加密解密信息推算出私钥是一个困难问题

我们来尝试构造一个弱鸡的非对称算法,并假装它是一个困难问题。

这个算法是这样的,假定我们发出的信息只能是[1,2,3,4,5,...,10], 公钥是10。并且我们自己保留私钥7。加密算法是 (x+7)%17, 解密算法是 (x+10)%17。我们假装通过10和已经发生过的加解密的过程无法推算出私钥7。

由于((x+7)%17+10)%17 = x, 比如对信息5加密,用私钥7加密5+7=12,用公钥10解密(12+10)%17=22%17=5, 就可以将信息还原。

有了这个算法,C需要验证S的身份只需要说一句,“嘿,6加密后的数据是什么”,S算了以下回复,“13”,客户端用公钥运算(13+10)%17果然是6,就可以快乐的回应,“来啦,老弟!”

在上面的场景中,有了非对称密钥算法,S可以换成说,“我的公钥放在网上了,你们自己去拿,拿好以后,以后验证我私钥加密过的信息解密后就确认我是我了”。(注:这里不谈及CA及信任链,默认C拿到证书后可以确认这个证书确实是S的证书)

如何解决第二个问题:C和S如何确保通信没有被窃听,或者即使被窃听也不能听懂内容究竟是什么?

在互联网环境下,保证第一条是不可能的,公开网络中任何一个节点都有可能被抓包解析。非对称加密通过私钥加密信息在网上传输可以应对这个问题。但这样做有两个缺点:一个是非对称加密通常相对比较慢,第二个问题是虽说非对称加密是安全的,但架不住老是拿同样的公钥私钥来传输大量的信息,这样做会破坏它的安全性。因此,通常会选择使用用公钥沟通,得出一个在一次对话过程中使用的对称加密(公钥和私钥相同)的密钥来(密钥交换协议),并在之后的通信中使用对称加密算法来加密传输内容,来保证传输过程的安全性。

对称加密容易理解,这里不做多谈。

注意:以上简介均非规范描述,只是以简化的形式来描述网络通信面临的安全问题以及解决的方法。

简介中提到的对称加密算法,非对称加密算法,和没有提及的如何在一次会话中采用安全的协议来沟通出对称密钥,均可以在 维基百科 上找到相应的介绍。

你好,下面主要说一说如何配置SSL/TLS服务器。

Sun在JDK中提供了一个安全钥匙与证书的管理工具Keytool。Keytool 把钥匙,证书以及和与它们相关联的证书链储存到一个keystore,默任的实现keystore的是一个文件,它有一个密码保护存储在其中的内容。

配置一个SSL/TLS服务器需要以下几步:

假设服务器的域名是:test.server.net

1.为服务器的keystore,以存储证书等。

keytool -genkey -alias test.server.net -keyalg RSA -keystore <your_keystore_filename>

在执行上面的命令式,会要求用户输入一些信息,例如keystore密码,服务器区域等等,依照提示输入即可。

2.生成一个Certificate Signing Request (CSR),CSR是提供给证书颁发机构,供证书颁发机构依据其中信息生成证书的。

keytool -certreq -keyalg RSA -alias test.server.net -file certreq.csr -keystore <your_keystore_filename>

3.将CSR提供给证书颁发机构CA,等待CA颁发证书:

知名的CA有Versign, Thawte等。

4.在CA等网站上下载CA的根证书。

5.导入CA的根证书到keystore中

keytool -import -alias root -keystore <your_keystore_filename>-trustcacerts -file <filename_of_the_root_certificate>

6.导入CA颁发的证书到keystore,CA通常不会直接返回一个文件,而是通过网页或email以文本形式提供,需要用户自己创建一个文件,再将文本拷入。

keytool -import -alias test.server.net -keystore <your_keystore_filename>-trustcacerts -file <your_certificate_filename>

这样就完成对服务器的配置,最后为服务器指定这个keystore就可以了。

注意:一定导入正确的CA根证书,最常见的错误就是没有导入或导入错误的CA根证书。

注意:有些客户端,在使用SSL/TLS时必须通过域名来连接服务器,不能通过IP地址来连接。其所连接的服务器域名和服务器的证书的颁发对象必须相同。例如服务器的域名是test.server.net,那么服务器的证书也必须是颁发给test.server.net的。

天互数据 为您解答,希望能帮到你


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/537054.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-06-25
下一篇2023-06-25

发表评论

登录后才能评论

评论列表(0条)

    保存