Python XML签名和XAdES库
项目描述
SignXML是W3CXML签名标准的Python实现。此标准(也称为“XMLDSig”)用于提供SAML 2.0、XAdES和WS-Security等用途中的有效载荷安全。该标准在W3C推荐 XML签名语法和处理版本1.1中定义。SignXML实现了1.1版本标准的所有必需组件以及大多数推荐组件。其功能包括
使用基于libxml2的XML解析器,在验证签名时配置为防御常见的XML攻击
扩展以允许使用X.509证书链进行签名和验证,包括主机名/CN验证
扩展以签名和验证XAdES签名
支持具有包容性前缀的独占XML规范化(包容性命名空间前缀列表,某些SAML实现生成的签名所需的验证)
现代Python兼容性(3.7-3.11+和PyPy)
广泛支持、便携、可靠的依赖项: lxml 和 cryptography
全面测试(包括XMLDSig互操作性套件)和持续集成
简单界面,具有实用、人体工程学和安全的默认值(无网络调用、XSLT或XPath转换)
紧凑性、可读性和可扩展性
安装
pip install signxml
概要
SignXML使用lxml ElementTree API来处理XML数据。
from lxml import etree
from signxml import XMLSigner, XMLVerifier
data_to_sign = "<Test/>"
cert = open("cert.pem").read()
key = open("privkey.pem").read()
root = etree.fromstring(data_to_sign)
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
为了使此示例在测试目的上自给自足
使用以下命令生成测试证书和密钥:openssl req -x509 -nodes -subj "/CN=test" -days 1 -newkey rsa -keyout privkey.pem -out cert.pem(如果找不到openssl可执行文件,请运行apt-get install openssl、yum install openssl或brew install openssl)。
将x509_cert=cert关键字参数传递给XMLVerifier.verify()。在生产环境中,请确保用正确的配置替换此配置,以信任CA或证书 - 这决定了你的应用程序信任哪些签名。)
验证SAML断言
假设metadata.xml包含断言源的SAML元数据
from lxml import etree
from base64 import b64decode
from signxml import XMLVerifier
with open("metadata.xml", "rb") as fh:
cert = etree.parse(fh).find("//ds:X509Certificate").text
assertion_data = XMLVerifier().verify(b64decode(assertion_body), x509_cert=cert).signed_xml
XML签名构造方法:封装、非封装、封装
XML签名规范定义了三种组合签名的数据签名的三种方式:封装、分离和封装签名。封装是默认方法。要指定要生成的签名类型,请将method参数传递给sign()
signed_root = XMLSigner(method=signxml.methods.detached).sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
对于分离签名,上述代码将使用root的Id或ID属性来生成一个相对URI(<Reference URI="#value">)。您还可以通过将reference_uri参数传递给sign()来覆盖URI的值。要验证引用外部实体的分离签名,请将可调用的解析器传递给XMLVerifier().verify(data, uri_resolver=...)。
有关更多详细信息,请参阅API文档。
XML表示细节:配置命名空间前缀和空白
某些应用程序需要特定的命名空间前缀配置 - 例如,许多应用程序假定http://www.w3.org/2000/09/xmldsig#命名空间被设置为默认的无前缀命名空间,而不是使用习惯的ds:前缀。虽然在实际使用中命名空间前缀命名是一个不重要的表示细节,但在某些XML规范化签名配置中可能很重要。在生成签名时配置命名空间前缀映射,请设置XMLSigner.namespaces属性
signer = signxml.XMLSigner(...)
signer.namespaces = {None: signxml.namespaces.ds}
signed_root = signer.sign(...)
同样,签名文档中的空白对XML规范化和签名目的也很重要。在生成签名后不要美化打印XML,因为这可能会不幸地使签名无效。
XML解析安全性和与xml.etree.ElementTree的兼容性
SignXML使用lxml ElementTree库,而不是Python标准库中的ElementTree,来处理XML。由于lxml具有优异的抵抗XML攻击的能力,以及XML规范化和命名空间组织功能,因此使用lxml。建议在进一步解析之前直接将XML字符串输入传递给signxml,并通常使用lxml处理不受信任的XML输入。如果您确实将xml.etree.ElementTree对象传递给SignXML,您应该意识到这两个库之间XML命名空间处理的不同之处。有关更多信息,请参阅以下参考资料
XAdES签名
XAdES(“XML高级电子签名”)是用于将元数据附加到XML签名对象的规范。该规范得到了欧盟的认可,作为其实施其电子签名法规的规范。
SignXML支持使用XAdES签名进行文档的签名和验证
from signxml import DigestAlgorithm
from signxml.xades import (XAdESSigner, XAdESVerifier, XAdESVerifyResult,
XAdESSignaturePolicy, XAdESDataObjectFormat)
signature_policy = XAdESSignaturePolicy(
Identifier="MyPolicyIdentifier",
Description="Hello XAdES",
DigestMethod=DigestAlgorithm.SHA256,
DigestValue="Ohixl6upD6av8N7pEvDABhEL6hM=",
)
data_object_format = XAdESDataObjectFormat(
Description="My XAdES signature",
MimeType="text/xml",
)
signer = XAdESSigner(
signature_policy=signature_policy,
claimed_roles=["signer"],
data_object_format=data_object_format,
c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
)
signed_doc = signer.sign(doc, key=private_key, cert=certificate)
verifier = XAdESVerifier()
verify_results = verifier.verify(
signed_doc, x509_cert=certificate, expect_references=3, expect_signature_policy=signature_policy
)
for verify_result in verify_results:
if isinstance(verify_result, XAdESVerifyResult):
verify_result.signed_properties # use this to access parsed XAdES properties
链接
W3C 工作组笔记:XML 签名语法和版本 2.0 处理(此草案标准提案从未最终确定,并且没有广泛使用。)
错误
请通过 GitHub 报告错误、问题、功能请求等。
版本控制
此包遵循 语义版本控制 2.0.0 标准。为了控制更改,建议应用程序开发者锁定包版本,并使用 pip-tools 或类似工具进行管理。对于库开发者,建议锁定主版本。
许可证
版权所有 2014-2023,Andrey Kislyuk 和 SignXML 贡献者。根据 Apache 许可证 2.0 版本 许可。根据 Apache 许可证的规定,分发此包和衍生作品的源代码副本时,必须分发 LICENSE 和 NOTICE 文件。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。