前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「IM系列」WebSocket教程:安全授权认证详解和简单实现思路

「IM系列」WebSocket教程:安全授权认证详解和简单实现思路

作者头像
Tinywan
发布2023-12-05 17:38:05
8450
发布2023-12-05 17:38:05
举报
文章被收录于专栏:开源技术小栈开源技术小栈

介绍

场景

近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对websocket的要求也越来越高。从早期对websocket的应用仅限于少部分功能和IM等特殊场景,逐步发展为追求支持高并发,百万、千万级每秒通讯的高可用websocket服务。

相比于 Http 的单项通信方式,WebSocket 可以从服务器向浏览器主动推送消息,这一特性可以帮助我们完成诸如:订单消息推送、IM实时聊天 等一些特定业务。

数据通信

安全问题

WebSocket 本身对 身份认证 并没有提供直接的支持,对客户端的连接默认是 来者不拒

WebSocket作为一种通信协议引入到Web应用中,并不会解决Web应用中存在的安全问题,因此WebSocket应用的安全实现是由开发者或服务端负责。这就要求开发者了解WebSocket应用潜在的安全风险,以及如何做到安全开发规避这些安全问题。

认证

WebSocket 协议没有规定服务器在握手阶段应该如何认证客户端身份。服务器可以采用任何 HTTP 服务器的客户端身份认证机制,如 cookie认证,HTTP 基础认证,TLS 身份认证等。在WebSocket应用认证实现上面临的安全问题和传统的Web应用认证是相同的,如:CVE-2015-0201, Spring框架的Java SockJS客户端生成可预测的会话ID,攻击者可利用该漏洞向其他会话发送消息,CVE-2015-1482, Ansible Tower未对用户身份进行认证,远程攻击者通过websocket连接获取敏感信息。

授权

同认证一样,WebSocket协议没有指定任何授权方式,应用程序中用户资源访问等的授权策略由服务端或开发者实现。WebSocket应用也会存在和传统Web应用相同的安全风险,如:垂直权限提升和水平权限提升。

跨域请求

WebSocket使用基于源的安全模型,在发起WebSocket握手请求时,浏览器会在请求中添加一个名为Origin的HTTP头,Oringin字段表示发起请求的源,以此来防止未经授权的跨站点访问请求。WebSocket 的客户端不仅仅局限于浏览器,因此 WebSocket 规范没有强制规定握手阶段的 Origin 头是必需的,并且WebSocket不受浏览器同源策略的限制。

如果服务端没有针对Origin头部进行验证可能会导致跨站点WebSocket劫持攻击。该漏洞最早在 2013 年被Christian Schneider 发现并公开,Christian 将之命名为跨站点 WebSocket 劫持 (Cross Site WebSocket Hijacking)(CSWSH)。跨站点 WebSocket 劫持危害大,但容易被开发人员忽视。

图片来源:腾讯安全应急响应中心(Tencent Security Response Center)

上图展示了跨站WebSocket劫持的过程,某个用户已经登录了WebSocket应用程序,如果他被诱骗访问了某个恶意网页,而恶意网页中植入了一段js代码,自动发起 WebSocket 握手请求跟目标应用建立 WebSocket 连接。注意到,Origin 和 Sec-WebSocket-Key 都是由浏览器自动生成的,浏览器再次发起请求访问目标服务器会自动带上Cookie 等身份认证参数。

如果服务器端没有检查Origin头,则该请求会成功握手切换到 WebSocket 协议,恶意网页就可以成功绕过身份认证连接到 WebSocket 服务器,进而窃取到服务器端发来的信息,或者发送伪造信息到服务器端篡改服务器端数据。与传统跨站请求伪造(CSRF)攻击相比,CSRF 主要是通过恶意网页悄悄发起数据修改请求,而跨站 WebSocket 伪造攻击不仅可以修改服务器数据,还可以控制整个双向通信通道。也正是因为这个原因,Christian 将这个漏洞命名为劫持(Hijacking),而不是请求伪造(Request Forgery)。

理解了跨站WebSocket劫持攻击的原理和过程,那么如何防范这种攻击呢?处理也比较简单,在服务器端的代码中增加 对Origin头的检查,如果客户端发来的 Origin 信息来自不同域,服务器端可以拒绝该请求。但是仅仅检查 Origin 仍然是不够安全的,恶意网页可以伪造Origin头信息,绕过服务端对Origin头的检查,更完善的解决方案可以借鉴CSRF的解决方案-令牌机制。

