如何验证 HTTP 重定向绑定的 SAML 签名

     2023-02-15     174

关键词:

【中文标题】如何验证 HTTP 重定向绑定的 SAML 签名【英文标题】:How to verify a SAML signature for HTTP-redirect binding 【发布时间】:2017-05-18 21:51:17 【问题描述】:

我通过 HTTP 重定向接收 SAML 请求,绑定 SAML 请求的内容如下所示

"SigAlg"=>"http://www.w3.org/2000/09/xmldsig#rsa-sha1", “SAMLRequest”=> “lVLLaoQwFP0VyT5jEqPG4AiFoSDMtNApXXQzxDxaQRObRDqfX3XoolAKXd7DPQ / uuXUQ4zDxo3tzc3zSH7MOMWkPe3DpcixzVVVQl4RBqoiCncEYEmkoY7k00hCQvGgfemf3gOwQSNoQZt3aEIWNC4RwCRGGiD6jkmPMs2KHUPYKksPi0lsRN + Z7jFPgafqpvejtbtQpSK7jYAPfsu3B7C13IvSBWzHqwKPk57vTkS + WfPIuOukG0NSbub9R / yaJELRfzUGzrhmtFut15qdeeheciY926K2u05toUz8sIu0huXd + FPFv9RXpFTTbKp / WA4WobQT / jEYrykwhNaQ66yDNMwY7wijEtMCmysqqo6xOb8Ga + tbjWYe1jtYqfW0uCucoYwWCHS3F0kRGoajWTpAiiJRZJRmu01 + Y3 + CPt2i + AA ==” P>

它也有一个签名值

WkDaGzC6vPTlzh + EnFA5 / 8IMmV7LviyRh2DA5EHF0K0nl + xzBlKfNCYRnunpwoEvGhereGdI5xBpv + mc9IguiCaLZSZjDh6lIDdpvctCnmSNzORqzWQwQGeZ9vjgtCLjUn35VZLNs3WgEqbi2cL + ObrUDS2gV1XvBA3Q3RRhoDmi + XE89Ztnd1cNpR3XdA + EL2ENbMI2XAD9qSgMufUJY / 3GBBpT7Vg1ODtPxBudq + sXrgPh / + + WtUUitLkkfC8tdRTCS1EZPv h27I5g / VNza23Xl8w2HdAuYP0F2FjREo8VV2aUtaOUd / jAF9 + bfkGV93y1PzFttLxdBbFoxp6qBg == P>

但我不明白如何验证此签名是否正确。

第 3.4.4.1 节 SAML 绑定 https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf

To construct the signature, a string consisting of the concatenation of the RelayState (if present),
SigAlg, and SAMLRequest (or SAMLResponse) query string parameters (each one URLencoded)
is constructed in one of the following ways (ordered as below):
SAMLRequest=value&RelayState=value&SigAlg=value
SAMLResponse=value&RelayState=value&SigAlg=value

我尝试了这种方法,但是

我使用私钥生成的签名与我从我的 SP 收到的签名不匹配。 (在上面发布)

另外,我无法使用私钥解密签名的消息(我假设签名是使用我与之联合的公众创建的。)

<samlp:LogoutRequest ID="_36167d94-d868-4c04-aee3-8bbd4ed91317" Version="2.0" IssueInstant="2017-01-05T16:21:55.704Z" Destination="https://werain.me/" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">urn:federation:MicrosoftOnline</Issuer><NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">4948f6ce-4e3b-4538-b284-1461f9379b48</NameID><samlp:SessionIndex>_eafbb730-b590-0134-a918-00d202739c81</samlp:SessionIndex></samlp:LogoutRequest>

这里有任何帮助。

【问题讨论】:

【参考方案1】:

SAML 身份验证消息是具有嵌入(封装)XMLDSig 签名或压缩编码签名的 XML 文档

封装的 XMLDSign 签名

<samlp:LogoutRequest>
    <...saml message...> 
    <ds:Signature>
         <ds:SignedInfo />
         <ds:SignatureValue /> 
         <ds:KeyInfo /> 
    </ds:Signature> 
</samlp:LogoutRequest>

