WebSocket协议分析及实现

澳门新葡亰赌995577 2

WebSockets是一个能够给单TCP连接提供全双工信道的HTML5特性。它的持续性连接功能,使得构建B/S模式的实时应用成为可能。Websockets常常用在那些带有聊天功能的WEB应用上。

1.概述

Webscoket是Web浏览器和服务器之间的一种全双工通信协议,其中WebSocket协议由IETF定为标准,WebSocket
API由W3C定为标准。一旦Web客户端与服务器建立起连接,之后的全部数据通信都通过这个连接进行。通信过程中,可互相发送JSON、XML、HTML或图片等任意格式的数据。
WS(WebSocket)与HTTP协议相比,相同点主要有:

  • 都是基于TCP的应用层协议;
  • 都使用Request/Response模型进行连接的建立;
  • 在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码;
  • 都可以在网络中传输数据。
    不同之处在于:
  • 澳门新葡亰赌995577,WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用;
  • WS的连接不能通过中间人来转发,它必须是一个直接连接;
  • WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据;
  • WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息;
  • WS的数据帧有序。
    WS整个通信过程如下图所示:
WebSocket通信原理图

下面的图片就非常贴切地阐释了一个APT攻击用到的websockets:

2.主要特点

推送功能:服务器可以直接向客户端推送消息。之前采取的方式都是客户端主动向服务器发送请求,这样比较耗费资源。
减少通信量:只要第一次建立连接,就可以一直进行通信,不像HTTP协议,需要频繁的建立请求,一问一答的模式。此外,Websocket的头部数据也比较少。

澳门新葡亰赌995577 1

3.握手协议

websocket是基于TCP的一个应用协议,与HTTP协议的关联之处在于websocket的握手数据被HTTP服务器当作HTTP包来处理,主要通过Update
request HTTP包建立起连接,之后的通信全部使用websocket自己的协议。
请求:TCP连接建立后,客户端发送websocket的握手请求,请求报文头部如下:

GET /chat HTTP/1.1
Host: server.example.com
**Upgrade: websocket**
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: https://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
  • 第一行为为请求的方法,类型必须为GET,协议版本号必须大于1.1
  • Upgrade字段必须包含,值为websocket
  • Connection字段必须包含,值为Upgrade
  • Sec-WebSocket-Key字段必须包含 ,记录着握手过程中必不可少的键值。
  • Sec-WebSocket-Protocol字段必须包含 ,记录着使用的子协议
  • Origin:作安全使用,防止跨站攻击,浏览器一般会使用这个来标识原始域

响应:服务器接收到请求后,返回状态码为101 Switching Protocols
的响应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
  • Sec-WebSocket-Accept字段是由握手请求中的Sec-WebSocket-Key字段生层的。
    握手成功后,通信不再使用HTTP协议,而采用WebSocket独立的数据帧。如下图所示,为协议帧格式:
image



图中各名词含义如下

FIN:1bit,是否为信息的最后一帧
RSV 1-3:1bit,备用,默认为0
opcode:4bit,帧类型
                         0x00 连续消息分片
                         0x01 文本消息分片
                         0x02 二进制消息分片
                         0x03 ~ 0x07 为将来的非控制消息片段保留测操作吗
                         0x08 连接关闭
                         0x09 心跳检查 ping
                         0x0a 心跳检查pong
                         0x0b ~ 0x0f 为将来的控制消息片段保留的操作码
MASK:定义传输的数据是否有加掩码,如果设置为1,掩码键必须放在masking-key区域,客户端发送给服务端的所有消息,此位的值都是1
payload length:7bit,传输数据长度,以字节为单位。当这个长度为7bit数字为126时,紧随其后的2个字节也是表示数据长度。当这个长度为7bit数字为127时,紧随其后的8个字节也是表示数据长度。
Masking-key:0或者4bit,只有当MASK设置为1时才有效。
Playload data:负载数据,为扩展数据和应用数据之和,Extension data + Application data。
Extension data:扩展数据,如果客户端和服务端没有特殊的约定,那么扩展数据长度始终为0
Application data:应用数据,

以上就是WebSocket协议帧的分析

科普:

同源策略(Same origin
policy):同源是指,域名,协议,端口相同,即浏览器会检查同一浏览器的不同选项卡中,来源相同的脚本才能跨选项卡执行。

Origin字段:浏览器在发送POST请求的时候可能会加上一个Origin字段,这个Origin字段主要是用来标识出最初请求是从哪里发起的。如果浏览器不能确定源在哪里,那么在发送的请求里面Origin字段的值就为空。