授权实现

Origin头的检查

修改配置文件config\plugin\webman\gateway-worker\process.php进程配置文件,修改网关gateway配置onConnect链接配置回调函数。

代码语言:javascript
复制
...
'gateway' => [
        'handler'     => Gateway::class,
        'listen'      => 'websocket://0.0.0.0:8783',
        'count'       => cpu_count(),
        'reloadable'  => false,
        'constructor' => ['config' => [
            'lanIp'           => '127.0.0.1',
            'startPort'       => 2300,
            'pingInterval'    => 25,
            'pingData'        => '{"type":"ping"}',
            'registerAddress' => '127.0.0.1:12306',
            'onConnect' => function ($connection) {
                $connection->onWebSocketConnect = function ($connection, $header) {
                    /** 1. HTTP_ORIGIN 请求头合法性校验 */
                    // var_dump($_SERVER);
                    // 判断连接来源是否合法,不合法就关掉连接(Jmeter压测暂时注释掉)
                    if (!isset($_SERVER['HTTP_ORIGIN'])) {
                        echo ' [x] [ORIGIN合法检测] 未定义HTTP_ORIGIN ', "\n";
                        return $connection->close();
                    }

                    // 判断连接来源是满足条件,不合法就关掉连接
                    // if ($_SERVER['HTTP_ORIGIN'] != 'http://127.0.0.1:8783') {
                    if ($_SERVER['HTTP_ORIGIN'] != 'https://tinywan.com') {
                        echo ' [x] [ORIGIN合法检测] HTTP_ORIGIN不满足条件', "\n";
                        return $connection->close();
                    }
                    echo ' [x] [ORIGIN合法检测] HTTP_ORIGIN验证通过啦!!!', "\n";

                    /** 2. 认证签名校验 */
                    if (!isset($_GET['sign']) || !isset($_GET['ts'])) {
                        echo ' [x] [签名认证] 未携带签名或时间戳参数', "\n";
                        return $connection->close();
                    }

                    // 秘钥可以通过配置文件或者Redis读取
                    $secret = 'Tinywan2024';
                    $serverSign = sha1($_GET['ts'].'|'.$secret);
                    if ($_GET['sign'] != $serverSign) {
                        echo ' [x] [签名认证] 签名认证失败', "\n";
                        return $connection->close();
                    }
                    echo ' [x] [签名认证] 验证通过啦!!!!!!!!', "\n";
                    return true;
                };
            },
        ]]
    ],  
...
非法HTTP_ORIGIN

测试代码

代码语言:javascript
复制
var ws = new WebSocket("ws://127.0.0.1:8783");
ws.onopen = function(evt) {
    ws.send("认证授权和实现思路");认证授权和实现思路
};

客户端

服务端

以上截图可以看出HTTP_ORIGIN请求源不合法,链接被断开链接了

合法 HTTP_ORIGIN

服务端

客户端

签名认证

签名函数get_wss_sign()
代码语言:javascript
复制
/**
 * @desc: 获取websocket连接签名
 * @return array
 * @author Tinywan(ShaoBo Wan)
 */
function get_wss_sign(): array
{
    // ts = 生成链接的时间+有效时间
    $ts = time() + 360;
    $secret = 'Tinywan2024';
    return [
        'sign' => sha1($ts.'|'.$secret),
        'ts' => $ts
    ];
}

客户端连接代码

代码语言:javascript
复制
var ws = new WebSocket("ws://127.0.0.1:8783/?ts=1701697325&sign=3c99ce96521602cf54df53f65cc07b977e33a27c");

ws.onopen = function(evt) {
    console.log("Connection open ...");
    let $_content = {
        "mode": 1,
        "from_username": "Tinywan",
        "to_user_id": "10000",
        "content": "Hi, 开源技术小栈",
    };
    ws.send(JSON.stringify($_content));
};

ws.onmessage = function(evt) {
    console.log( "Received Message: " + evt.data);
};

ws.onclose = function(evt) {
    console.log("Connection closed.");
};
携带签名连接

客户端

服务端

不携带签名或者签名错误

客户端

服务端

上一章节:「IM系列」WebSocket教程:响应格式规范与异常处理

源码

文章相关源码地址:https://github.com/Tinywan/webman-admin

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-12-04,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 安全问题
    • 认证
      • 授权
        • 跨域请求
        • 授权实现
          • Origin头的检查
            • 签名认证
            • 源码
            相关产品与服务
            云数据库 Redis
            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com