websocket

 

websocket: 流程

ws 请求
sec-WebSocket-key: 前端传过来的,会变
magic_string: #固定值
加密后返回,建立连接 (服务端加密)

客户端发送的消息,服务端解密后查看
服务端发送加密的信息


解密:
与位运算 最大127
前端传过来(数据长度,解密所需字符串,数据)

加密:后台加密后传过去数据

 

import socket, base64, hashlib
import websocket_jiemi
import websocket_jiami

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 9527))
sock.listen(5)
# 获取客户端socket对象
conn, address = sock.accept() # 阻塞

# 获取客户端的【握手】信息
data = conn.recv(2048)
print(data)


"""
b'
GET / HTTP/1.1\r\n
Host: 127.0.0.1:9527\r\n
Connection: Upgrade\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n
Upgrade: websocket\r\n
Origin: http://localhost:63342\r\n
Sec-WebSocket-Version: 13\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n
Sec-WebSocket-Key: tPWfDfGthkhhqfY4ZdT1yQ==\r\n
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n'
"""
#
# # magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11 #固定值
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
#
#
def get_headers(data):
    header_dict = {}
    header_str = data.decode("utf8")
    for i in header_str.split("\r\n"):
        if str(i).startswith("Sec-WebSocket-Key"):
            header_dict["Sec-WebSocket-Key"] = i.split(":")[1].strip()

    return header_dict

headers = get_headers(data)  # 提取请求头信息 Sec-WebSocket-Key

# # 对请求头中的sec-websocket-key进行加密

#
value = headers['Sec-WebSocket-Key'] + magic_string  # jtl/vockZ8GRyadFVeiUTA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
print(value)
sha1_value = hashlib.sha1(value.encode('utf-8')).digest() #字节
print("sha1_value",sha1_value)
ac = base64.b64encode(sha1_value) #字节
print("ac",ac)
# ac  = base64(sha1(sec+magic))
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
               "Upgrade:websocket\r\n" \
               "Connection: Upgrade\r\n" \
               "Sec-WebSocket-Accept: %s\r\n" \
               "WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n"

response_str = response_tpl % (ac.decode('utf-8'))
# 响应【握手加密后的】信息
conn.send(response_str.encode("utf8"))

while True:
    msg = conn.recv(8096)
    msg = websocket_jiemi.websocket_jiema(msg)

    # conn.send("123123123123".encode("utf8"))
    send_str = websocket_jiami.jiami("hello".encode("utf8"))
    print(send_str)
    conn.send(send_str)
websocket_hand.py
# b'\x81\x83\xceH\xb6\x85\xffz\x85'

hashstr = b'\x81\x85$\xcb>\x14L\xaeRxK'
# b'\x81
# \x85$
# \xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L
# \xaeRxK\xcb>\x14L\xaeRxK
# \xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK'

# 将第二个字节也就是 \x83 第9-16位 进行与127进行位运算

def websocket_jiema(hashstr):
    print(hashstr[1])
    payload = hashstr[1] & 127
    print(payload)  #位运算后的结果

    if payload == 127:
        extend_payload_len = hashstr[2:10] # 834473503 数据长度
        mask = hashstr[10:14] #解密所需字符串
        decoded = hashstr[14:] #数据
    # 当位运算结果等于127时,则第3-10个字节为数据长度
    # 第11-14字节为mask 解密所需字符串
    # 则数据为第15字节至结尾
    #

    # b'\x81
    # \x85$    126
    # \xcb>\x14L 120
    # \xaeRxK\xcb>\x14L\xaeRxK
    # \xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK \xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK\xcb>\x14L\xaeRxK'


    if payload == 126:
        extend_payload_len = hashstr[2:4]
        mask = hashstr[4:8]
        decoded = hashstr[8:]
    # 当位运算结果等于126时,则第3-4个字节为数据长度
    # 第5-8字节为mask 解密所需字符串
    # 则数据为第9字节至结尾
    #
    #   b'\x81
    # \x85$ 5 len数据长度
    # \xcb>\x14L\xaeRxK'

    if payload <= 125:
        extend_payload_len = payload
        mask = hashstr[2:6]
        decoded = hashstr[6:]  # 5

    # 当位运算结果小于等于125时,则这个数字就是数据的长度
    # 第3-6字节为mask 解密所需字符串
    # 则数据为第7字节至结尾
    #
    str_byte = bytearray() #字节的列表,里面存放传过来的字节,自动拼成字节串
    #
    for i in range(len(decoded)):
        byte = decoded[i] ^ mask[i % 4] #或运算
        str_byte.append(byte)
    #
    return str_byte.decode("utf8")  #解密运算完后的前端穿过来的信息
websocket_jiemi.py
import struct  #加密使用
# msg_bytes = "哎呀妈呀脑瓜疼".encode("utf8")
def jiami(msg_bytes):
    token = b"\x81"
    length = len(msg_bytes) #发送到客服端的真实数据的字节长度

    # 该模块可以把一个类型,如数字,转成固定长度的bytes
    # struct.pack('i',1111111111111)

    if length < 126:
        token += struct.pack("B", length) # \x85$
    elif length == 126:
        token += struct.pack("!BH", 126, length)
    else:
        token += struct.pack("!BQ", 127, length)

    msg = token + msg_bytes

    return msg #加密后的字节信息
websocket_jiami.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    var ws = new WebSocket("ws://127.0.0.1:9527")
    ws.onmessage = function (data) {
        console.log(data.data)

    }
</script>
</html>
my_socket.html

 

posted @ 2018-10-31 23:03  xujinjin  阅读(160)  评论(0编辑  收藏  举报