请求头配置正确时WebSocket连接仍返回403 Forbidden问题咨询
Socket.IO WebSocket连接持续返回403 Forbidden(Cloudflare环境)排查方案
问题现象
尝试连接地址 ws://rustypot.com/socket.io/?EIO=4&transport=websocket 时持续返回403 Forbidden,使用NodeJS后端、Postman发起连接均复现该问题,已校验常规请求头符合规范,握手阶段响应如下:
Error: Unexpected server response: 403 Handshake Details Request URL: https://rustypot.com/socket.io/?EIO=4&transport=websocket Request Method: GET Status Code: 403 Forbidden Request Headers Sec-WebSocket-Version: 13 Sec-WebSocket-Key: HeibSZt/sW4ivlyCkdN87g== Connection: Upgrade Upgrade: websocket Origin: https://rustypot.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Host: rustypot.com Response Headers Date: Sun, 26 Jun 2022 14:48:11 GMT Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: close CF-Chl-Bypass: 1 Permissions-Policy: accelerometer=(),autoplay=(),camera=(),clipboard-read=(),clipboard-write=(),fullscreen=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=() Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Expires: Thu, 01 Jan 1970 00:00:01 GMT X-Frame-Options: SAMEORIGIN Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" Server: cloudflare CF-RAY: 7216be129b0484b0-LED
同环境下使用Chrome扩展发起连接可正常完成握手。
根因判定
从响应头的Server: cloudflare、CF-Chl-Bypass: 1字段可直接确认,拦截来自Cloudflare边缘安全策略,与Socket.IO服务本身配置无关:
- NodeJS后端、Postman发起的请求属于非真实浏览器环境流量,无法自动通过Cloudflare的人机校验、浏览器完整性校验,会被直接标记为可疑流量返回403
- Chrome扩展发起请求时,默认继承当前浏览器已通过Cloudflare校验的合法会话状态,因此可以正常完成握手。
排查步骤
- 校验Cloudflare规则配置(若你持有站点管理权限)
登录Cloudflare控制台查看对应站点的安全规则:- 检查全局安全等级,若设置为「高」或「Under Attack Mode」,非浏览器的WebSocket请求会被默认拦截
- 检查WAF规则、速率限制规则,确认是否存在针对
/socket.io/路径的拦截策略 - 检查Browser Integrity Check(浏览器完整性检查)开关,该功能会主动识别非浏览器客户端的TLS、HTTP指纹并拦截
- 对比合法请求的关键差异
抓取Chrome扩展正常连接时的完整请求头,核心差异是测试请求缺失Cloudflare校验通过后下发的两个Cookie:cf_clearance(人机挑战通过凭证)、__cf_bm(合法浏览器流量标识),这两个值是Cloudflare放行请求的核心依据,仅伪装User-Agent、Origin等常规头无法通过校验。 - 排除Socket.IO本身配置问题
你使用的EIO=4参数对应Socket.IO v4协议,且Chrome扩展可正常连通,说明服务端跨域配置、版本适配、路径配置均无问题,不需要在这部分耗费排查精力。
可行解决方案
你持有站点/Cloudflare管理权限时
- 为
/socket.io/路径配置WAF例外规则,允许可信来源IP、或携带有效服务端鉴权Token的请求跳过Cloudflare安全校验 - 单独为WebSocket服务分配二级域名,关闭该域名的高等级安全防护、浏览器完整性检查,在Socket.IO层独立实现连接鉴权(如连接时校验自定义Token),避免边缘防护影响长连接可用性
- 若需要保留安全防护,可配置规则仅对普通页面GET请求启用人机挑战,对WebSocket升级请求放行并通过后端逻辑做流量校验。
你无站点管理权限,仅作为客户端接入时
- 不要直接使用原生ws客户端、Postman发起裸连接,先通过无头浏览器(Playwright/Puppeteer)访问目标站点,等待Cloudflare挑战自动完成后,从浏览器上下文提取有效
cf_clearance、__cf_bmCookie,搭配与无头浏览器完全一致的User-Agent、请求头发起WebSocket握手,可正常通过校验 - 若需要长期稳定连接,需定期刷新Cookie(Cloudflare下发的Cookie有效期通常为1-2小时),可搭配自动挑战求解组件实现凭证的自动更新
- 注意:仅在HTTP层伪装请求头无法绕过最新的Cloudflare防护,其校验逻辑覆盖TLS指纹、TCP栈特征、请求行为序列等多维度信息,纯协议层伪装的请求会被持续拦截。
内容的提问来源于stack exchange,提问作者My Man
相关产品推荐
相关产品推荐

