You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

signxml签名无效但xmlsec有效,求差异原因及适配方案

解决signxml与xmlsec签名不一致的问题

关键差异分析

你遇到的验证失败,核心源于两个签名结构的差异:

  • 缺失Issuer详情标签:xmlsec生成的签名在KeyInfo节点中包含了证书的Issuer信息,而signxml默认不会输出该字段
  • Reference节点数量不同:xmlsec生成的签名包含两个Reference(分别指向SOAP Body和WSSE Security头),你的signxml代码仅生成一个指向主体的Reference

调整signxml配置的具体方案

1. 生成多Reference的WSSE风格签名

你的xmlsec代码采用的是WSSE(Web Services Security)规范的签名逻辑,需要同时对SOAP Body和Security头进行签名。调整signxml代码如下:

from signxml import XMLSigner, methods
from lxml import etree

# 假设xml_element是你的SOAP Envelope节点
soap_env = xml_element
security_ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
wsse_prefix = "wsse"

# 创建WSSE Security头并插入到SOAP Header中
security_header = etree.SubElement(
    soap_env.find("{http://schemas.xmlsoap.org/soap/envelope/}Header"),
    f"{{{security_ns}}}Security",
    nsmap={wsse_prefix: security_ns}
)

# 初始化签名器,对齐算法配置
signer = XMLSigner(
    method=methods.enveloped,
    signature_algorithm="rsa-sha1",
    digest_algorithm='sha1',
    c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
)
signer.namespaces = {None: signer.namespaces['ds']}

# 给需要签名的节点添加唯一ID
body_id = "Body-SigId"
security_id = "Security-SigId"

soap_body = soap_env.find("{http://schemas.xmlsoap.org/soap/envelope/}Body")
soap_body.set(f"{{{security_ns}}}Id", body_id)
security_header.set(f"{{{security_ns}}}Id", security_id)

# 添加两个Reference,对应xmlsec的签名逻辑
signer.references = [
    {"uri": f"#{body_id}", "digest_algorithm": "sha1"},
    {"uri": f"#{security_id}", "digest_algorithm": "sha1"}
]

# 将签名节点插入到Security头内
signed_root = signer.sign(
    soap_env, 
    key=self.chave, 
    cert=self.certificado, 
    reference_uri=None,
    insert_reference=security_header
)

2. 添加Issuer详情标签

需要让signxml在KeyInfo中输出证书的Issuer和Serial信息,修改签名时的参数配置:

from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend

# 从证书中提取Issuer和Serial信息
cert_obj = load_pem_x509_certificate(self.certificado, default_backend())
issuer_name = cert_obj.issuer.rfc4514_string()
serial_number = cert_obj.serial_number

# 签名时指定keyinfo_options,添加X509IssuerSerial
signed_root = signer.sign(
    soap_env, 
    key=self.chave, 
    cert=self.certificado, 
    reference_uri=None,
    insert_reference=security_header,
    keyinfo_options={
        "X509IssuerSerial": {"issuer_name": issuer_name, "serial_number": serial_number},
        "X509Certificate": True  # 保留证书内容,和xmlsec对齐
    }
)

3. 额外注意事项

  • 命名空间完全对齐:确保WSSE、ds等命名空间的前缀和URI与xmlsec生成的完全一致,避免因命名空间差异导致验证失败
  • 确认C14N算法:确保xmlsec使用的规范化算法和signxml配置的http://www.w3.org/TR/2001/REC-xml-c14n-20010315完全相同
  • 签名节点位置:xmlsec默认将签名放在WSSE Security头内,signxml通过insert_reference参数指定插入位置,确保结构一致

内容的提问来源于stack exchange,提问作者Krish V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 19:55:19