SAML断言/验证如何使用X509公钥

本文关键字:何使用 X509 公钥 验证 断言 SAML | 更新日期: 2023-09-27 18:00:06

在我的asp.net MVC网站中,我实现了SSO,其中IDP/ADFS发送SAML响应,我验证SAML令牌以允许用户访问网站。我正在使用自定义代码(使用System.IdentityModel.dll和System.IdentiityModel.Services.dll库来验证SAML响应和令牌,而不是让.net框架使用web.config设置进行检查)。

到目前为止,代码似乎工作得很好,但由于我是这个领域的新手,我担心黑客会通过正确构建的SAML响应绕过验证。最近,我尝试了SAML令牌生成部分,我意识到如果令牌是智能生成的,我的令牌验证代码可以绕过。

在高层,这是我正在做的验证令牌:

  1. 从请求中提取安全令牌
  2. 通过使用提供的X509公钥(存在于SAML响应中)检查摘要值,验证令牌是否有效且未受影响
    1. 提取用户的声明/身份并允许访问

我担心的是,如果黑客创建SAML令牌(就像我自己的令牌生成器代码一样),并在响应中添加公钥并将其发布到我的网站,我的网站将成功验证响应,因为响应本身是正确格式和签名的。这是一个合理的担忧吗?我错过了一些处理这种情况的基本验证?我可以考虑以下选项来降低风险:

  1. 检查URLReferer,并确保SAML响应是从预期实体发布的。我不确定是否有办法操纵URLReferer。

  2. 避免使用响应中存在的公钥来验证摘要值。我可以将X509证书存储在我的端上,并使用它来验证响应。黑客将无法使用相同的证书对响应进行签名,因为他没有私钥。如果这是正确的方式,有人能建议我如何指示"tokenhandler"忽略响应中存在的公钥并使用显式公钥吗?

  3. 有没有一种方法可以让我对IDP进行后端调用,可以调用web服务,并检查我的网站收到的令牌是否确实是由IDP生成的?

由于我是一个新手,我可能会错过基本的SAML验证概念。所以请让我知道我的担忧是否合理。以下是我用来验证响应的示例代码。

public ActionResult SAMLAssert()
    {
        var fam = new WSFederationAuthenticationModule();
        var request = this.HttpContext.Request;
        // Get the security token from the SAML response
        var securityToken = fam.GetSecurityToken(request);
        var config = new SecurityTokenHandlerConfiguration
        {
            CertificateValidator = X509CertificateValidator.None,
            IssuerNameRegistry = new CustomIssuerNameRegistry(),
        };
        config.AudienceRestriction.AudienceMode = AudienceUriMode.Never;
        var tokenHandler = new Saml2SecurityTokenHandler
        {
            CertificateValidator = X509CertificateValidator.None,
            Configuration = config,
        };
        //// validate the token and get the ClaimsIdentity out of it
        var identity = tokenHandler.ValidateToken(securityToken);
        bool isSuccess = identity[0].IsAuthenticated;
        // Code to retrieve the claims/user information from the token
        //....
        return View();
    }

这是自定义的"IssuerNameRegistry"。

public class CustomIssuerNameRegistry : IssuerNameRegistry
    {
        public override string GetIssuerName(SecurityToken securityToken)
        {
            X509SecurityToken x509Token = securityToken as X509SecurityToken;
            return x509Token.Certificate.Subject;
        }

    }

我怀疑自定义类是有问题的部分,因为它没有进行任何验证。

SAML断言/验证如何使用X509公钥

  1. 我认为你不应该检查推荐人的价值。它很容易被欺骗。

  2. IdP使用其私钥对发送给您的响应进行签名。攻击者就是无法访问此私钥。因此,如果攻击者想伪造签名,他需要使用自己的证书并将公钥放入令牌中。虽然验证代码使用嵌入的公钥来验证签名是正确的,但AFAICT还做了一件事:检查公钥是否受我们机器的信任。此处的信任可以通过将公钥添加到您的Windows证书存储->TrustedPeople来建立。虽然我没有所有的代码来验证这一点,但它应该以这种方式工作,或者它应该为您提供一种实现这一点的方法。如果您可以完全控制IdP(嵌入公钥(又名X509Data)的替代方案),则只能使用keyname、使用者名称和指纹。但是,它们提供了多大的安全性以及如何实现都超出了这个问题的范围。

  3. 不,SAML协议并不是这样设计的。最接近这一点的是使用Artifact流,其中IdP只向应用程序返回一个Artifact,它需要向IdP发出ArtifactResolve请求以获得实际响应。请参阅SAML工件的用途是什么?。但您仍然需要验证收到的响应的签名。