PROBLEM
By default, Spring Security SAML’s SAMLBootstrap
uses SHA1withRSA for signature algorithm and SHA-1 for digest algorithm.
@Configuration @EnableWebSecurity public abstract class AppSAMLConfig extends WebSecurityConfigurerAdapter { ... @Bean public static SAMLBootstrap SAMLBootstrap() { return new SAMLBootstrap(); } ... }
For example, the above configuration will generate the following SAML request payload when using HTTP-POST binding:-
<?xml version="1.0" encoding="UTF-8"?> <saml2p:AuthnRequest AssertionConsumerServiceURL="https://server/app/saml/SSO" Destination="https://adfs-server/adfs/ls/" ForceAuthn="true" ID="a3bj4e05i70f6946gi85299i51i02a" IsPassive="false" IssueInstant="2016-02-23T15:10:26.414Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"> <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://server/app/saml/metadata</saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#a3bj4e05i70f6946gi85299i51i02a"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>u25hV7rk8hIpXYLJQs0aZjkueP0=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>YDR9ybi...</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICxz...</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2p:RequestedAuthnContext Comparison="exact"> <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef> </saml2p:RequestedAuthnContext> </saml2p:AuthnRequest>
Unfortunately, SHA-1 is now deemed insecure due to “Freestart Collision” attack.
Further, most modern browsers have ceased to trust SHA-1 code signing certificates starting January 2016 and will eventually stop accepting these certificates by January 2017.
SOLUTION
To fix this, we could replace SHA-1 with stronger secure hash algorithm, such as SHA-256.
To do so, create a class that extends SAMLBootstrap
that uses SHA256withRSA for signature algorithm and SHA-256 for digest algorithm.
public final class CustomSAMLBootstrap extends SAMLBootstrap { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { super.postProcessBeanFactory(beanFactory); BasicSecurityConfiguration config = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration(); config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256); } }
Then, return CustomSAMLBootstrap
instead of SAMLBootstrap
@Configuration @EnableWebSecurity public abstract class AppSAMLConfig extends WebSecurityConfigurerAdapter { ... @Bean public static SAMLBootstrap SAMLBootstrap() { return new CustomSAMLBootstrap(); } ... }
Now, the generated SAML request payload using HTTP-POST binding looks like this:-
<?xml version="1.0" encoding="UTF-8"?> <saml2p:AuthnRequest AssertionConsumerServiceURL="https://server/app/saml/SSO" Destination="https://adfs-server/adfs/ls/" ForceAuthn="true" ID="a2e7f98agfaec7d253714fjdbcf8a83" IsPassive="false" IssueInstant="2016-02-23T15:18:43.452Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"> <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://server/app/saml/metadata</saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#a2e7f98agfaec7d253714fjdbcf8a83"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>w4qHFsBxFGifzemEJCYcuGOt+oZJ9N2DQM+Q2aEqJFI=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>YDR9ybi...</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIICxz...</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml2p:RequestedAuthnContext Comparison="exact"> <saml2:AuthnContextClassRef xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef> </saml2p:RequestedAuthnContext> </saml2p:AuthnRequest>