4

我们的 IdP 是 Salesforce.com 组织。SP 是第三方.Net 应用程序。在开发过程中,第 3 方报告他们无法验证发送的 SAML 响应。

我们决定尝试使用ComponentSpace来验证 SAML 响应。以下是我们尝试过的:

// Load the certificate from the file: certInFile
// Load the SAML in an XMLElement: samlXml
// Retrieve the certificate from the SAML: certInSaml

Console.WriteLine("SAML is valid ? " + SAMLResponse.IsValid(samlXml));
Console.WriteLine("Is SAML signed? " + SAMLMessageSignature.IsSigned(samlXml));
Console.WriteLine("Certificate found in SAML is same as certificate file? " + certInFile.Equals(certInSaml));
Console.WriteLine("Validated SAML with certificate found in SAML" + SAMLMessageSignature.Verify(samlXml, certInSaml));
Console.WriteLine("Validated SAML with certificate file" + SAMLMessageSignature.Verify(samlXml, certInFile));

除了最后两个之外,我对以上所有内容都是正确的。所以:

  1. SAML 有效
  2. SAML 具有有效的签名
  3. SAML中的公钥证书和我们的证书文件一样
  4. SAML 既不是使用证书文件的私钥,也不是使用 SAML 中发送的公钥

从 3,4 我们可以得出结论,Salesforce 正在签名,但使用不同的证书,但在响应中发送了错误的公钥?!

编辑:示例 SAML 在这里http://pastebin.com/J8FTxnhJ

我错过了什么?

4

3 回答 3

4

XML 签名验证失败,因为 XML 在签名后已被修改,或者使用了错误的证书来验证签名。最可能的情况是使用了错误的证书。

Salesforce 使用其私钥签署 SAML 响应。使用 Salesforce 管理控制台,您可以下载用于执行签名验证的相应公钥/证书。

调用 时SAMLMessageSignature.Verify,您可以指定X509Certificate用于执行验证的方法,这通常是您应该执行的操作。

但是,base-64 编码的 X.509 证书也嵌入在 XML 签名中。您可以使用此嵌入式证书来检查签名是否验证。

为此,请勿将 X509Certificate 传递给SAMLMessageSignature.Verify.

例如:SAMLMessageSignature.Verify(samlXml, null);

如果这有效但指定证书无效,则这确认使用了错误的证书。

您可以调用SAMLMessageSignature.GetCertificate以从 XML 签名中检索 X.509 证书,以将其与正在使用的证书进行比较。

另外,附带说明一下,XML 签名适用于 XML。无法使用在 HTTP Post 数据中发送的 base-64 编码的 SAML 响应直接验证它们。在尝试验证 XML 签名之前,必须将发布数据解码为 XML。

于 2015-05-09T00:54:37.333 回答
4

我知道这是一篇旧帖子,但我遇到了同样的问题并且对没有答案感到不满。对于遇到此问题并从 Internet 搜索中发现此页面是使用 ComponentSpace 对 Salesforce SAML 进行签名验证失败的唯一结果之一的人,问题可能不在 SAML 签名验证本身,而在于您如何解码 base-64 编码的 SAML 响应负载。

请注意,SAMLServiceProvider.ReceiveSSO()采用 an 的方法HttpRequest不会遇到此问题。我发现它特别是在手动解码可以触发此问题的有效负载时,具体取决于IdP 签署响应时的 XML格式

由于这是一篇较旧的帖子,并且 pastebin 链接早已不复存在,我们假设原始代码可能如下所示。(还假设 X.509 证书嵌入在有效负载中,但修复最终是相同的。)

var str = Encoding.UTF8.GetString(Convert.FromBase64String(samlResponse));
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(str);
var xcert = SAMLMessageSignature.GetCertificate(xdoc.DocumentElement);
var isSigned = SAMLMessageSignature.IsSigned(xdoc.DocumentElement);
var isValid = SAMLResponse.IsValid(xdoc.DocumentElement);
var isVerified = SAMLMessageSignature.Verify(xdoc.DocumentElement);

在 Salesforce(可能还有其他)的情况下,xcert 将为非 null,isSigned 和 isValid 设置为 true,但 isVerified 将为 false。上述代码的简单,难以捉摸的修复?xdoc.PreserveWhitespace = true;

原因是签名是基于原始 XML 结构(或它的某个子部分)生成的。如果 IdP 在其原始 SAML XML 中有空格,则它会包含在签名生成中,即使在 XML 中通常可以忽略空格。这就是 IsValid 在签名验证失败时仍会返回 true 的原因。

最后一个方便的说明,隐藏在 ComponentSpace 的示例代码中,完整的安全XmlDocument 转换是:

XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore;
xmlReaderSettings.XmlResolver = null;

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.XmlResolver = null;

using (XmlReader xmlReader = XmlReader.Create(new StreamReader(fileName), xmlReaderSettings))
{
    xmlDocument.Load(xmlReader);
}

对于我们的场景,我们不需要DtdProcessing.Ignore在 using 的额外步骤中XmlReaderSettings包含 ,而是将其包含在此解决方案中以涵盖所有用例。

于 2019-07-30T05:35:03.183 回答
1

当我们没有解码生成的 base64 编码的 SAML 而是直接尝试验证它时,这很有效。但是,仍然不确定为什么 ComponentSpace 方法对解码字符串的报告不同。

于 2014-01-18T08:35:34.680 回答