IronWASP:某开源WEB测试平台,用户可以自定义安全扫描,并且可以自己用python/ruby来定义插件系统。相关介绍见:

ZAP(Zed Attack
Proxy):是一款集成各种工具的渗透测试框架,可以发现在WEB应用程序中的漏洞,相关介绍见:

4.实现

WebSocket的安全评估

最近,我们对一个拥有复杂菜单选项和功能的WEB应用做了安全评估。该应用中大部分操作都用到了web-sockets,这意味着其大多数行为都不会记录到http代理日志上。

首先,我们打开主页后,网站会加载一个带有JS脚本和CSS文件的静态网页。此后,整个通信交互会转为Websockets模式,浏览器和服务端之间会建立websocket连接,从而加载网站里所有可见的HTML资源。点击链接或者提交Form表单时,浏览器会向服务端发送一些WebSocket消息。服务器处理了这些消息后,会通过WebSocket进行反馈,而后客户端浏览器会展示新的HTML内容。

这时当websocket消息在进行交互时,通信数量是非常巨大的。每隔一秒它们之间会有心跳探测包的交互。然而现有的工具达不到我的要求,我不得不给IronWASP添加了一个Websocket消息分析装置和一个WebSocket客户端,这样它才能识别Websocket从而尝试fuzz其漏洞。你可以在在这里了解下相关知识。

在测试这个应用时,我发现它存在WebSocket跨站劫持(Cross-Site WebSocket
Hijacking)漏洞(由christian
schneider首创)。当然,我会在给大家介绍测试方法之前,解释下这个漏洞的影响。在测试相关Websockets应用之前,我们需要先做下准备。

客户端

// websocket.js
+function( window ){
  // check whether your browser surpport the WebSocket Protocal
  if ( 'WebSocket' in window ) {
    var url = 'ws://127.0.0.1:8080';
    var ws = new WebSocket(url);
    var msgRecieved;

    ws.onopen = function () {
      console.log('Connected to websocket server ...');
    };

    ws.onmessage = function(e){
      msg = e.data;
      console.log('Message from server:' + e.data);
    };

    ws.onclose = function(e){
      console.log('Disconnected');
    }

    // send message to server
    ws.send('message from client');

  } else {
    console.error('Websocket is not supported by your browser!')
  }

}( window );

WebSocket跨站劫持漏洞实验准备

大家应该明白,同源策略(SOP)不会通过浏览器在websockets上强制执行(同一浏览器下,受SSL保护的页面,不会让非SSL的WebSocket通过),我们测试的应用采用了http
cookie作为session认证,WebSocket通过浏览器发送的消息不会有Session
ID或是随机参数。

这样一来,如果某用户登录了带有漏洞的WEB应用,然后在同一浏览器还打开了
ID的请求包。于是,这个由攻击者网站建立的WebSocket连接会和应用本身有相同的权限。

由于整个应用都是以websockets为基础运行的,劫持了WebSocket就相当于劫持了用户的session。所以这个漏洞在本质上和存储型跨站脚本漏洞是一样的。

如果你认为这就很糟了,那当你听到某些情况下WebSocket跨站脚本,甚至可以在用户系统上实现远程代码执行的时候,会不会更惊讶呢?事见IPython
Notebook的案例。

测试之前,你首先要做的就是确认该应用是否存在WebSockets。幸运的是,做这个非常简单,你只需要知道以下三点:

1.WebSocket的URL连接一般是以ws://或者wss://开头的。

2.需要检测建立连接的Origin头,该网页可能是通过Origin字段建立的WebSocket链接。

3.浏览器和服务端之间发送的消息中,我们可以从中检查出普通WebSocket连接的特征。

下面这张图会给你展示:如何通过IronWASP日志得到Origin字段的值和WebSocket的URL值。

澳门新葡亰赌995577 2

一旦你得到这些信息,你可以使用一些特殊方法,对跨站WebSocket劫持漏洞进行检测。我在这里例举三个简单的例子:

服务端

采用NodeJS+socket.io实现

# 安装模块
npm install --save express
npm install --save socket.io

服务端代码:

var app= require('express')()
var http = require('http').Server(app)
var io= require('socket.io').(http)

app.get('/', function(req, res){
  res.send('<center><h1>WebSocket Test</h1></center>')
})

io.on('connection', function(socket){
    console.log('There is a client connected!');

    socket.on('disconnect', function(){
    console.log('There is a client disconnected')
    socket.on('message', function(msg){
      io.emit('message', msg)
    })

  })

http.listen(8080, function(){
  console.log('listening on *:8080')
})

})

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图