网络数据包分层结构

┌───────────────────────────────┐
│ 以太网头 (Ethernet Header)     │  ← 链路层:源 MAC、目标 MAC
├───────────────────────────────┤
│ IP 头 (IP Header)             │  ← 网络层:源 IP、目标 IP、TTL 等
├───────────────────────────────┤
│ TCP 头 (TCP Header)           │  ← 传输层:源端口、目标端口、序列号
├───────────────────────────────┤
│ HTTP 报文 (HTTP Request/Resp) │  ← 应用层:GET/POST、头部、正文
└───────────────────────────────┘

什么是TCP

在发送应用数据之前,TCP 会用三次握手建立一条可靠的双向通道:

SYN: 客户端提出“我要连你”(同步序列号)。
SYN‑ACK: 服务端回应“我收到了,也准备好了”(同步并确认)。
ACK: 客户端再确认一次“好,开始吧”。

这三步让双方都知道彼此的初始序列号与收发能力,随后才进入数据传输。

TCP 是“面向连接”的,必须先建立连接(SYN → SYN-ACK → ACK)。
UDP 是“无连接”的,直接发数据,不需要建立或关闭连接。

RSA/ECC(非对称加密)

方式 1:你说的 “甲方生成对称密钥,用公钥加密”(以 RSA 为例)

    乙方生成 RSA 密钥对:私钥(自己留)、公钥(发给甲方)。
    甲方要发 “123”:
    自己生成一个对称密钥(比如 AES 密钥 “key123”)。
    用乙方的公钥加密这个对称密钥(“key123” 变成乱码)。
    用 “key123” 加密 “123” 得到密文。
    把 “加密后的对称钥” 和 “加密后的 123” 一起发给乙方。
    乙方收到后:
    用自己的私钥解密 “加密后的的对称密钥”,得到 “key123”。
    用 “key123” 解密密文,得到 “123”。

    方式 2:ECC 常用的 “密钥交换”

    乙方生成 ECC 密钥对:私钥(自己留)、公钥(发给甲方)。
    甲方生成自己的 ECC 临时密钥对:私钥(自己留)、公钥(发给乙方)。
    双方各自计算:
    甲方用自己的私钥 + 乙方的公钥 → 算出对称密钥 “key123”。
    乙方用自己的私钥 + 甲方的公钥 → 也算出 “key123”。
    甲方用 “key123” 加密 “123” 发给乙方,乙方用 “key123” 解密。

    RSA代码分析

    解释

    公钥加密的密文只能用私钥解密,私钥加密的密文也只能用公钥解密

    代码

    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import serialization, hashes
    
    # ------------------------------
    # 1. 生成RSA密钥对(私钥+公钥)
    # ------------------------------
    # 生成2048位RSA私钥(密钥长度推荐2048位及以上,安全性更高)
    # public_exponent=65537:固定公钥指数,是RSA的标准选择
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048
    )
    
    # 从私钥中提取公钥(公钥可公开给其他人)
    public_key = private_key.public_key()
    
    # 序列化密钥为PEM格式(便于存储或传输,如保存到文件)
    private_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,  # 通用的私钥格式
        encryption_algorithm=serialization.NoEncryption()  # 不加密私钥(实际场景可加密)
    )
    
    public_pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo  # 公钥标准格式
    )
    
    print("RSA私钥(PEM格式,需保密):\n", private_pem.decode()[:50] + "...")  # 简化输出
    print("\nRSA公钥(PEM格式,可公开):\n", public_pem.decode()[:50] + "...")
    
    
    # ------------------------------
    # 2. 用公钥加密数据(只能加密小数据,这里加密"123")
    # ------------------------------
    # 要加密的数据(RSA加密长度有限制,2048位密钥约可加密245字节以内的数据)
    data = "123".encode()  # 转为字节流
    
    # 用公钥加密(OAEP是推荐的安全填充方式)
    encrypted_data = public_key.encrypt(
        data,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),  # 掩码生成函数
            algorithm=hashes.SHA256(),  # 哈希算法
            label=None
        )
    )
    
    print("\n加密后的数据(十六进制):", encrypted_data.hex())
    
    
    # ------------------------------
    # 3. 用私钥解密数据
    # ------------------------------
    # 用私钥解密(必须和加密时用相同的填充方式)
    decrypted_data = private_key.decrypt(
        encrypted_data,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    
    print("解密后的数据:", decrypted_data.decode())  # 输出"123"

    PEM 格式的作用:“二进制→文本” 的转换器

    PEM 格式其实是一种 “编码规则”,把二进制密钥转成由A-Z、a-z、0-9、+、/组成的 Base64 字符串,再加上固定的头部(-----BEGIN PUBLIC KEY-----)和尾部(-----END PUBLIC KEY-----),形成可读的文本。

    私钥加密原始数据,公钥解密还原

    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import serialization, hashes
    
    # 1. 生成RSA密钥对
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048
    )
    public_key = private_key.public_key()
    
    # 2. 用私钥直接加密原始数据(注意:RSA私钥加密也有长度限制,2048位约245字节)
    data = "123".encode()  # 要加密的原始数据
    
    # 私钥加密(使用OAEP填充,和公钥加密时保持一致,确保能解密)
    encrypted_by_private = private_key.encrypt(
        data,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    print("私钥加密后的数据(十六进制):", encrypted_by_private.hex())
    
    # 3. 用公钥解密,直接还原原始数据(不做验证,仅解密)
    decrypted_by_public = public_key.decrypt(
        encrypted_by_private,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    print("公钥解密后的数据:", decrypted_by_public.decode())  # 输出"123"

    验证签名是否被篡改

    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import serialization, hashes
    
    # 1. 生成RSA密钥对(和之前相同)
    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048
    )
    public_key = private_key.public_key()
    
    # 2. 用私钥加密数据(注意:这里的“加密”更偏向“签名”逻辑)
    data = "123".encode()
    
    # 私钥加密(使用PSS填充,适合签名场景;也可继续用OAEP,但PSS更推荐用于签名)
    encrypted_by_private = private_key.sign(
        data,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    
    print("私钥加密(签名)后的数据(十六进制):", encrypted_by_private.hex())
    
    # 3. 用公钥解密(验证签名)
    try:
        # 公钥解密密(验证签名):如果成功数据是否由对应私钥加密(即签名)
        public_key.verify(
            encrypted_by_private,  # 私钥加密后的结果(签名)
            data,                  # 原始数据
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        print("公钥解密(验证)成功:数据确实由对应应私钥加密,且未被篡改")
        print("原始数据:", data.decode())
    except:
        print("公钥解密(验证)失败:数据被篡改或不是对应应私钥加密")

    AES(对称加密)(会话密钥)

    会话密钥的核心属性:基本是对称密钥

    对称密钥的特点是加密、解密用同一把密钥,运算速度快,适合加密大量传输数据。
    会话密钥的设计目的就是高效加密通信数据,所以几乎都采用对称密钥(如 AES 算法)。
    少数特殊场景可能用非对称密钥做会话密钥,但会导致通信效率极低,极少实际应用。

    双方获取会话密钥的核心方式

    甲方先向乙方发送自己的证书(含甲方公钥),乙方通过 CA 签名验证证书合法性。
    乙方生成随机的会话密钥,用甲方公钥加密后发给甲方。
    甲方用自己的私钥解密,双方就同时拥有了相同的会话密钥。

    生成AES的逻辑

    IV(初始化向量)的作用一句话说透:让相同明文 + 相同密钥,每次加密都得到不同密文,防止被破解,随机生成就是为了最大化这个效果。

    IV 的核心作用:给 “洗牌” 定一个 “随机起始位置”

      没有 IV 时:
      你每次加密 “123”(相同明文),用同一把 AES 密钥(相同规则),“洗牌” 的第一步(替换、移位)起始位置都一样。
      结果就是:每次加密后的密文都完全相同 —— 黑客只要看到 “某串乱码 = 123”,下次再碰到这串乱码,直接就知道是 123,一破解一个准。


      有 IV 时:
      IV 就像洗牌前的 “随机起点”,比如第一次让你从第 3 格开始换值,第二次从第 7 格开始,第三次从第 12 格开始。
      哪怕明文和密钥都没变,因为 “起始位置” 随机,最终的洗牌结果(密文)也完全不同,黑客没法通过 “密文重复” 猜明文。

      IV 不用保密,只需要 “每次不同”

      IV 的作用是 “定起始位置”,不是 “加密密钥”,所以可以和密文一起公开传输(比如之前代码里,IV 放在密文最前面)。
      解密时,只要用 “和加密时相同的 IV + 相同的密钥”,就能找到正确的 “起始位置”,反向洗牌还原明文。

      代码

      from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
      import os
      
      # ------------------------------
      # 1. 生成AES密钥(关键!必须保存好,解密需要)
      # ------------------------------
      # AES密钥长度可选:128位(16字节)、192位(24字节)、256位(32字节)
      # 推荐128位或256位,这里用128位示例
      aes_key = os.urandom(16)  # 随机生成16字节(128位)密钥
      print("AES密钥(十六进制):", aes_key.hex())  # 显示密钥(实际中不要泄露)
      
      
      # ------------------------------
      # 2. 定义加密函数(用AES加密数据)
      # ------------------------------
      def aes_encrypt(key, plaintext):
          # 生成随机IV(初始化向量):AES-CBC模式需要16字节IV,每次加密都要不同
          iv = os.urandom(16)  # 随机生成16字节IV
          
          # 创建加密器:使用AES算法,CBC模式(最常用的模式之一)
          cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
          encryptor = cipher.encryptor()
          
          # 数据补位:CBC模式要求数据长度是16字节的倍数,不足的用空格补全
          # (实际场景中会用更标准的PKCS7补位,这里简化用空格)
          padded_text = plaintext.encode().ljust(16 * ((len(plaintext) // 16) + 1))
          
          # 执行加密
          ciphertext = encryptor.update(padded_text) + encryptor.finalize()
          
          # 返回:IV + 密文(解密时需要IV,所以一起传输)
          return iv + ciphertext
      
      
      # ------------------------------
      # 3. 定义解密函数(用AES解密数据)
      # ------------------------------
      def aes_decrypt(key, encrypted_data):
          # 从加密结果中提取IV(前16字节)和密文(剩余部分)
          iv = encrypted_data[:16]
          ciphertext = encrypted_data[16:]
          
          # 创建解密器:和加密用相同的算法和模式
          cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
          decryptor = cipher.decryptor()
          
          # 执行解密
          decrypted_padded = decryptor.update(ciphertext) + decryptor.finalize()
          
          # 去除补位的空格,转回字符串
          return decrypted_padded.decode().strip()
      
      
      # ------------------------------
      # 4. 测试:加密解密"123"
      # ------------------------------
      # 要加密的数据
      data = "123"
      
      # 加密
      encrypted = aes_encrypt(aes_key, data)
      print("加密后的数据(十六进制):", encrypted.hex())  # 十六进制显示密文
      
      # 解密
      decrypted = aes_decrypt(aes_key, encrypted)
      print("解密后的数据:", decrypted)

      MD5 (数据指纹)

      MD5 是一种哈希 算法(哈希算法,也叫散列算法),核心作用是把任意长度的数据(比如一段文字、一个文件)转换成一个固定长度的字符串(通常是 32 位十六进制十六进制的十六数字和字母的组合),这个字符串被称为 “哈希值” 或 “摘要”。

      不可逆:通过哈希值无法反推出原始数据(比如知道 202cb962ac59075b964b07152d234b70,无法算出原始数据是 “123”)。

      加盐

      MD5 加盐(Salt)是一种增强 MD5 安全性的手段,专门用来对付 “字典攻击”(通过彩虹表反查明文),原理很简单:给原始数据 “加一段随机字符串” 再算 MD5,让黑客的字典彻底失效。

      加盐的核心逻辑:

      生成随机 “盐”:每次加密时,生成一段随机字符串(比如 8 位、16 位,越长越安全),比如 “salt_123$”。


      明文 + 盐混合:把原始明文和盐拼接在一起(比如明文 “123”+ 盐 “salt_123”)。


      计算加盐后的 MD5:用混合后的字符串算 MD5,得到的哈希值和不加盐时完全不同。


      存储 “盐 + 加盐后的 MD5”:盐不需要保密,和最终的 MD5 值一起存到数据库里(比如存 “salt_123$|a7b3f9...”)。

      SHA-256(数据指纹)

      证书验证

      CA 数字签名的生成逻辑:CA 先对证书主体数据用 SHA 算法算 “原始哈希值”,再用自身私钥加密这个哈希值,形成签名。

      乙方验证步骤:
      提取证书的主体数据和 CA 签名,用设备预装的该 CA 公钥解密签名,拿到 “原始哈希值”。
      乙方用相同 SHA 算法,对提取的主体数据重新计算,得到 “新哈希值”。
      对比两个哈希值:一致则证书合法(未篡改、是 CA 签发),不一致则证书失效,通信中断。

      代理网络

      没开代理:手机 → 直接 → 服务器(请求直达,没人能拦)
      开了代理:手机 → 先到抓包工具 → 再到服务器(请求被抓包工具截胡,再转发)

      简单说:代理就是给网络请求 “改道”,强制让抓包工具成为手机和服务器之间的 “必经之路”—— 不然请求直接飞服务器了,抓包工具根本碰不到,自然没法抓数据。

        Logo

        北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

        更多推荐