Golang Go语言中 websocket 实现了统计在线人数,那 websocket 该如何防爆,防跨站?
Golang Go语言中 websocket 实现了统计在线人数,那 websocket 该如何防爆,防跨站?
站点在线人数统计实现思路: https://www.douyacun.com/article/d189d3d86915f5ff4c3be6a517570a0a
-
如何检测跨站点 WebSocket 劫持漏洞
- 我使用 jwt 来下发 token
- 申请 token 的接口也是对外暴露的
- 同一设备 ws 连接数如何限制,避免 bug 导致连接数过多导致服务挂掉
更多关于Golang Go语言中 websocket 实现了统计在线人数,那 websocket 该如何防爆,防跨站?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
侧边栏弹出来遮住右侧内容是 feature?
更多关于Golang Go语言中 websocket 实现了统计在线人数,那 websocket 该如何防爆,防跨站?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
用 tcp 长链统计在线人数???也是醉了
这种方式有什么问题吗?展开说说
量,N 万 百万 在线, 你试下
wss 统计在线人数,代价还是很低的,一般只是端口不够用
我之前的测试,库使用 gorilla/websocket 1 万个连接测试
占用 147.93MB RAM, 平均连接每个占用 15kb 测试代码见:[github gwebsocket]( https://github.com/douyacun/gwebsocket/blob/master/v3_ws_ulimit/wsserver.go)shell<br>(pprof) top<br>Showing nodes accounting for 137.93MB, 93.24% of 147.93MB total<br>Dropped 6 nodes (cum <= 0.74MB)<br>Showing top 10 nodes out of 51<br> flat flat% sum% cum cum%<br> 73.79MB 49.88% 49.88% 73.79MB 49.88% bufio.NewWriterSize<br> 34.63MB 23.41% 73.29% 34.63MB 23.41% bufio.NewReaderSize<br> 11MB 7.44% 80.73% 11MB 7.44% runtime.malg<br> 4MB 2.70% 83.44% 5.50MB 3.72% net/textproto.(*Reader).ReadMIMEHeader<br> 3MB 2.03% 85.46% 3.50MB 2.37% <a target="_blank" href="http://github.com/gorilla/websocket.newConn" rel="nofollow noopener">github.com/gorilla/websocket.newConn</a><br> 3MB 2.03% 87.49% 10.50MB 7.10% net/http.readRequest<br> 2.50MB 1.69% 89.18% 16.50MB 11.16% net/http.(*conn).readRequest<br> 2.50MB 1.69% 90.87% 3.50MB 2.37% context.propagateCancel<br> 2MB 1.35% 92.23% 2MB 1.35% syscall.anyToSockaddr<br> 1.50MB 1.01% 93.24% 1.50MB 1.01% net.newFD<br>(pprof) web<br>failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH<br>(pprof) list flat<br>Total: 147.93MB<br>
goroutine 是 10003,每个 goroutine 占用 4kb 的内存shell<br>(pprof) top<br>Showing nodes accounting for 10001, 100% of 10003 total<br>Dropped 24 nodes (cum <= 50)<br>Showing top 10 nodes out of 19<br> flat flat% sum% cum cum%<br> 10001 100% 100% 10001 100% runtime.gopark<br> 0 0% 100% 9998 100% bufio.(*Reader).Peek<br> 0 0% 100% 9998 100% bufio.(*Reader).fill<br> 0 0% 100% 9999 100% <a target="_blank" href="http://github.com/gorilla/websocket.(*Conn).NextReader" rel="nofollow noopener">github.com/gorilla/websocket.(*Conn).NextReader</a><br> 0 0% 100% 9999 100% <a target="_blank" href="http://github.com/gorilla/websocket.(*Conn).ReadMessage" rel="nofollow noopener">github.com/gorilla/websocket.(*Conn).ReadMessage</a><br> 0 0% 100% 9999 100% <a target="_blank" href="http://github.com/gorilla/websocket.(*Conn).advanceFrame" rel="nofollow noopener">github.com/gorilla/websocket.(*Conn).advanceFrame</a><br> 0 0% 100% 9998 100% <a target="_blank" href="http://github.com/gorilla/websocket.(*Conn).read" rel="nofollow noopener">github.com/gorilla/websocket.(*Conn).read</a><br> 0 0% 100% 9999 100% internal/poll.(*FD).Read<br> 0 0% 100% 10001 100% internal/poll.(*pollDesc).wait<br> 0 0% 100% 10001 100% internal/poll.(*pollDesc).waitRead (inline)<br>(pprof) list flat<br>Total: 10003<br>(pprof)<br>
刚才本子打开也恶心到我自己了,都是在外接显示上开发的
第一,可能会有跨站点 WebSocket 劫持漏洞;第二,同一设备出 bug 导致连接数过多会让服务挂掉 🤣
在线人数这种需求建议还是轮询吧。
这几个问题也是这个帖子发布的目的,也是想看看大家是怎么玩的,有什么好的思路,之前有个安卓的同学就这么搞过我~,吐血的经历
自己的站点,当然随意玩耍了,主要是有 wss 使用的场景,如何防护一下
直接把用户登入的状态放在 Redis 里边啊,设置个超时时间,然后没有统计有多少数据存在不就行了
我的错,没看清标题.
抖音 APP 在使用 WS 传输 Protobuf 编码之后的数据,同时也使用了 token,这也算是一个比较好的解决方案吧
登入状态放 redis 里,如何统计有多少数据存在?命令是啥呀?
额,不同的语言写法不同。
思路就是丢个唯一值到客户端 cookie,再把这个值丢到 redis 设置个超时,然后每次新请求获取这个值,如果这个值还在 redis 就不做操作,返回当前 redis 总计多少个 key 。
如果这个值不在 redis 里,就再丢一个唯一值到客户端,本地新增一个记录,返回 key 总数。
初次访问你网站的时候,下发一个 cookie. 后续 websocket 携带这个 cookie 去访问. 同一个 cookie 的直接 close 掉. 不带 cookie 的也 close 掉.
所有用户的这个值都应该是一样的啊,为啥要 ws
直接服务端统计然后直接暴露一个固定的接口轮询不就好了
Client 与 Server 之间可以用 RabbitMQ 来缓和压力,这个在 Spring 中很好的支持,通过 STOMP 协议,客户端也用 sockjs 支持。
设置一个能承受的连接上限, 比如好几十万. 网站最大就显示这么多个数…
超过就直接连接失败
一个端口服务能服务多少用户和服务器本地有多少个端口(也就是你认为的那个常规是 65535 的数值)没关系。
忽略我上面的发言,原来楼主是做压力测试
我认为 ws,做在线是非常好的方案,实时性和性能开销比都不错。
#5 对外的 websocket 服务不是以端口为单位,而是以 URL 路径为单位的,websocket 可以发布于某个域名的某个路径或多个不同的路径下,与其他路径的 URL 页面或服务互不影响
- -我一直以为这个数字是瞎整的(也不算瞎整,就是不需要那么严谨)
websocket 和 http 是占用同一端口的( 80 | 443 ),linux kernel 3.9 引入的 SO_REUSEPORT 的选项,允许多个进程分享同一地址同一端口的 TCP 连接
> wss 统计在线人数,代价还是很低的,一般只是端口不够用
这个说法是错误的,我测试的 端口不够用 是因为客户端会占用本地端口,不是服务端的占用端口~
跨站点劫持楼主已经写了,check origin + 业务层认证
单设备连接数限制这个不太合理,通常应该按照身份限制比较好:既然有业务层认证,每个连接都有身份,如果不允许同一个身份多个连接、认证后就把之前的踢掉,如果允许,那就自己服务节点配置提高、节点数量增加之类的(如果怕统一身份的连接散到多个服务节点上,可以加个网关层,网关层按身份指定到实际的业务节点、由业务节点进行踢下线处理)。如果实在是想按照设备限制,那策略里使用身份的地方就改用 ip 或者你的算法能够生成的设备 id
统计人数通常不需要太精确,即使是多个服务节点,每个节点定时(比如 5s )更新自己节点在线数到 redis/sql 都可以、更新多节点在线数量总和就可以了,实时在线本来就是不停跳动的,精确的意义不大。如果实在要求精确,自己再写个服务进行统计、并且同步到所有节点,或者直接用 redis incr 之类的,每秒查询、更新,但是都没法保证百分百精确,实时的本来就是跳动的数据,即使是股票 K 线的蜡烛图也都是按时间段的起值、止值、最高值、最低值进行统计的
BTW,我这有个 ARPC 的 golang 框架提供了 websocket 聊天的简单示例
https://github.com/lesismal/arpc/tree/master/examples/webchat
另外 ARPC 支持发布订阅,如果想自己实现个管理服务器进行多个服务节点的在线数统计,管理服务器接收上报人数、然后把多节点的业务服在线总和发布就行了
想简单处理的话轮询写、读 redis 就好了
节点数不多、redis 的话,每个节点每秒 hset 、hmget 下就行了,没啥压力,而且实时性也足够
另外,怕连接数过多的话,单节点配置好最大在线数,新连接进来的时候判断下、超过了就拒绝掉,这个可以在网关或者业务节点的 upgrader checkorigion 里做,更好点的方式是自己 wrap 下 net.Listener,serve(listener),Accept 的地方直接做
端口数量通常不是问题,文件描述符上限设置个 10w 、100w,其他的几个内核参数设置合理就行,只要你硬件配置足够。不过还真有的站点设置的不合理,golang 中国报错文件打开数量过多我就遇到过好多次。socket 是 4 元组,单 IP 自己过来的最大端口 65535,不代表服务器对所有 IP 加起来只能 65535,而且单 IP 除非故意写 bug 或者攻击、否则也不至于有这么多,而且这些 CDN 、防火墙那里就能挡,还轮不到业务层来处理这个(并且业务曾代码也没有这个能力处理)
如果是觉得某个设备只要超过两三个连接就算过多,那就看我上一楼说过,限制机制自己订制下就好
针对Golang中WebSocket的防爆(防止拒绝服务攻击DoS等)和防跨站(防止跨站脚本攻击XSS、跨站请求伪造CSRF等)问题,以下是一些专业的建议:
一、防爆措施
- 限制连接数:通过限制每个IP地址或用户的并发连接数,防止单个用户占用过多的服务器资源。
- 建立连接时验证:在建立WebSocket连接时,对客户端进行身份验证,确保其是合法的用户。
二、防跨站措施
-
防止XSS攻击:
- 输入验证和过滤:接收客户端数据时,使用Golang的验证函数和正则表达式检查数据的合法性。
- 输出编码:向客户端发送数据时,对输出进行适当的编码,防止恶意脚本执行。
-
防止CSRF攻击:
- 添加CSRF令牌:为每个用户生成随机的CSRF令牌,存储于会话中,每次WebSocket请求时验证令牌。
- 设置SameSite Cookie属性:将Cookie的SameSite属性设为Strict或Lax,增强对CSRF攻击的防御。
综上所述,通过结合上述防爆和防跨站措施,可以显著提升Golang WebSocket应用的安全性和可靠性。在开发过程中,务必重视这些安全问题,并实施相应的防御机制。