-
Notifications
You must be signed in to change notification settings - Fork 190
Adjust deprecation to better reflect real-world usage #498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
0e0dc85
9899fcd
fd36c19
c5657f6
156fde7
04bb79e
9ac1547
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -323,6 +323,7 @@ export class SignedXml { | |
| valid(ated). Put simply: if one fails, they are all not trustworthy. | ||
| */ | ||
| this.signedReferences = []; | ||
| // TODO: add this break change here later on for even more security: `this.references = [];` | ||
| if (callback) { | ||
| callback(new Error("Could not validate all references"), false); | ||
| return; | ||
|
|
@@ -357,6 +358,7 @@ export class SignedXml { | |
| // but that may cause some breaking changes, so we'll handle that in v7.x. | ||
| // If we were validating `signedInfoCanon` first, we wouldn't have to reset this array. | ||
| this.signedReferences = []; | ||
| // TODO: add this break change here later on for even more security: `this.references = [];` | ||
|
|
||
| if (callback) { | ||
| callback( | ||
|
|
@@ -539,14 +541,14 @@ export class SignedXml { | |
| } | ||
| } | ||
|
|
||
| ref.getValidatedNode = (xpathSelector?: string) => { | ||
| ref.getValidatedNode = deprecate((xpathSelector?: string) => { | ||
| xpathSelector = xpathSelector || ref.xpath; | ||
| if (typeof xpathSelector !== "string" || ref.validationError != null) { | ||
| return null; | ||
| } | ||
| const selectedValue = xpath.select1(xpathSelector, doc); | ||
| return isDomNode.isNodeLike(selectedValue) ? selectedValue : null; | ||
| }; | ||
| }, "`ref.getValidatedNode()` is deprecated and insecure. Use `ref.signedReference` or `this.getSignedReferences()` instead."); | ||
|
|
||
| if (!isDomNode.isNodeLike(elem)) { | ||
| const validationError = new Error( | ||
|
|
@@ -573,6 +575,7 @@ export class SignedXml { | |
| // thus the `canonXml` and _only_ the `canonXml` can be trusted. | ||
| // Append this to `signedReferences`. | ||
| this.signedReferences.push(canonXml); | ||
| ref.signedReference = canonXml; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No one will even bother using the API here. Better to clearly warn the user that the entire reference object is contaminated and shift to using the new API which I already designed and spent efforts into making it secure.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the entire reference object is contaminated then your suggested code over at This is a super small change that literally takes the exact same data and puts in on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't use what is inside the getReferences() Data for processing, I only use it for some spurious validation checks. You can see in my change, only the data from getSignedReferences() is processed for SAML assertions.
This is a change that doesn't benefit the users of xml-crypto at all. it takes time to review, could possible contain security defects. Your change doesn't warn users against how they current verify XML Signatures: const uri = sig.getReferences()[0].uri; // might not be 0; it depends on the document
const id = uri[0] === "#" ? uri.substring(1) : uri;And they will not get a deprecation warning of their insecure behavior. What we should be focusing on is getting the SAML Libraries to start using the new APIs. The current code that I wrote is secure, future changes will (even small), are just an annoyance and take time to review. Remember, we can always leave discussions in V7. Now is not the time
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to ship a Your referenced example about checking the ID will still cause a deprecation warning because just a few lines below that is this: https://github.com/node-saml/xml-crypto/tree/v6.0.0#:~:text=const%20elem%20%3D%20sig.references%5B0%5D.getvalidatedelement() const elem = sig.references[0].getValidatedElement()That is now a deprecated function due this this PR. So, users, like you did in your change in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Agreed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should just keep all the signedReferences in 1 place, instead of maintaining 2 separate places.
Now previous API: This isolates the signed data into one place. new API: Insecure because the getReferences() each Reference object is garbage. We are mixing signed and unsigned data. it's a very difficult security boundary to enforce.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ahacker1-securesaml , I'm very confused by your back and forth on this. If I take @srd90 's point about validation and signing. @srd90 has been a valued, cooperative, helpful, long-time watchful eye over these projects and has helped us all immeasurably to keep this code functioning as best we can and to help us to understand many things related to security along the way. No one maintintaing this project gets paid to do this work; there is no corporate sponsor. I don't understand how looking at an ID is insecure in any way. Please elaborate on how the ID is insecure @ahacker1-securesaml . I also don't understand how to find the reference that I'm after without some additional metadata, which is what
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Thank you @srd90 . You can see from my comment I thought something might need to be done here, but I stopped short of a secure solution. Please have a look at #500 to see if that addresses the concern. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
IMHO that change "rolls back" filled There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I never propose to use the API. I only keep using the getReferences() API to throw error messages, i.e. never do any security checks based off of it. I.e. because some test cases and some integrators will depend on the error messages given. To make those error messages I have to get use the Reference ID. But stricly speaking, look at the PR contents, I only use the contents from getSignedReferences(). Try to follow the logic behind the changed. Remove our usage of getReferences() and my program is still secure.
Can't you just do .getSignedReferences() exist as well. The ID is not really relavant for anything. I also don't understand how to find the reference that I'm after without some additional metadata, which is what getReferences() provides. Thus, the thinking was to provide the validated XML along with the metadata. If I did so incorrectly, which it appears I have, I'll pull forward the changes the I marked at TODO for v7 and call it a security fix in a 6.2 release. If it is unsigned, that is one thing; it can stay. If it fails a signature check, then it should be removed along with all other data because something corrupting has happened and we don't want to trust anything. getReferences() currently provides an URI or ID attribute (i.e. additional metadata). The ID attribute is a random string which is irrelavant, and shouldn't be used for security decisions. I think this is a fundamental misconception. You should never go back into the original document, because the original document is attacker controlled. If you use the ID to drive security, then you would have to use the original document, thus your system would be using untrusted data. For example, you might do something like originalDocument.getElementByID("referenceID"). This is useless, since the orignal document is attacker controlled. I.e. since only parts of it is signed. Instead what users MUST do is use the contents from getSignedReferences() API, which is isolated from the original document, and contains only signed data. Please give a counterexample, where you cannot use getSignedReferences() but can only use getReferences().
You should ask for more funding. Your package handles security for the largest websites. It's immoral and unethical to be maintaining a package without funding - it makes supply chain attacks easier and increases code software vulnerabilities (i.e. no code auditing). |
||
|
|
||
| return true; | ||
| } | ||
|
|
@@ -821,13 +824,18 @@ export class SignedXml { | |
| } | ||
|
|
||
| /** | ||
| * @deprecated Use `.getSignedReferences()` instead. | ||
| * Returns the list of references. | ||
| */ | ||
| getReferences = deprecate( | ||
| () => this.references, | ||
| "getReferences() is deprecated. Use `.getSignedReferences()` instead.", | ||
| ); | ||
| getReferences() { | ||
| // TODO: Refactor once `getValidatedNode` is removed | ||
| /* Once we completely remove the deprecated `getValidatedNode()` method, | ||
| we can change this to return a clone to prevent accidental mutations, | ||
| e.g.: | ||
| return [...this.references]; | ||
| */ | ||
|
|
||
| return this.references; | ||
| } | ||
|
|
||
| getSignedReferences() { | ||
| return [...this.signedReferences]; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.