接口加密思路

  1. 简述

    使用加密算法实现接口加密,实现一定程度上的防爬及数据安全。

    悉知:没有绝对安全的系统,只有破解成本的高低。

  2. 加密算法

    目前密码学通常将加密算法分为以下三类:

    • 对称加密算法

      • 特点:加密和解密使用相同的密钥(或可相互推导)。
      • 核心问题:密钥需要在通信双方之间安全共享。
      • 常见算法:AES(高级加密标准)、DES(已淘汰)、SM4(国密)。
      • 应用场景:大数据量加密(如文件加密、数据库存储、SSL/TLS通信的会话密钥)。
    • 非对称加密算法

      • 特点:使用公钥(公开)和私钥(保密)组成的密钥对,公钥加密的数据只能由私钥解密,反之亦然。
      • 核心问题:解决密钥分发难题,但计算效率低于对称加密。
      • 常见算法:RSA(基于大数分解)、ECC(椭圆曲线密码学,如ECDSA)、ElGamal、SM2(国密)。
      • 应用场景:密钥交换(如DH算法)、数字签名、身份认证(如SSL/TLS证书)。
    • 哈希算法

      • 特点:将任意长度输入映射为固定长度的输出(哈希值),且不可逆
      • 核心要求:抗碰撞性、单向性。
      • 常见算法:SHA-256、SHA-3(Keccak)、MD5(已不安全)、SM3(国密)。
      • 应用场景:数据完整性校验(如文件校验)、密码存储(加盐哈希)、区块链(默克尔树)。

      对称加密与非对称加密对比

      对称加密 (如AES) 非对称加密 (如RSA)
      密钥机制 单密钥(加密/解密相同) 密钥对(公钥加密,私钥解密)
      算法复杂度 基于位运算(快速) 基于数学难题(大数分解/椭圆曲线)
      密钥长度 短(128/256位) 长(2048位以上)
      典型算法 AES, ChaCha20, SM4 RSA, ECC, SM2
      加密速度 极快(GB/s级) 慢(比对称加密慢100-1000倍)
      资源消耗 低(适合IoT/移动设备) 高(需强大CPU)
      大数据处理能力 优秀(适合流数据) 仅适合小数据(如加密密钥)
      密钥分发风险 高(需安全通道共享密钥) 低(公钥可公开)
  3. 实现思路

    客户端:

    1. 生成随机AES密钥 (会话密钥)
    2. 用RSA公钥加密AES密钥
    3. 用AES密钥加密实际数据
    4. 发送 [加密后的AES密钥] + [AES加密的数据]

    服务端:

    1. 用RSA私钥解密获取AES密钥
    2. 用AES密钥解密数据
    3. 用AES加密响应数据返回

    客户端:

    1. 使用会话中的AES密码解密响应数据
    sequenceDiagram
        participant Client as 客户端
        participant Server as 服务端
        Note over Client: 请求加密阶段
            Client->>Client: 1. 生成随机AES密钥
            Client->>Client: 2. 用AES加密请求数据
            Client->>Client: 3. 用RSA公钥加密AES密钥
            Client->>Server: 4. 发送[加密的AES密钥]+[AES加密请求]
    
            Note over Server: 请求处理阶段
            Server->>Server: 5. 用RSA私钥解密AES密钥
            Server->>Server: 6. 用AES密钥解密请求数据
            Server->>Server: 7. 处理业务逻辑
    
            Note over Server: 响应加密阶段
            Server->>Server: 8. 用同一AES密钥加密响应
            Server->>Client: 9. 返回[AES加密响应]
    
            Note over Client: 响应解密阶段
            Client->>Client: 10. 用缓存的AES密钥解密响应
  4. Python RSAAES工具类

    1
    $ pip install pycryptodome

    RSA工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    # time : 2022/2/7
    # __author__ = Ysc

    import base64
    import json
    import os
    from Crypto import Random
    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    from Crypto.PublicKey import RSA


    PEM_DIR = os.path.join('.')


    def GeneratePEM():
    # rsa算法生成实例
    rsa = RSA.generate(1024, Random.new().read)

    # Server的秘钥对的生成
    private_pem = rsa.exportKey()
    with open("%s/server-public.pem" % PEM_DIR, "wb") as f:
    f.write(private_pem)

    public_pem = rsa.publickey().exportKey()
    with open("%s/server-private.pem" % PEM_DIR, "wb") as f:
    f.write(public_pem)


    class DeEncrypt:
    __instance = None
    __hasInit = False

    def __new__(cls):
    if cls.__instance is None:
    cls.__instance = object.__new__(cls)
    return cls.__instance
    else:
    return cls.__instance

    def __init__(self):
    if not self.__hasInit:
    with open("%s/server-public.pem" % PEM_DIR) as f:
    public_key = f.read()
    f.close()
    self.public_key = public_key
    with open("%s/server-private.pem" % PEM_DIR) as f:
    private_key = f.read()
    f.close()
    self.private_key = private_key

    self.__hasInit = True

    # todo 长度隐患旧方法
    # 使用公钥对内容进行rsa 加密
    def Encrypt(self, msg):
    key = self.public_key
    rsakey = RSA.importKey(key)
    cipher = Cipher_pkcs1_v1_5.new(rsakey)
    cipher_text = base64.b64encode(cipher.encrypt(msg.encode('utf-8')))
    return cipher_text.decode('utf-8')

    # 使用私钥对内容进行rsa 解密
    def Decrypt(self, msg):
    random_generator = Random.new().read
    key = self.private_key
    rsakey = RSA.importKey(key)
    cipher = Cipher_pkcs1_v1_5.new(rsakey)
    text = cipher.decrypt(base64.b64decode(msg), random_generator)
    return text.decode('utf-8')

    AES工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    # time : 2022/2/8
    # __author__ = Ysc

    from Crypto.Cipher import AES
    import base64


    class AESCipher:

    def __init__(self, key: str, iv: str):
    if len(key) != 16 or len(iv) != 16:
    log.error(f"key or iv 长度异常: {key}, {iv} ")
    raise ValueError("length error")

    self.key = bytes(key, encoding='utf-8')
    self.iv = bytes(iv, encoding='utf-8')

    def pkcs7padding(self, text):
    """
    明文使用PKCS7填充
    最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理
    :param text: 待加密内容(明文)
    :return:
    """
    bs = AES.block_size # 16
    length = len(text)
    bytes_length = len(bytes(text, encoding='utf-8'))
    # tips:utf-8编码时,英文占1个byte,而中文占3个byte
    padding_size = length if (bytes_length == length) else bytes_length
    padding = bs - padding_size % bs
    # tips:chr(padding)看与其它语言的约定,有的会使用'\0'
    padding_text = chr(padding) * padding
    return text + padding_text

    def pkcs7unpadding(self, text):
    """
    处理使用PKCS7填充过的数据
    :param text: 解密后的字符串
    :return:
    """
    try:
    length = len(text)
    unpadding = ord(text[length - 1])
    return text[0:length - unpadding]
    except Exception as e:
    pass

    def encrypt(self, content):
    """
    AES加密
    key,iv使用同一个
    模式cbc
    填充pkcs7
    :param key: 密钥
    :param content: 加密内容
    :return:
    """
    cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
    # 处理明文
    content_padding = self.pkcs7padding(content)
    # 加密
    aes_encode_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8'))
    # 重新编码
    result = str(base64.b64encode(aes_encode_bytes), encoding='utf-8')
    return result

    def decrypt(self, content):
    """
    AES解密
    key,iv使用同一个
    模式cbc
    去填充pkcs7
    :param key:
    :param content:
    :return:
    """
    try:

    cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
    # base64解码
    aes_encode_bytes = base64.b64decode(content)
    # 解密
    aes_decode_bytes = cipher.decrypt(aes_encode_bytes)
    # 重新编码
    result = str(aes_decode_bytes, encoding='utf-8')
    # 去除填充内容
    result = self.pkcs7unpadding(result)
    except Exception as e:
    pass
    if result == None:
    return ""
    else:
    return result