&lt;ds:SignatureValue&gt; 包含签名,&lt;ds:SignedInfo&gt; 包含签名数据和对消息的引用,&lt;ds:KeyInfo&gt; 通常包含带有签名者身份的 X509Certificate,或对该证书的引用

URL 中的压缩编码

SAMLRequest=value&RelayState=value&SigAlg=value&Signature=value

每个值都是 url 编码的

SAMLRequest=urlencode(base64(<samlp:LogoutRequest> <...saml message...> </samlp:LogoutRequest>))

并且签名是在使用算法SigAlg的查询字符串算法的串联上完成的

Signature = urlencode( base64 ( SigAlg ("SAMLRequest=value&RelayState=value&SigAlg=value")))

SAML 消息的数字签名

SAML 消息使用发行者 (SP) 的私钥进行数字签名(未加密),并且可以使用 SP 的公钥进行验证。 SAML 响应必须使用身份提供者 (IdP) 的私钥进行签名,并且 SP 可以使用 IdP 的公钥验证消息。

如果您作为 IdP 并且想要验证 SP 的 SAML 请求,您需要:

验证数字签名:使用SP的公钥验证签名与签名消息是否匹配,确保签名者身份且消息未被篡改 p>

授权请求:验证签名者的身份是否可以执行请求的操作。通常您必须将证书的序列号或主题与预先存在的列表进行匹配,或者验证证书是否由受信任的证书颁发机构颁发

生成 SAML 响应:使用 SAML 数据生成 XML 消息,并使用您的私钥对其进行签名以发送到 SP

大多数编程语言都支持 XMLDsig 签名,但在您的情况下使用的是 deflated encoding,这是 SAML 绑定的特定特征,因此如果您的 SAML 库不支持它,您有手动验证签名。根据specification,这些或多或少是要遵循的步骤

 //get params from query string 
String samlrequest = getQueryParam("SAMLRequest");
String relaystate = getQueryParam("RelayState");
String sigalg = getQueryParam("SigAlg");
String signature = getQueryParam("Signature");


//The signature
byte signature[] = URLDecoder.decode(Base64.getDecoder().decode(signature ), "UTF-8");

//The signed data. build the following string checking if RelayState is null
//SAMLRequest=samlrequest&RelayState=relaystate&SigAlg=sigalg
byte signedData[] = concat(samlrequest,relaystate,sigalg);

//The signature algorithm could be "SHA1WithRSA" or "SHA1withDSA" depending on sigalg is http://www.w3.org/2000/09/xmldsig#rsa-sha1 or http://www.w3.org/2000/09/xmldsig#dsa-sha1 
String signatureAlgorithm = extractSignatureAlgorithm(sigalg);

//get the public key of the SP. It must be registered before this process
PublicKey publicKey = ...

//Verify the signature
Signature sig = Signature.getInstance(signatureAlgorithm);
sig.initVerify(publicKey);
sig.update(signedData); 
boolean verifies = sig.verify(signature);  

【讨论】:

几件事。首先它是LogoutRequest 而不是 SAML AuthRequest(我想我忘了提)。其次,绑定是 HTTP 重定向,而不是 HTTP-POST,请参阅 SAML 绑定的第 3.4.4.1 节。 如果我错了,也请纠正我,但这就是 SAML 签名和验证的正确工作方式。 IDP(拥有自己的公共/私人对)SP(拥有自己的公共/私人对)。如果 IDP 必须对数据进行签名,它会使用自己的私钥对其进行签名。然后,SP 可以使用 IDP 的 Public/cert(通过 IDP 的元数据共享)解密签名数据。同样,如果 SP 必须使用自己的私钥签署数据,则 IDP 使用 SP 的公共/证书对其进行解密(可通过 SP 元数据访问) AuthRequest 只是一个例子。 IdP&SP 的签名模型是正确的。只有术语decrypt 不合适。消息已签名,未加密(内容未隐藏),使用公钥检查的操作为verification 如果我是正确的,您说的是嵌入签名,我从 SP 收到的请求是通过 HTTP 重定向绑定与没有嵌入签名的 SAML 请求的请求。添加了我的 SAML 注销请求的片段。 您的 SAML 注销包括 &lt;samlp:SessionIndex&gt; 以识别要注销的会话,因此在这种情况下,我猜不需要数字签名,因为之前已识别客户端并且拥有 sessionIndex 足以验证请求【参考方案2】:

