WebSocket学习笔记

发布于:2024-05-05 ⋅ 阅读:(31) ⋅ 点赞:(0)

概述

WebSocket是一种网络通信协议,它在2011年被IETF(互联网工程任务组)标准化为RFC 6455。WebSocket协议允许服务器与客户端之间进行全双工通信,即客户端和服务器可以在任何时候发送消息,而不需要像传统的HTTP请求那样等待响应。
WebSocket的主要特点包括:

  1. 全双工通信:客户端和服务器可以在任何时候发送消息,实现了真正的实时通信。
  2. 基于TCP协议:WebSocket在传输层使用TCP协议,保证了数据的可靠传输。
  3. 握手过程:WebSocket连接的建立是通过HTTP协议的升级请求来完成的。客户端发起一个普通的HTTP请求,并在请求头中包含升级到WebSocket的请求。如果服务器支持WebSocket,它会同意升级,并返回一个101 Switching Protocols的响应,之后连接就会使用WebSocket协议。
  4. 轻量级:WebSocket消息格式相对简单,减少了数据传输的开销。
  5. 跨域支持:WebSocket协议支持跨源通信,允许不同域的网页应用进行数据交换。
  6. 持久连接:一旦WebSocket连接建立,它就会保持开放状态,直到客户端或服务器显式地关闭连接。
    WebSocket的应用场景包括但不限于:
  • 实时消息传递:如即时通讯、聊天室等。
  • 实时游戏:多人在线游戏、实时对战游戏等。
  • 实时数据流:如实时股票报价、实时监控系统等。
  • 实时协作工具:如在线白板、文档协作编辑等。
    在现代Web应用中,WebSocket已经成为实现实时互动功能的重要技术之一。随着HTML5的普及,WebSocket得到了广泛的支持,几乎所有的现代浏览器都支持WebSocket协议。

websocket应用示例

这里计划使用FastAPI实现一个WebSocket服务并创建一个Python客户端来接收消息。
安装依赖:

pip install fastapi[all] websockets

服务端程序

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from typing import List

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>WebSocket Example</title>
    </head>
    <body>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var messages = document.getElementById('messages')
                var message = document.createElement('li')
                message.appendChild(document.createTextNode(event.data))
                messages.appendChild(message)
            };
            function sendMessage() {
                var input = document.getElementById('messageInput');
                ws.send(input.value);
                input.value = '';
            }
        </script>
        <input type="text" id="messageInput" placeholder="Type a message...">
        <button οnclick="sendMessage()">Send</button>
        <ul id="messages"></ul>
    </body>
</html>
"""

active_connections: List[WebSocket] = []

@app.get("/")
async def get():
    return HTMLResponse(html)

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    active_connections.append(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            for conn in active_connections:
                if conn == websocket:
                    continue
                await conn.send_text(f"User: {data}")
    except WebSocketDisconnect:
        active_connections.remove(websocket)

客户端程序

import asyncio
import websockets

async def hello():
    uri = "ws://localhost:8000/ws"
    async with websockets.connect(uri) as websocket:
        while True:
            response = await websocket.recv()
            print(f"Received message from server: {response}")

asyncio.get_event_loop().run_until_complete(hello())

运行服务器和客户端
运行FastAPI WebSocket服务:

uvicorn websocket_server:app --reload

在另一个终端窗口中运行Python WebSocket客户端:

python websocket_client.py

客户端现在应该会持续运行,等待并打印出从服务器接收到的消息。如果你打开浏览器并访问http://localhost:8000,你可以在HTML页面中输入消息,这些消息会被服务器广播给所有连接的客户端,包括Python客户端。

WebSocket有哪些常见的安全问题

WebSocket协议虽然为实时通信带来了便利,但也带来了一些安全挑战。以下是一些常见的WebSocket安全问题:

  1. 跨站请求伪造(CSRF):由于WebSocket连接可以在不同域之间建立,攻击者可能会利用WebSocket接口进行CSRF攻击,强迫用户的浏览器在已登录的WebSocket会话中执行非用户意愿的操作。
  2. 跨站脚本包含(XSSI):如果WebSocket服务器返回的数据没有适当的保护措施,攻击者可能会通过XSSI攻击窃取敏感数据。
  3. 数据泄露:WebSocket连接可能会传输敏感数据,如果数据没有加密,或者加密措施不当,攻击者可能会通过中间人攻击(MITM)窃取数据。
  4. 拒绝服务攻击(DoS):由于WebSocket连接是持久的,攻击者可以通过建立大量连接来消耗服务器资源,导致合法用户无法访问服务。
  5. 权限控制不当:如果WebSocket服务器没有正确实施权限控制,攻击者可能会访问或篡改其他用户的会话。
  6. 心跳机制缺失或无效:WebSocket连接可能因为网络问题、服务器问题或客户端问题而断开。如果没有适当的心跳机制来检测连接状态,可能会导致资源泄漏或服务中断。
  7. 协议降级攻击:攻击者可能会尝试将WebSocket连接降级到不安全的HTTP协议,从而进行中间人攻击。
  8. 错误的消息验证:如果服务器没有正确验证客户端发送的消息,可能会导致注入攻击,例如SQL注入、XML注入等。
    为了防范这些安全问题,可以采取以下措施:
  • 使用wss://(WebSocket Secure)代替ws://,确保WebSocket连接使用SSL/TLS加密。
  • 实施适当的认证和授权机制,确保只有合法用户才能访问WebSocket服务。
  • 使用反向代理或API网关来管理WebSocket连接,以便实施更细粒度的安全策略。
  • 对WebSocket消息进行适当的验证和清理,防止注入攻击。
  • 实现心跳机制来监控连接状态,及时释放断开的连接资源。
  • 限制连接数量和消息速率,防止DoS攻击。
  • 对WebSocket服务进行渗透测试和代码审计,及时发现和修复安全漏洞。

网站公告

今日签到

点亮在社区的每一天
去签到