websocket之四:WebSocket 的鉴权授权方案

本文介绍了WebSocket的鉴权授权方法,包括在连接建立时检查HTTP请求头信息,连接过程中验证授权,以及通过颁发ticket进行授权。此外,还讨论了防止重放攻击的安全措施,并提供了基于node.js的ws库的代码实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引子

WebSocket 是个好东西,为我们提供了便捷且实时的通讯能力。然而,对于 WebSocket 客户端的鉴权,协议的 RFC 是这么说的:

This protocol doesn’t prescribe any particular way that servers can
authenticate clients during the WebSocket handshake. The WebSocket
server can use any client authentication mechanism available to a
generic HTTP server, such as cookies, HTTP authentication, or TLS
authentication.

也就是说,鉴权这个事,得自己动手

协议原理

WebSocket 是独立的、创建在 TCP 上的协议。

为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”。

实现步骤:

1. 发起请求的浏览器端,发出协商报文:

2. 服务器端响应101状态码(即切换到socket通讯方式),其报文:

3. 协议切换完成,双方使用Socket通讯

直观的协商及通讯过程:

方案

通过对协议实现的解读可知:在 HTTP 切换到 Socket 之前,没有什么好的机会进行鉴权,因为在这个时间节点,报文(或者说请求的Headers)必须遵守协议规范。但这不妨碍我们在协议切换完成后,进行鉴权授权:

鉴权
  1. 在连接建立时,检查连接的HTTP请求头信息(比如cookies中关于用户的身份信息)
  2. 在每次接收到消息时,检查连接是否已授权过,及授权是否过期
  3. 以上两点,只要答案为否,则服务端主动关闭socket连接
授权

服务端在连接建立时,颁发一个ticket给peer端,这个ticket可以包含但不限于:

  • peer端的uniqueId(可以是ip,userid,deviceid…任一种具备唯一性的键)
  • 过期时间的timestamp
  • token:由以上信息生成的哈希值,最好能加盐
安全性的补充说明

有朋友问:这一套机制如何防范重放攻击,私以为可以从以下几点出发:

  • 可以用这里提到的expires,保证过期,如果你愿意,甚至可以每次下发消息时都发送一个新的Ticket,只要上传消息对不上这个Ticket,就断开,这样非Original Peer是没法重放的
  • 可以结合redis,实现 ratelimit,防止高频刷接口,这个可以参考 express-rate-limit,原理很简单,不展开
  • 为防止中间人,最好使用wss(TLS)
代码实现

WebSocket连接处理,基于 node.js 的 ws 实现:

### WebSocket 后端认证的最佳实践 WebSocket 是一种全双工通信协议,允许客户端和服务端之间保持持久连接并实时交换消息。然而,在实际应用场景中,为了保护敏感数据和防止未授权访问,对 WebSocket 的后端进行认证是非常必要的。 以下是基于现有引用内容以及专业知识总结的 WebSocket 后端认证最佳实践: #### 1. 使用 Token 进行身份验证 Token 是目前最常用的机制之一。可以通过在握手阶段传递 Token 来完成用户的合法性校验。具体实现如下: - 客户端在建立 WebSocket 握手请求时,将携带的身份凭证(如 JWT 或 OAuth Token)作为 HTTP 请求头的一部分发送给服务器。 - 在 `beforeHandshake` 方法中解析该 Token 并验证其有效性[^3]。 ```java @Override public void beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; String token = servletRequest.getServletRequest().getParameter("token"); // 验证 Token 是否有效 boolean isValid = validateToken(token); if (!isValid) { throw new RuntimeException("Invalid or missing token."); } } } ``` #### 2. 设置特定路径为匿名访问 对于某些不需要严格限控制的功能模块,可以选择将其设置为匿名访问。例如 Ruoyi Vue 分离版的做法就是在 SecurityConfig 中配置 `/websocket/**` 地址为匿名访问[^2]。这种方式适用于公开接口或者调试环境中的 WebSocket 测试工具[^1]。 #### 3. 单点登录支持 如果项目涉及多系统间的协同工作,则可能需要用到 SSO(Single Sign-On)。此时可以在 admin 模块下新增 LoginSsoController 控制器来处理跨域单点登录逻辑[^4]。这样即使用户切换不同子系统也能维持一致性的会话状态而无需重复登录操作。 #### 4. 数据加密传输保障安全性 除了基本的外还应考虑采用 SSL/TLS 加密整个通讯过程以进一步提升系统的安全等级。确保所有的 WebSocket 连接都是通过 wss:// 方式发起从而避免中间人攻击等问题发生。 --- ### 示例代码片段展示如何集成上述要点至 Spring Boot 应用程序当中: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new HandshakeInterceptor()); } } @Component public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { private final JwtUtil jwtUtil; public HandshakeInterceptor(JwtUtil jwtUtil){ this.jwtUtil=jwtUtil; } @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { if(request instanceof ServletServerHttpRequest){ ServletServerHttpRequest serverHttpRequest=(ServletServerHttpRequest)request; MultiValueMap<String,String> params=serverHttpRequest.getServletRequest().getParameterMap(); List<String> tokens=params.getOrDefault("access_token",Collections.emptyList()); if(tokens.isEmpty()){ return false;//拒绝无令牌的请求 }else{ try{ claimsSet=jwtUtil.parseJwt(tokens.get(0)); attributes.put("claims_set",claimsSet); }catch(Exception e){ return false; //非法令牌也直接返回false } } } return super.beforeHandshake(request,response,wsHandler,attributes); } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值