【问题标题】:PowerShell Validate SAML Signed XMLPowerShell 验证 SAML 签名的 XML
【发布时间】:2016-07-09 22:23:31
【问题描述】:

我们最近遇到了一个问题,即 IdP 不信任来自我们 RP/SP 的 SAML 2.0 注销请求签名。我们正在寻找其他方法来验证 SAML 请求签名,因为 IdP 和 samltool.com 都抱怨签名验证。以下是我们用来检查签名数据是否可以根据签名验证的示例答案。

【问题讨论】:

  • 此代码无法正确验证签名并且容易受到 XML 签名包装攻击,因为它不检查引用。我写了一个blog post 说明什么是引用以及为什么必须检查它们。
  • @AndersAbel,我不确定我是否 100% 关注您的评论。在我对此代码的测试中,当我更改签名数据时,XML 签名验证会按预期返回 false。如果您正在谈论验证整个 XML 文档的信任,那么这超出了我试图展示的范围。这只是一个验证签名数据签名的简单脚本。在这两个示例中,我都在 $signed 对象中提供了关键信息,您是否表示我仍需要在 $signed.CheckSignature() 中将其作为参数提供?
  • @AndersAbel 我想我现在明白了,但是此代码并非用于检查 SAML 令牌的可信度/有效性,仅根据签名数据验证签名是否通过。
  • @AndersAbel 此代码用于解决验证问题,而不是用于编写需要验证引用的 IdP/SP/RP,正如您所指出的。在我们的场景中,我们有一个无法验证注销请求上的签名的 IdP,我们需要的只是一个验证签名的示例,令牌是否被篡改并不重要。这段代码用来证明 IdP 配置错误。如果您想建议一些代码来改进我们使用它的功能,那就太好了!
  • 好的,我看到在您的特定用例中,可能不需要检查引用。但请在示例中明确说明没有做,否则别人会找到代码并使用它而不了解后果。

标签: .net xml powershell saml xml-dsig


【解决方案1】:

为 SHA256 添加所需的类型和定义

Add-Type -AssemblyName System.Security

# Add SHA-256 per http://stackoverflow.com/questions/30759119/verifying-xml-signature-in-powershell-with-pem-certificate
Add-Type @'
        public class RSAPKCS1SHA256SignatureDescription : System.Security.Cryptography.SignatureDescription
            {
                public RSAPKCS1SHA256SignatureDescription()
                {
                    base.KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider";
                    base.DigestAlgorithm = "System.Security.Cryptography.SHA256Managed";
                    base.FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
                    base.DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
                }

                public override System.Security.Cryptography.AsymmetricSignatureDeformatter CreateDeformatter(System.Security.Cryptography.AsymmetricAlgorithm key)
                {
                    System.Security.Cryptography.AsymmetricSignatureDeformatter asymmetricSignatureDeformatter = (System.Security.Cryptography.AsymmetricSignatureDeformatter)
                        System.Security.Cryptography.CryptoConfig.CreateFromName(base.DeformatterAlgorithm);
                    asymmetricSignatureDeformatter.SetKey(key);
                    asymmetricSignatureDeformatter.SetHashAlgorithm("SHA256");
                    return asymmetricSignatureDeformatter;
                }
            }
'@
$RSAPKCS1SHA256SignatureDescription = New-Object RSAPKCS1SHA256SignatureDescription
[System.Security.Cryptography.CryptoConfig]::AddAlgorithm($RSAPKCS1SHA256SignatureDescription.GetType(), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")

验证请求中不包含证书的 SAML 2.0 HTTP-POST 请求:

$saml = "insert real saml request here"

$decoded = [System.Convert]::FromBase64String($saml)
$stream = [System.IO.MemoryStream]::new($decoded, 0, $decoded.length)

$xml = New-Object System.Xml.XmlDocument
$xml.PreserveWhitespace = $true
$xml.Load($stream)

$signed = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $xml
$signed.LoadXml($xml.DocumentElement.Assertion.Signature)

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new("C:\Users\username\Desktop\idp.cer")

$keyinfo = [System.Security.Cryptography.Xml.KeyInfo]::new()
$clause = [System.Security.Cryptography.Xml.KeyInfoX509Data]::new($cert)
$keyinfo.AddClause($clause)

$signed.KeyInfo = $keyinfo

$signed.CheckSignature()

修改 XML,使上述示例中的签名无法验证:

$xml.Response.Assertion.Subject.NameID.'#text' = 'asdasdasd'

$signed = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $xml
$signed.LoadXml($xml.DocumentElement.Assertion.Signature)

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new("C:\Users\username\Desktop\idp.cer")

$keyinfo = [System.Security.Cryptography.Xml.KeyInfo]::new()
$clause = [System.Security.Cryptography.Xml.KeyInfoX509Data]::new($cert)
$keyinfo.AddClause($clause)

$signed.KeyInfo = $keyinfo

$signed.CheckSignature()

使用包含在请求中的证书验证 SAML 2.0 HTTP-POST 请求:

$saml = "insert example saml request here"
$decoded = [System.Convert]::FromBase64String($saml)
$stream = [System.IO.MemoryStream]::new($decoded, 0, $decoded.length)

$xml = New-Object System.Xml.XmlDocument
$xml.PreserveWhitespace = $true
$xml.Load($stream)

$signed = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $xml
$signed.LoadXml($xml.DocumentElement.Signature)
$signed.CheckSignature()

修改 XML,使上述示例中的签名无法验证:

$xml.LogoutRequest.NameID.'#text' = "dasdasd"

$signed = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $xml
$signed.LoadXml($xml.DocumentElement.Signature)


# Should return false since we modified the data
$signed.CheckSignature()

如果其他人需要完成相同的任务,希望这可以节省一些时间。如果您有任何意见/建议,请告诉我。

谢谢!

【讨论】:

  • 好建议@AndersAbel,我已经更新了问题/答案的格式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 2021-12-18
  • 2013-10-28
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多