传统的实现即时通信的方式
ajax轮询
ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) —- loop
long poll
long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现:
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
小结:
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
长连接
在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。
优点:消息即时到达,不发无用请求;管理起来也相对方便。
缺点:服务器维护一个长连接会增加开销,当客户端越来越多的时候,server压力大!
实例:Gmail聊天
(1).基于http协议的长连接
在HTTP1.0和HTTP1.1协议中都有对长连接的支持。其中HTTP1.0需要在request中增加”Connection: keep-alive“ header才能够支持,而HTTP1.1默认支持.
http1.0请求与服务端的交互过程:
a)客户端发出带有包含一个header:”Connection: keep-alive“的请求
b)服务端接收到这个请求后,根据http1.0和”Connection: keep-alive“判断出这是一个长连接,就会在response的header中也增加”Connection: keep-alive“,同是不会关闭已建立的tcp连接.
c)客户端收到服务端的response后,发现其中包含”Connection: keep-alive“,就认为是一个长连接,不关闭这个连接。并用该连接再发送request.转到a)
(2).http1.1请求与服务端的交互过程:
a)客户端发出http1.1的请求
b)服务端收到http1.1后就认为这是一个长连接,会在返回的response设置Connection: keep-alive,同是不会关闭已建立的连接.
c)客户端收到服务端的response后,发现其中包含”Connection: keep-alive“,就认为是一个长连接,不关闭这个连接。并用该连接再发送request.转到a)
基于http协议的长连接减少了请求,减少了建立连接的时间,但是每次交互都是由客户端发起的,客户端发送消息,服务端才能返回客户端消息.因为客户端也不知道服务端什么时候会把结果准备好,所以客户端的很多请求是多余的,仅是维持一个心跳,浪费了带宽.
一、什么是websocket?
WebSocket本质上是一种计算机网络应用层的协议,用来弥补http协议在持久通信能力上的不足。
我们知道http协议本身是无状态协议,每一个新的http请求,只能通过客户端主动发起,通过 建立连接–>传输数据–>断开连接 的方式来传输数据,传送完连接就断开了,也就是这次http请求已经完全结束了(虽然http1.1增加了keep-alive请求头可以通过一条通道请求多次,但本质上还是一样的)。
并且服务器是不能主动给客户端发送数据的(因为之前的请求得到响应后连接就断开了,之后服务器根本不知道谁请求过),客户端也不会知道之前请求的任何信息。
所以说,http协议本身是没有持久通信能力的,但是我们在实际的应用中,是很需要这种能力的,所以WebSocket协议由此而生,于2011年被IETF定为标准RFC6455,并被RFC7936所补充规范。
并且在HTML5标准中增加了有关WebSocket协议的相关api,所以只要实现了HTML5标准的客户端,就可以与支持WebSocket协议的服务器进行全双工的持久通信了。
ps:这里的持久通信能力指的是协议本身的能力,我们当然可以通过编程的方式实现这种功能,比如轮询的方式,但谁不喜欢原生就支持呢?
ps2:计算机网络里还有socket关键字,这里的socket指的是运输层协议的某一端,泛指某个应用程序。
ps3: unix编程里还有一个socket接口,这里的译名是套接字,泛指应用层协议的端口号。
WebSocket 的特点:
建立在 TCP 协议之上,服务器端的实现比较容易。
与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
数据格式比较轻量,性能开销小,通信高效。
可以发送文本,也可以发送二进制数据。
没有同源限制,客户端可以与任意服务器通信。
协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
websocket协议的应用场景
· 即时聊天通信
· 多玩家游戏
· 在线协同编辑/编辑
· 实时数据流的拉取与推送
· 体育/游戏实况
· 实时地图位置
二、websocket协议的原理
与http协议一样,WebSocket协议也需要通过已建立的TCP连接来传输数据。具体实现上是通过http协议建立通道,然后在此基础上用真正的WebSocket协议进行通信,所以WebSocket协议和http协议是有一定的交叉关系的。
下面是WebSocket协议请求头:
其中请求头中重要的字段:
Connection:Upgrade
Upgrade:websocket
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:mg8LvEqrB2vLpyCNnCJV3Q==
Sec-WebSocket-Version:13
-
Connection和Upgrade字段告诉服务器,客户端发起的是WebSocket协议请求
-
Sec-WebSocket-Extensions表示客户端想要表达的协议级的扩展
-
Sec-WebSocket-Key是一个Base64编码值,由浏览器随机生成
-
Sec-WebSocket-Version表明客户端所使用的协议版本
得到的响应头中重要的字段:
Connection:Upgrade
Upgrade:websocket
Sec-WebSocket-Accept:AYtwtwampsFjE0lu3kFQrmOCzLQ=
-
Connection和Upgrade字段与请求头中的作用相同
-
Sec-WebSocket-Accept表明服务器接受了客户端的请求
Status Code:101 Switching Protocols
并且http请求完成后响应的状态码为101,表示切换了协议,说明WebSocket协议通过http协议来建立运输层的TCP连接,之后便与http协议无关了。
三、websocket漏洞测试
1、操纵 WebSocket 消息以利用漏洞
基于输入的漏洞都可以通过篡改 WebSocket 消息的内容来发现和利用
例如,假设一个聊天应用程序使用 WebSockets 在浏览器和服务器之间发送聊天消息。当用户键入聊天消息时,会向服务器发送如下 WebSocket 消息:
{“message”:“Hello Carlos”}
消息的内容被传输(再次通过 WebSockets)给另一个聊天用户,并在用户的浏览器中呈现如下:
<td>Hello Carlos</td>
在这种情况下,如果没有其他输入处理或防御在起作用,攻击者可以通过提交以下 WebSocket 消息来执行概念验证 XSS 攻击:
{"message":"<img src=1 onerror='alert(1)'>"}
测试方法:寻找websocket中用户输入的地方,尝试修改输入内容为非法字符看是否能够成功;如果输入内容可以在页面或响应中有回显,此时可以尝试输入payload测试是否存在XSS或SQL注入。
2、操纵 WebSocket 握手以利用漏洞
一些 WebSockets 漏洞只能通过操纵 WebSocket 握手来发现和利用。这些漏洞往往涉及设计缺陷,例如:
错误地信任 HTTP 标头以执行安全决策,例如X-Forwarded-For标头。
会话处理机制的缺陷,因为处理 WebSocket 消息的会话上下文通常由握手消息的会话上下文决定。
应用程序使用的自定义 HTTP 标头引入的攻击面。
例如:当你修改websocket消息进行攻击后发现连接被终止并且你的IP已被禁止,可以尝试添加以下标头到握手请求中以欺骗IP地址:X-Forwarded-For: 1.1.1.1
3、跨站websocket劫持漏洞
PS:
socket.io,一个很流行的JavaScript WebSockets库。
https://www.freebuf.com/articles/web/189994.html
原文:https://www.blackhillsinfosec.com/how-to-hack-websockets-and-socket-io/
参考链接:
https://www.zhihu.com/question/20215561
https://zhuanlan.zhihu.com/p/32845970
https://www.cnblogs.com/cangqinglang/p/8331120.html
https://www.freebuf.com/articles/web/189994.html