Fix saml signature verification#4165
Fix saml signature verification#4165ahacker1-securesaml wants to merge 2 commits intodexidp:masterfrom
Conversation
- Ensures return data is parsed solely from signed contents Signed-off-by: Alexander Tan <alex@securesaml.com>
- Get identity from only the signed assertion - Fixes bugs in code Signed-off-by: Alexander Tan <alex@securesaml.com> Signed-off-by: Alexander Tan <alex@securesaml.com>
169ab3c to
faee7bf
Compare
|
@joonas-fi @DemiMarie see: #1884 Can you confirm that this PR meets your expectation of parsing from solely signed contents. Let me know if there are any security improvements. Thanks! |
| // this method returns rootVerified=false to indicate that the <Assertion> | ||
| // elements should be trusted, but all other elements MUST be ignored. | ||
| // unverified, but the sub <Assertion> elements are signed. | ||
| // In these cases, the method returns the assertion, however, the signedResponse will be nil |
There was a problem hiding this comment.
Is it possible to create a response that contains only the assertion, data derived from the assertion, and data not under attacker control?
There was a problem hiding this comment.
In a case where only the assertion is signed like:
<Response InResponseTo="...">
<Assertion><Signature/>
Subject ...
</Assertion>
</Response>What we can tell is signed is the canonical assertion string:
<Assertion>
subject
</Assertion>In that case I just reparse the Assertino node and return it.
I think you're interested in also returning a Response.
In this case, I actually return nil for the Response since we can't tell it's signed. (And further on we don't actually use the Response element, we just process the assertion element)
Previously dexidp, kept the original response ,but then removed all the child elements and replaced them with our signed assertion node.
This is unsafe because you end up with something like
etree {
"rootElement": {
"name": "Response",
"attrs": ["USER CONTROLLED"],
"childElements": [SignedAssertionNode]
},
"directives": ["USER_CONTROLLED"],
"other xml parts": "USERCONTROLLED"
}
When serializing our etree element, the USER_CONTROLLED could round trip and actually become another Assertion node. When reparsing it sees our USER_CONTROLLED data.
So now I don't even bother to return the response if only assertion is signed
There was a problem hiding this comment.
What I meant is to return something like
<Response>
<Assertion>
stuff
</Assertion>
</Response>where no components are attacker controlled.
There was a problem hiding this comment.
Yea, that could work.
However, I think it's simpler if we return (assertion, response) as a pair. It's simpler since the we only need the assertion for obtaining the user identity.
The response element is quite different, and sometimes unsigned. So it's better to separate the two.
|
Hey @jupenur , @ericchiang Also what should we do if no validator is specified. It's quite dangerous behavior to not verify a SAML Response, so for my PR I didn't return any identity. Thanks! |
|
I haven't worked on dex in a long time, so you may want to reach out to one of the existing maintainers for review: https://github.com/dexidp/dex/blob/master/MAINTAINERS |
|
cc @sagikazarmark this resolves a security concern |
Overview
What this PR does / why we need it
Resolves security concerns around: Closes #1884
Previously, the verifyResponseSig returned contents from the original SAML Response document. We must instead return contents from only the signed parts of the document i.e. parts verified with the XML Signature library.
This PR does that.
Special notes for your reviewer
This would break cases where p.validator is nil. i.e. users don't want to verify SAML Response, since we cannot obtain any signed assertion from it.
This would be an insecure and rare use case, as it would allow an attacker to create their own SAML Responses unsigned.
However, I can update the PR if Dex wants to support this use case.