Python signxml签名XML时命名空间异常致验证失败的求助
解决signxml生成指定命名空间XML签名的问题
核心思路
确保Signature标签单独携带http://www.w3.org/2000/09/xmldsig#命名空间,根节点getToken无命名空间,同时保证序列化后签名验证有效。
具体实现步骤
- 导入依赖库
from lxml import etree from signxml import XMLSigner, XMLVerifier from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa
- 准备密钥对(实际场景建议从文件读取密钥)
# 生成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 )
- 构造无命名空间的基础XML结构
# 根节点getToken不带任何命名空间 root = etree.Element("getToken") # 添加业务子节点示例 etree.SubElement(root, "userId").text = "test_user_001" etree.SubElement(root, "timestamp").text = "20240520153000"
- 执行签名并控制命名空间
# 初始化签名器,指定SHA-1算法 signer = XMLSigner( method="enveloped", signature_algorithm="rsa-sha1", digest_algorithm="sha1" ) # 签名时指定Signature标签的命名空间,确保命名空间仅附着在Signature上 signed_root = signer.sign( root, key=private_pem, reference_uri="#", ns="http://www.w3.org/2000/09/xmldsig#" ) # 清理自动添加到根节点的冗余命名空间声明 etree.cleanup_namespaces(signed_root)
- 序列化XML并验证
# 序列化XML,确保格式符合要求 serialized_xml = etree.tostring( signed_root, encoding="UTF-8", xml_declaration=True, pretty_print=True ) # 验证序列化后的签名有效性 parsed_signed_xml = etree.fromstring(serialized_xml) verifier = XMLVerifier() verifier.verify(parsed_signed_xml, key=public_pem) print("签名验证通过")
关键注意事项
- 构造根节点时不要添加任何命名空间,避免后续自动继承
- 使用
etree.cleanup_namespaces()移除根节点上被自动添加的命名空间声明 - 签名时通过
ns参数明确指定Signature标签的目标命名空间,确保命名空间仅出现在Signature节点上
内容的提问来源于stack exchange,提问作者Diego Salinas Flores
相关产品推荐
相关产品推荐

