""" 签名验证工具 参考 TranspondSms 的签名规则: timestamp + "\n" + secret -> HMAC-SHA256 -> Base64 -> URL Encode """ import hmac import hashlib import base64 import urllib.parse import time def generate_sign(secret: str, timestamp: int = None) -> str: """ 生成签名 Args: secret: 密钥 timestamp: 时间戳(毫秒),不传则使用当前时间 Returns: 签名字符串 """ if timestamp is None: timestamp = int(time.time() * 1000) string_to_sign = f"{timestamp}\n{secret}" hmac_code = hmac.new( secret.encode('utf-8'), string_to_sign.encode('utf-8'), digestmod=hashlib.sha256 ).digest() sign = urllib.parse.quote(base64.b64encode(hmac_code).decode()) return sign def verify_sign(secret: str, sign: str, timestamp: int, max_age: int = 3600000) -> tuple[bool, str]: """ 验证签名 Args: secret: 密钥 sign: 待验证的签名 timestamp: 时间戳(毫秒) max_age: 签名最大有效时间(毫秒),默认1小时 Returns: (是否有效, 错误信息) """ current_time = int(time.time() * 1000) # 检查时间戳是否过期 if abs(current_time - timestamp) > max_age: return False, f"签名过期,时间差: {abs(current_time - timestamp) / 1000:.1f}秒" # 生成期望的签名 expected_sign = generate_sign(secret, timestamp) # 比较签名 if sign != expected_sign: return False, "签名不匹配" return True, "签名有效" def verify_from_app(from_number: str, content: str, timestamp: int, sign: str, secret: str, max_age: int = 3600000) -> tuple[bool, str]: """ 验证 TranspondSms APP 发来的请求 Args: from_number: 发送方手机号 content: 短信内容 timestamp: 时间戳 sign: 签名 secret: 密钥 max_age: 最大有效时间(毫秒) Returns: (是否有效, 错误信息) """ # 检查必填字段 if not from_number or not content: return False, "缺少必填字段" # 如果没有签名,跳过验证(取决于配置) if not sign: return True, "无签名,跳过验证" return verify_sign(secret, sign, timestamp, max_age) # 测试代码 if __name__ == '__main__': # 测试签名生成和验证 secret = "test_secret" timestamp = int(time.time() * 1000) # 生成签名 sign = generate_sign(secret, timestamp) print(f"Timestamp: {timestamp}") print(f"Sign: {sign}") # 验证签名 is_valid, message = verify_sign(secret, sign, timestamp) print(f"验证结果: {is_valid}, {message}") # 测试过期签名 old_timestamp = timestamp - 7200000 # 2小时前 is_valid, message = verify_sign(secret, sign, old_timestamp) print(f"过期验证: {is_valid}, {message}") # 测试错误签名 wrong_sign = "wrong_signature" is_valid, message = verify_sign(secret, wrong_sign, timestamp) print(f"错误签名: {is_valid}, {message}")