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

时间:2016-08-03 14:54:41

标签: 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框架使用web.config设置进行检查)。

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

在高级别,我正在做的是验证令牌:

  1. 从请求中提取安全令牌。
  2. 使用提供的X509公钥(存在于SAML响应中)检查摘要值,验证令牌是否有效且不受影响
    1. 提取用户的声明/身份并允许访问。
  3. 我担心的是,如果黑客创建SAML令牌(比如我自己的令牌生成器代码)并在响应中添加公钥并将其发布到我的网站,我的网站将成功验证响应,因为响应本身已经很好地形成并签字。这是一个有效的问题吗?我缺少一些基本的验证来处理这种情况? 我可以考虑采用以下方案来降低风险:

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

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

    3. 我是否有办法对IDP进行后端呼叫,可以进行网络服务呼叫,并检查我的网站收到的令牌是否确实是由IDP生成的?

    4. 由于我是新手,我可能会错过基本的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;
              }
      
      
          }
      

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

1 个答案:

答案 0 :(得分:2)

  1. 我认为您不应该检查引荐来源值。它很容易被欺骗。

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

  3. 不,SAML协议并未设计为以这种方式工作。最接近这一点的是使用Artifact流,其中IdP仅向您的应用程序返回Artifact,并且它需要向IdP发出ArtifactResolve请求以获取实际响应。见What is the purpose of a SAML Artifact?。但是,您仍然需要验证收到的响应的签名。