我正在尝试使用上述答案,但没有成功。

然后,阅读文档并稍等片刻,我已经成功使用 Java 验证签名,快速的答案是:

final String samlRequest = request.getParameter("SAMLRequest");
final String relayState = request.getParameter("RelayState");
final String sigAlg = request.getParameter("SigAlg");
final String signature = request.getParameter("Signature");

FileInputStream fis = new FileInputStream(new File("path-to-service-provider-x509-certificate"));

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(fis);

// ps: java.net.URLEncoder;
String query = "SAMLRequest=" + URLEncoder.encode(samlRequest, "UTF-8");
query += "&RelayState=" +URLEncoder.encode(relayState, "UTF-8");
query += "&SigAlg=" + URLEncoder.encode(sigAlg, "UTF-8");

// ps: org.opensaml.xml.util.Base64
byte[] signatureBytes = Base64.decode(signature);

org.apache.xml.security.Init.init();
Signature sig = Signature.getInstance("SHA1withRSA"); // or other alg (i, e: SHA256WithRSA or others)
sig.initVerify(cert.getPublicKey());
sig.update(query.getBytes());
Boolean valid = sig.verify(signatureBytes);

【讨论】:

什么教程?你能编辑你的答案并给出更好的解释吗? @MehdiBounya 正确的术语是“回答”没有教程。【参考方案3】:

我想在上述答案中补充一点:URL 编码/解码是非规范的,这意味着每种框架/语言可能实际上都有不同的处理方式。我被困在验证 HTTP-Redirect 绑定很多天了,结果发现我们使用的 Java Play 1.x 框架以不同于 SAML 框架预期的方式对事物进行解码。

我们解决了这个问题,而是直接从查询字符串中取出查询参数,而不是让 Play 框架为我们解码(只是我们需要重新编码)。因此,如果您的代码与 Alexandre 的代码匹配,但 SAML 框架说签名无效,请确保您将 直接 从 URL GET 参数中获取的字符串输入算法。

【讨论】:

【参考方案4】:

根据绑定(POST 或重定向)不同,验证 SAML 2.0 签名的方式也不同。如果使用 POST 绑定,则在 SAML XML 中验证签名。如果使用重定向绑定,则查询字符串会使用签名进行验证。

此 LogoutRequest 使用重定向绑定发送。 以下 C# 示例代码是从 ITfoxtec.Identity.Saml2 组件复制而来的,并展示了如何验证签名。

var queryString = request.QueryString;
var signatureValue = Convert.FromBase64String(request.Query["Signature"]);

var messageName = "SAMLRequest";
var signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
var signatureValidationCertificate = new X509Certificate2("path-to-service-provider-x509-certificate");

var saml2Sign = new Saml2SignedText(signatureValidationCertificate, signatureAlgorithm);
if (saml2Sign.CheckSignature(Encoding.UTF8.GetBytes(new RawSaml2QueryString(queryString, messageName).SignedQueryString), signatureValue))

    // Signature is valid.

else

    throw new InvalidSignatureException("Signature is invalid.");

从Saml2RedirectBinding复制的代码 RawSaml2QueryString Saml2SignedText

【讨论】:

【参考方案5】:

对于那些仍然卡住的人,这里是完整的方法

public static void verifySignature(boolean isResponse, String samlQueryString, String relayStateString, String sigAlgString, String signature, X509Certificate cert) throws Exception 
    String type = isResponse ? "SAMLResponse" : "SAMLRequest";

    String query = type + "=" + URLEncoder.encode(samlQueryString, "UTF-8");
        query += relayStateString == null ? "" : "&RelayState=" + URLEncoder.encode(relayStateString, "UTF-8");
        query += "&SigAlg=" + URLEncoder.encode(sigAlgString, "UTF-8");

    String javaSigAlgName = null;

    if(sigAlgString.equals("http://www.w3.org/2000/09/xmldsig#rsa-sha1")) 
        javaSigAlgName = "SHA1withRSA";
     else if(sigAlgString.equals("http://www.w3.org/2000/09/xmldsig#rsa-sha256")) 
        javaSigAlgName = "SHA256withRSA";
     else 
        throw new Exception("signature: " + sigAlgString + " not supported by SP/IDP");
    

    byte[] signatureBytes = Base64.getDecoder().decode(signature);

    Signature sig = Signature.getInstance(javaSigAlgName);
    sig.initVerify(cert.getPublicKey());
    sig.update(query.getBytes());

    Boolean valid = sig.verify(signatureBytes);
    System.out.println("is valid: " + valid);

