模型身份认证:验证部署模型是否被篡改

FreeGuideOnline 最新 2026-06-27

bash pip install cryptography torch


### 生成模型文件的哈希值

我们使用 SHA-256 计算模型文件的哈希。实际应用中,模型可能是 `.pt`、`.h5` 或 SavedModel 目录,对于目录可先打包为压缩文件再计算。

```python
import hashlib

def get_file_hash(filepath, algo='sha256'):
    """返回文件的哈希十六进制字符串"""
    h = hashlib.new(algo)
    with open(filepath, 'rb') as f:
        while chunk := f.read(8192):
            h.update(chunk)
    return h.hexdigest()

# 示例:计算随机模型文件的哈希
import torch
import torch.nn as nn
model = nn.Linear(10, 2)
torch.save(model.state_dict(), 'model.pth')
hash_value = get_file_hash('model.pth')
print(f"模型哈希(SHA-256): {hash_value}")

记下这个哈希值,稍后用于签名。

创建数字签名(RSA示例)

下面生成一对 RSA 密钥,用私钥对哈希值进行签名,生成签名文件。实际场景中私钥必须安全离线存储

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding

def generate_keys():
    """生成RSA私钥和公钥,返回私钥路径和公钥路径"""
    private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
    # 保存私钥(实践中需加密保护)
    with open('private_key.pem', 'wb') as f:
        f.write(private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        ))
    # 保存公钥
    public_key = private_key.public_key()
    with open('public_key.pem', 'wb') as f:
        f.write(public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        ))
    return 'private_key.pem', 'public_key.pem'

def sign_hash(hash_value, private_key_path):
    """用私钥对哈希值签名"""
    with open(private_key_path, 'rb') as f:
        private_key = serialization.load_pem_private_key(f.read(), password=None)
    signature = private_key.sign(
        hash_value.encode(),  # 哈希字符串转为字节
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    with open('model.sig', 'wb') as f:
        f.write(signature)
    print("签名已生成,保存至 model.sig")

private_pem, public_pem = generate_keys()
sign_hash(hash_value, private_pem)

此时目录中有了模型文件 model.pth、签名文件 model.sig 和公钥 public_key.pem

验证签名与哈希

使用者收到模型、签名文件和公钥后,执行验证:

def verify_model(model_path, sig_path, public_key_path):
    # 1. 重新计算模型哈希
    new_hash = get_file_hash(model_path)
    # 2. 加载公钥和签名
    with open(public_key_path, 'rb') as f:
        public_key = serialization.load_pem_public_key(f.read())
    with open(sig_path, 'rb') as f:
        signature = f.read()
    # 3. 验证
    try:
        public_key.verify(
            signature,
            new_hash.encode(),
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        print("✅ 验证成功:模型完整且来源可信")
    except Exception:
        print("❌ 验证失败:模型可能被篡改或签名无效")

verify_model('model.pth', 'model.sig', public_pem)

你可以故意修改模型文件(哪怕一个权重值),再次运行验证,系统将报告验证失败。

在生产环境中实施模型身份认证

部署流程集成验证

将验证步骤硬编码进模型加载器。例如在服务启动时,自动对指定模型执行数字签名验证,失败则拒绝启动服务。伪代码:

def load_model_with_verification(model_path, sig_path, pub_key_path):
    if not verify_signature(model_path, sig_path, pub_key_path):
        raise SecurityException("模型身份认证失败,拒绝加载")
    return load_model(model_path)

这样,任何试图加载篡改模型的请求都会被立即阻断。

自动化校验脚本

在 CI/CD 流水线中,模型构建完成后立刻自动签名,并将签名文件和公钥随模型一同打包。部署容器启动时运行校验脚本,仅当校验通过才挂载模型卷。

# Docker 入口脚本示例
#!/bin/bash
python verify.py /models/model.pth /signatures/model.sig /keys/public_key.pem
if [ $? -ne 0 ]; then
  echo "Model verification failed" >&2
  exit 1
fi
exec python serve.py