如何验证 HTTP 重定向绑定的 SAML 签名 [英] How to verify a SAML signature for HTTP-redirect binding

查看:68
本文介绍了如何验证 HTTP 重定向绑定的 SAML 签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过 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 =="}

它也有一个签名值

<块引用>

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

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

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

要构造签名,一个由 RelayState 串联组成的字符串(如果存在),SigAlg 和 SAMLRequest(或 SAMLResponse)查询字符串参数(每一个 URLencoded)以下列方式之一构造(按以下顺序排列):SAMLRequest=value&RelayState=value&SigAlg=valueSAMLResponse=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-9210-180-b590-9210-130-130-1000;/samlp:LogoutRequest>

这里有任何帮助.

解决方案

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

封装的 XMLDSign 签名

<...saml 消息...><ds:签名><ds:SignedInfo/><ds:SignatureValue/><ds:KeyInfo/></ds:签名></samlp:LogoutRequest>

包含签名、 签名数据和对消息的引用以及 通常包含带有签名者身份的 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的公钥验证签名与签名的消息匹配,以确保签名者的身份和消息没有被篡改>

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

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

大多数编程语言都支持 XMLDsig 签名,但在您的情况下使用的是 deflated 编码g,这是 SAML 绑定的特定特征,因此如果您的 SAML 库不支持它,您有手动验证签名.根据 规格

//从查询字符串中获取参数String samlrequest = getQueryParam("SAMLRequest");String relaystate = getQueryParam("RelayState");String sigalg = getQueryParam("SigAlg");String signature = getQueryParam("Signature");//签名字节签名[] = URLDecoder.decode(Base64.getDecoder().decode(signature), "UTF-8");//签名数据.构建以下字符串检查 RelayState 是否为空//SAMLRequest=samlrequest&RelayState=relaystate&SigAlg=sigalgbyte signedData[] = concat(samlrequest,relaystate,sigalg);//签名算法可以是SHA1WithRSA"或SHA1withDSA",具体取决于sigalg是http://www.w3.org/2000/09/xmldsig#rsa-sha1或http://www.w3.org/2000/09/xmldsig#dsa-sha1String signatureAlgorithm = extractSignatureAlgorithm(sigalg);//获取SP的公钥.必须在此过程之前注册公钥 publicKey = ...//验证签名签名 sig = Signature.getInstance(signatureAlgorithm);sig.initVerify(publicKey);sig.update(signedData);布尔验证 = sig.verify(signature);

I'm receiving a SAML request via HTTP-redirect binding the content of the SAML request look like this

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

It also has a Signature value

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

But I fail to understand how to verify this signature is correct.

Section 3.4.4.1 on SAML binding 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

I tried the approach but

  • The signature I generated using the Private key does not match to the one I received from my SP. (posted above)

  • Also, I'm not able to decrypt the signed message using the Private key (I'm assuming the Signature was created using the public that I federated it with.)

<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>

Any help here.

解决方案

A SAML authentication message is a XML document with an embedded (enveloped) XMLDSig signature or a deflated encoding signature

Enveloped XMLDSign signature

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

<ds:SignatureValue> contains the signature, <ds:SignedInfo> the signed data and a reference to the message and <ds:KeyInfo> usually contains the X509Certificate with the identity of the signer, or a reference to that certicate

Deflated encoding in URL

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

Where each value is url encoded

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

And the signature is done on a concatenation of query string algorithm using the algorithm SigAlg

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

Digital signature of SAML messages

SAML message is digitally signed (not encrypted) with the private key of the issuer (SP), and can be verified with the public key of the SP. A SAML response must be signed with the private key of the identity provider (IdP), and the SP can verify the message with the public key of the IdP.

If you act as IdP and you want to verify a SAML request of the SP, you need:

  • Verify the digital signature: Verify using the public key of the SP that the signature match with the signed message to ensure the identity of the signer and the message has not been altered

  • Authorize the request: Verify that the identity of the signer can perform the requested operation. Usually you have to match the serial number or the subject of the certificate with a pre-existent list, or verify that the certificate has been issued by a trusted certificate authority

  • Generate the SAML response: Generate a XML message with the SAML data and sign it with your private key to send to SP

Most programming languages support XMLDsig signatures but in your case is used the deflated encoding that is a specific characteristic of SAML binding, so if your SAML library does not support it, you have to verify the signature manually. These are more or less the steps to follow according to 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);  

这篇关于如何验证 HTTP 重定向绑定的 SAML 签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