【讨论】:

【参考方案6】:

我们可以使用one login saml library 来验证 auth-request 签名。他们为 SAML 提供了很多包装方法。这是它的 ruby​​ 实现。 `

def verify_signature(params)
    saml_request = URI.decode(params[:SAMLRequest])
    relay_state_string = URI.decode(params[:RelayState])
    signature = URI.decode(params[:Signature])
    sign_alg = URI.decode(params[:SigAlg])
    query_params,sig_params=,
    query_params[:type] = "SAMLRequest"
    query_params[:data] = saml_request
    query_params[:relay_state] = relay_state_string
    query_params[:sig_alg] = sign_alg
    query = OneLogin::RubySaml::Utils.build_query(query_params)
    sig_params[:cert] = getPublicKeyFromCertificate
    sig_params[:sig_alg] = sign_alg
    sig_params[:signature] = signature
    sig_params[:query_string] = query
    OneLogin::RubySaml::Utils.verify_signature(sig_params)
end

`

【讨论】:

使用 Java 创建“HTTP 重定向绑定”SAML 请求

】使用Java创建“HTTP重定向绑定”SAML请求【英文标题】:Create\'HTTPRedirectBinding\'SAMLRequestusingJava【发布时间】:2014-12-1613:47:23【问题描述】:我正在尝试在Java中为SAMLHTTP重定向绑定实现相同的算法,如下所述:HowdoIcorrectlypreparean\'... 查看详情

如何正确解码 Java 中的 SAML 请求(HTTP 重定向)?

】如何正确解码Java中的SAML请求(HTTP重定向)?【英文标题】:HowcanIproperlydecodeaSAMLrequestinJava(HTTPredirect)?【发布时间】:2020-07-0305:29:50【问题描述】:我正在使用HTTP重定向绑定处理SAML请求。我在另一篇文章中读到,需要执行以... 查看详情

SAML HTTP 重定向绑定中未保留查询字符串

】SAMLHTTP重定向绑定中未保留查询字符串【英文标题】:QuerystringnotpreservedinSAMLHTTPRedirectbinding【发布时间】:2015-09-1622:17:16【问题描述】:我们使用SpringSAML安全扩展在我们的应用程序中实现SAML。我们现在有以下问题:我们的一... 查看详情

AADSTS750054:SAMLRequest 或 SAMLResponse 必须作为查询字符串参数出现在 SAML 重定向绑定的 HTTP 请求中

...SAMLRequest或SAMLResponse必须作为查询字符串参数出现在SAML重定向绑定的HTTP请求中【英文标题】:AADSTS750054:SAMLRequestorSAMLResponsemustbepresentasquerystringparametersinHTTPrequestforSAMLRedirectbinding【发布时间】:2021-05-1803:39:08【问题描述】:请告... 查看详情

单一登录(saml协议)

...)配置文件。 若要请求AzureActiveDirectory对用户进行身份验证时,云服务(服务提供商)必须使用HTTP重定向绑定传递 AuthnRequest (身份验证请求)与AzureActiveDirectory(标识提供者)的元素。 AzureActiveDire 查看详情

在 ELB 后面使用带有 Spring Boot 的 SAML 重定向到 http 而不是 https

...正在尝试使用Okta对来自SpringBoot应用程序的用户进行身份验证。我已经按照Okta教程设置了应用程序:https://developer.o 查看详情

如何在 itfoxtec 中支持工件绑定?

】如何在itfoxtec中支持工件绑定?【英文标题】:Howtosupportartifactbindinginitfoxtec?【发布时间】:2019-07-2821:47:31【问题描述】:我们正在使用ITFoxTec库进行saml身份验证。目前我们支持两种类型的binging。Http重定向Http-Post现在我们想将... 查看详情

