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

C# SAML断言/验证如何使用X509公钥,c#,saml-2.0,adfs,x509certificate2,ws-federation,C#,Saml 2.0,Adfs,X509certificate2,Ws Federation,在我的asp.net MVC网站中,我实现了SSO,其中IDP/ADFS发送SAML响应,我验证SAML令牌以允许用户访问网站。我正在使用自定义代码(使用System.IdentityModel.dll和System.IdentityModel.Services.dll库来验证SAML响应和令牌,而不是让.net framework使用web.config设置进行检查) 到目前为止,代码似乎运行良好,但由于我是这个领域的新手,我担心黑客可能会通过正确构造的SAML响应绕过验证。最近我尝试了SAM

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

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

在高级阶段,我正在执行以下操作来验证令牌:

  • 从请求中提取安全令牌
  • 通过使用提供的X509公钥(SAML响应中存在)检查摘要值,验证令牌是否有效且未触及
  • 提取用户的声明/身份并允许访问
  • 我担心的是,如果黑客创建SAML令牌(就像我自己的令牌生成器代码)并在响应中添加公钥并将其发布到我的网站,我的网站将成功验证响应,因为响应本身格式正确且经过签名。这是一个合理的担忧吗?我缺少一些处理此场景的基本验证? 我可以考虑以下选项来降低风险:

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

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

  • 是否有一种方法可以让我对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();
        }
    
    这是“发行人注册”的习俗

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

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

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

  • 不,SAML协议不是这样设计的。最接近这一点的是使用工件流,其中IdP只向应用程序返回工件,它需要向IdP发出工件解析请求以获得实际响应。看见但是,您仍然需要验证接收到的响应的签名

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