-
Notifications
You must be signed in to change notification settings - Fork 13
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
fix: insecure iframe messaging #297
base: master
Are you sure you want to change the base?
Conversation
@@ -46,7 +47,7 @@ class PostMessageIframeTransport extends Transport { | |||
const prom = this.transportRequestManager.addRequest(data, null); | |||
const notifications = getNotifications(data); | |||
if (this.frame) { | |||
this.frame.postMessage((data as IJSONRPCData).request, "*"); | |||
this.frame.postMessage((data as IJSONRPCData).request, this.uri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.frame.postMessage((data as IJSONRPCData).request, this.uri); | |
this.frame.postMessage((data as IJSONRPCData).request, this.origin); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the origin can easily be derived as new URL(this.uri).origin
We don't need another parameter from ctor
@@ -28,7 +28,8 @@ class PostMessageIframeTransport extends Transport { | |||
}); | |||
} | |||
private messageHandler = (ev: MessageEvent) => { | |||
this.transportRequestManager.resolveResponse(JSON.stringify(ev.data)); | |||
if (ev.origin === this.uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ev.origin === this.uri) | |
if (ev.origin === this.origin) |
@@ -36,7 +36,8 @@ class PostMessageTransport extends Transport { | |||
} | |||
|
|||
private messageHandler = (ev: MessageEvent) => { | |||
this.transportRequestManager.resolveResponse(JSON.stringify(ev.data)); | |||
if (ev.origin === this.uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ev.origin === this.uri) | |
if (ev.origin === this.origin || ev.orgin === "*") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes look good, there is an issue, I added some suggestions for adding origin
so the constructor should be
constructor(uri: string, origin: string) {
this.orgin = origin
...
We're debating a little if this should be a breaking change, because it's probably better to take this away, vs let it persist. You can still do star this way, but you have to set it explicitly.
This was awesome patch it up and I'll be excited to merge this in, nice find!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accidental approval in this state just requesting changes that were listed before
Pls check my changes. |
The suggestion for a parameter is so users can define what urls they want to accept request from. Locking people into request coming from the same url origin, makes the api not flexible enough. We can't universally make that assumption about the context in which client-js is operating in. |
@@ -5,10 +5,12 @@ class PostMessageIframeTransport extends Transport { | |||
public uri: string; | |||
public frame: undefined | null | Window; | |||
public postMessageID: string; | |||
public origin: string; | |||
|
|||
constructor(uri: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we'll still need the origin to come from the constructor here. We have to leave the origin to be specified by the consumers here, by passing it into the constructor. This is because we can't make an assumption about where they'd like the post message communication to come from.
In a dev case for instance they may want *, in a cross domain case they may want the origin to come from a window they launched that has a separate domain they know. If we lock them in it takes away the choice.
The default to * after speaking with @shanejonas we both feel like the security change warrants a version that makes people explicitly state *, so they know what assumptions they're making about the transport.
The pr looks great, and thanks for the questions and comments and getting this done!
I've made the necessary changes |
@@ -28,7 +30,8 @@ class PostMessageIframeTransport extends Transport { | |||
}); | |||
} | |||
private messageHandler = (ev: MessageEvent) => { | |||
this.transportRequestManager.resolveResponse(JSON.stringify(ev.data)); | |||
if (ev.origin === this.origin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ev.origin === this.origin) | |
if (ev.orgin === this.origin || ev.origin === "*") |
super(); | ||
this.uri = uri; | ||
this.origin = origin || new URL(uri).origin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome thanks for doing this. The only thing here is that we're going to opt for a breaking change here.
We're going to rm the default, because defaulting to origin can be a hidden breaking change to people using this in prod.
We'll do a maj. verson bump which will force people to explicitly update their clients to set what domain they'd like to use this against, when using postmessage transport.
Once this lands the team will bump the versions of generator and any other ecosystem consumers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.origin = origin || new URL(uri).origin; | |
this.origin = origin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit message for these changes should be in the following format for semantic release
fix: patch security hole for post message iframe transport. this change forces consumers to
explicitly set the transport's acceptable origins. Improving the security using the transport.
BREAKING CHANGE: transport now takes second argument and requires origin be set for filtering
post message request.
|
||
constructor(uri: string) { | ||
constructor(uri: string, origin?: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constructor(uri: string, origin?: string) { | |
constructor(uri: string, origin: string) { |
@@ -36,7 +38,8 @@ class PostMessageTransport extends Transport { | |||
} | |||
|
|||
private messageHandler = (ev: MessageEvent) => { | |||
this.transportRequestManager.resolveResponse(JSON.stringify(ev.data)); | |||
if (ev.origin === this.origin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ev.origin === this.origin) | |
if (ev.origin === this.origin || ev.origin === "*") |
@chaitanyapotti Thank you for the PR and issue! nice work! Are you able to finish this one off? Happy to help get it through. |
@zcstarr perhaps you have some time to cherrypick his commits and make the required changes? |
Fixes #296