Spring saml 将请求重定向到 http

】Springsaml将请求重定向到http【英文标题】:Springsamlredirectstherequesttohttp【发布时间】:2015-09-2706:41:15【问题描述】:我正在使用带有Apache2.2+Tomcat7.0+OKTA(IdP)的springsaml扩展。securityContext.xml如下所示:元数据生成器过滤器:<beanid... 查看详情

使用基于 SAML 的基本身份验证进行身份验证?

】使用基于SAML的基本身份验证进行身份验证?【英文标题】:AuthenticateusingSAML-basedBasicAuthentication?【发布时间】:2015-08-1219:55:40【问题描述】:我有一个用例,其中Web应用程序需要让用户以两种不同的方式进行身份验证,但通过... 查看详情

重定向到带有 SAML 响应的回调 url 时出现错误无法以角度发布

...0:16【问题描述】:我在我的Angular应用程序中使用SAML身份验证,该应用程序将托管在AWS上。我正在使用角度代码作为单独的项目,并且代码是在不同的项目中编写的。我在 查看详情

成功认证后的 Spring-SAML 无休止的重定向循环

】成功认证后的Spring-SAML无休止的重定向循环【英文标题】:Spring-SAMLEndlessredirectloopafterasuccessfulauthentication【发布时间】:2018-07-2305:50:36【问题描述】:SAML认证成功后:AuthNRequest;SUCCESS;0:0:0:0:0:0:0:1;https://localhost:8443/saml/metadata;http... 查看详情

Spring SAML Okta - 如何在 IDP 启动的流程中重定向到自定义 URL

】SpringSAMLOkta-如何在IDP启动的流程中重定向到自定义URL【英文标题】:SpringSAMLOkta-HowtoredirecttoacustomURLinIDPinitiatedflow【发布时间】:2018-07-2110:39:54【问题描述】:我的应用程序的入口点是一个自定义URL,我如何告诉Spring在SAML舞蹈... 查看详情

OneLogin 签名的 Authnrequest HTTP 重定向方法

】OneLogin签名的AuthnrequestHTTP重定向方法【英文标题】:OneLoginSignedAuthnrequestHTTP-RedirectMethod【发布时间】:2019-07-1620:07:49【问题描述】:从我发现OneLogin测试连接器默认情况下不需要签名的Authnrequest。使用HTTP-Redirect进行的Authnrequest... 查看详情

Spring Security SAML,使用 SAMLContextProviderLB 设置为 HTTPs 方案时重定向到 HTTP 而不是 HTTPS

】SpringSecuritySAML,使用SAMLContextProviderLB设置为HTTPs方案时重定向到HTTP而不是HTTPS【英文标题】:SpringSecuritySAML,RedirectsgoingtoHTTPinsteadofHTTPSwhenusingSAMLContextProviderLBsettoHTTPsscheme【发布时间】:2016-06-2118:04:02【问题描述】:为SAMLContext 查看详情

护照 Saml Loop

...站时,我被正确重定向到我的ADFS门户。ADFS门户,在身份验证后正确重定向到回调。然后是回调循环。Chromeconsolewhenit\'slooping我的路线(server.js) 查看详情

ADFS 2.0 中的 SAML 2 签名错误

...向)之间建立通信时,ADFS2.0抛出以下错误。SAML消息签名验证失败。消息发布者: 查看详情

验证 SAML 消息时出错

】验证SAML消息时出错【英文标题】:ErrorvalidatingSAMLmessage【发布时间】:2016-05-3017:53:59【问题描述】:我正在尝试JavaTomcatSAML的Okta快速入门,我对这个主题非常陌生。当我启动我的测试应用程序时,我确实看到了一个指向OktaIDP... 查看详情

如何将用户重定向到身份验证对话框?

】如何将用户重定向到身份验证对话框?【英文标题】:HowtoredirectausertoAuthDialog?【发布时间】:2011-11-1816:45:44【问题描述】:我按照步骤here而且我的应用程序不会重定向用户$app_id=APP_ID;$canvas_page=APP_LINK;$auth_url="http://www.facebook.co... 查看详情