Flask中PGP/GPG签名验证Zip文件的实现疑问
解决方案
核心思路
不能直接对包含签名的Zip文件进行签名(添加签名会改变Zip的哈希值,导致签名失效),正确的做法是:
- 对原始目标文件/压缩包生成分离式PGP签名
- 将原始文件和签名文件一起打包成新Zip上传
- 接收端从Zip中提取原始文件和签名,用公钥验证签名有效性——签名通过即证明原始文件未被篡改,同时也能间接证明整个上传Zip未被恶意修改(任何篡改都会导致签名验证失败)
签名方操作(生成带签名的Zip)
使用GPG命令生成分离式签名后打包:
# 对原始压缩包data.zip生成分离式签名 gpg --output data.zip.sig --detach-sign data.zip # 将原始压缩包和签名打包成上传用的Zip zip upload.zip data.zip data.zip.sig
Flask端验证实现
修改你的代码,实现从上传Zip中提取文件和签名并验证:
import os import zipfile import pgpy from flask import Flask, request app = Flask(__name__) @app.route('/', methods=['POST']) def verify_signature(): validate_files(request.files) return 'ok' def validate_files(files): # 加载公钥 public_key, _ = pgpy.PGPKey.from_blob(os.environ['PUBLIC_KEY']) for file in files.values(): # 读取上传的Zip文件 with zipfile.ZipFile(file.stream, 'r') as zip_ref: # 检查Zip内是否包含所需的两个文件(可根据实际情况调整文件名) required_files = {'data.zip', 'data.zip.sig'} if not required_files.issubset(set(zip_ref.namelist())): raise ValueError("上传的Zip缺少必要文件:原始压缩包或签名文件") # 提取原始压缩包和签名文件的内容 with zip_ref.open('data.zip') as data_zip_file: data_zip_content = data_zip_file.read() with zip_ref.open('data.zip.sig') as sig_file: sig_content = sig_file.read() # 加载签名 signature = pgpy.PGPSignature.from_blob(sig_content) # 创建PGP消息对象(包含原始文件内容) message = pgpy.PGPMessage.new(data_zip_content) # 验证签名 try: # 用公钥验证签名有效性,同时验证文件完整性 public_key.verify(message, signature) print("签名验证通过,文件未被篡改") except pgpy.errors.PGPError as e: raise ValueError(f"签名验证失败:{str(e)}")
关键说明
- 分离式签名的作用:分离式签名仅包含签名信息,不包含原始文件内容,因此可以和原始文件一起打包而不破坏签名有效性。
- 验证逻辑:PGP签名验证过程会自动比对原始文件的哈希值与签名中记录的哈希值,只要签名验证通过,就能确保原始文件在签名后未被篡改。
- 安全注意事项:
- 确保上传的Zip内仅包含必要的原始文件和签名,避免混入恶意文件
- 公钥需妥善保管,避免被篡改
内容的提问来源于stack exchange,提问作者Leah
相关产品推荐
相关产品推荐

