【问题标题】:Signature Validation for a SAML Authn Request via GET method fails通过 GET 方法对 SAML Authn 请求的签名验证失败
【发布时间】:2019-08-17 10:28:33
【问题描述】:

我正在使用 c# 和 asp.net 向 idp 发送 SIGNED authnRequest。我的代码对 authnRequest 进行了签名,但签名验证在 idp 处失败。

详情

我尝试了很多解决方案,但都是徒劳的。 这就是我按照https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf 设置的指导方针所做的事情:

  • 步骤

    1. 对身份验证请求进行压缩,然后对其进行 base64 编码,最后进行 Url 编码。让我们称之为 AR
    2. URL 对 RelayState 进行编码。让我们称之为 RS
    3. Url 对签名算法字符串进行编码。让我们称之为 SA
    4. 所以现在要签名的字符串变成 SAMLRequest=AR&RelayState=RS&SigAlg=SA
    5. 现在我使用我们的私钥(服务提供商私钥)对我们在步骤 4 中获得的字符串进行签名。 6.我得到的结果签名,我对它进行base 64编码,然后对它进行URL编码。因此,我得到了一个 base64 和 url 编码的签名。让我们称之为SG
    6. 现在我将我们在步骤#6 中获得的签名附加到步骤#4 中的查询字符串。所以最终的查询字符串变为 SAMLRequest=AR&RelayState=RS&SigAlg=SA&Signature=SG

一切正常,但签名验证失败!

这是我的代码,与https://github.com/Sustainsys/Saml2/blob/v0.21.2/Kentor.AuthServices/WebSSO/Saml2RedirectBinding.cs#L53-L68 的代码相似

protected void btnSendAuthRequest_Click(object sender, EventArgs e)
    {
        string authRequest = txtInput.Text;
        //authRequest = authRequest.TrimEnd('\r', '\n');
        authRequest = DeflateBase64UrlEncode(authRequest);

        string spPrivateKey= txtKey.Text;
        string relayState = HttpUtility.UrlEncode("https://example.com/pages/home.aspx");

        string qs = "SAMLRequest=" + authRequest + "&RelayState=" + relayState;
        qs = AddSignature(qs, spPrivateKey);

        txtOutput.Text = qs;
    }

public string AddSignature(string queryString, string PrivateKeyNoHeaders)
    {
        RSACryptoServiceProvider tmpRsa = RSAKeyTests.RSAKeyUtils.DecodePrivateKeyInfo(Convert.FromBase64String(PrivateKeyNoHeaders));

        string signingAlgorithmUrl = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";

        queryString += "&SigAlg=" + HttpUtility.UrlEncode(signingAlgorithmUrl);

        var signatureDescription = (SignatureDescription)CryptoConfig.CreateFromName(signingAlgorithmUrl);
        HashAlgorithm hashAlg = signatureDescription.CreateDigest();
        hashAlg.ComputeHash(Encoding.UTF8.GetBytes(queryString));

AsymmetricSignatureFormatter asymmetricSignatureFormatter =
            signatureDescription.CreateFormatter(
                ((RSACryptoServiceProvider)tmpRsa));
        //.GetSha256EnabledRSACryptoServiceProvider()); 
        // Is the signature failing because of above ? 

        byte[] signatureValue = asymmetricSignatureFormatter.CreateSignature(hashAlg);
        queryString += "&Signature=" + HttpUtility.UrlEncode(Convert.ToBase64String(signatureValue));

        return queryString;
    }

private string DeflateBase64UrlEncode(string input)
    {
        var inputs = string.Format(input, Guid.NewGuid());
        var bytes = Encoding.UTF8.GetBytes(inputs);
        using (var output = new MemoryStream())
        {
            using (var zip = new DeflateStream(output, CompressionMode.Compress))
            {
                zip.Write(bytes, 0, bytes.Length);
            }
            var base64 = Convert.ToBase64String(output.ToArray());
            return HttpUtility.UrlEncode(base64);
        }
    }

【问题讨论】:

    标签: c# asp.net saml saml-2.0 sign


    【解决方案1】:

    CryptoConfig.createFromName(...)doesn't knowhttp://www.w3.org/2000/09/xmldsig#rsa-sha1 作为摘要+签名算法。如果 CryptoConfig.createFromName() 没有返回 null,则为 http://www.w3.org/2000/09/xmldsig#rsa-sha1 注册的任何算法都可能不是 RSA-SHA1。下面是使用 RSA 和 SHA1 对 SignatureDescription 的显式实现:

    public class RSASHA1SignatureDescription : SignatureDescription {
    
            public RSASHA1SignatureDescription() {
                KeyAlgorithm = "System.Security.Cryptography.RSA";
                DigestAlgorithm = "System.Security.Cryptography.SHA1Cng";
                FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
                DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
                _hashAlgorithm = "SHA1";
            }
    
            public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) {
                AsymmetricSignatureDeformatter item = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm);
                item.setKey(key);
                item.SetHashAlgorithm(_hashAlgorithm);
                return item;
            }
    
            public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) {
                AsymmetricSignatureFormatter item = (AsymmetricSignatureFormatter) CryptoConfig.CreateFromName(FormatterAlgorithm);
                item.setKey(key);
                item.SetHashAlgorithm(_hashAlgorithm);
                return item;
            }
    
            private string _hashAlgorithm;
        }
    

    另一种可能性是,您验证签名时不需要 rsa-sha1(许多身份提供者通过配置禁止 rsa-sha1)或验证不正确。尝试向 Okta 或 Salesforce 等真正的 IdP 注册并在那里进行验证。

    【讨论】:

    • 我使用 (samltool.com/validate_authn_req.php) 来验证我的请求,这就是导致 SAML 请求无效的错误。
    • 用真实的 IdP 试试
    • 我使用 (samltool.com/validate_authn_req.php) 验证我的请求,这就是 SAML 请求无效的错误。如果我使用同一站点的其他工具签署我的 saml 然后验证上面的网址,我没有收到错误。我试过你的方法,但没有奏效。它给出了一个编译时错误“'RSAPKCS1SHA1SignatureDescription' 由于其保护级别而无法访问”我也这样做了: CryptoConfig.AddAlgorithm(typeof(SHA1CryptoServiceProvider), "w3.org/2000/09/xmldsig#rsa-sha1"); 给出了运行时类型转换错误!
    • @SuhailWani 查看更新。如果这没有帮助,也许其他人可能会为您提供更好的答案。
    • 它没有帮助。它生成的签名与之前生成的签名相同。并且在线工具生成的签名是不同的。我使用 samltool.com 的工具也是一个标准工具,由我认为 onelogin 组开发。所以这有点合法。
    猜你喜欢
    • 1970-01-01
    • 2013-10-28
    • 2013-05-26
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-01
    相关资源
    最近更新 更多