-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Security fix 1794. WS server missing Origin validation. #2494
Conversation
tests use the ws library to establish a websocket connection, and they have an undefined origin by default. This is changed tests have no defined hmrHostname so it was set too.
@@ -214,6 +214,7 @@ async function bundle(main, command) { | |||
|
|||
command.throwErrors = false; | |||
command.scopeHoist = command.experimentalScopeHoisting || false; | |||
command.hmrHostname = command.hmrHostname || 'localhost'; |
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 a breaking change, so not sure if this should have a default
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.
Ok, it could go on Bundler.js' normalizeOptions
like this:
hmrHostname:
options.hmrHostname ||
options.host ||
'localhost',
Instead of:
hmrHostname:
options.hmrHostname ||
options.host ||
(options.target === 'electron' ? 'localhost' : ''),
It simplifies the tests as well I think.
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.
That would still be a breaking change, but yes. If you really wanna do it than that would probably be a cleaner solution
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 problem is:
parcel/packages/core/parcel-bundler/src/cli.js
Lines 25 to 28 in c3d99de
.option( | |
'--hmr-hostname <hostname>', | |
'set the hostname of HMR websockets, defaults to location.hostname of current window' | |
) |
It says it defaults to window.location.hostname but this is not true. It is only true, for some var hostname
later in the code, that is used in the client side code for connecting to the websocket server:
var hostname = process.env.HMR_HOSTNAME || location.hostname; |
This default does not reach HMRServer.js (obviously). When the time to check the origin comes, hmrHostname is empty, and the check never takes place. And the check, even if it happened, does nothing, as explained before.
hmrHostname needs to have a default somewhere and normalizeOptions
is the best place. I don't see why it's a breaking change: people using a specified hmrHostname (because they are using some complex setup) will still keep that.
Another option: deprecate hmrHostname like you mentioned in #1794 (comment) and #1482 (comment). The flags host
or hostname
can be used to make the origin check, and as fallback to window.location.hostname in the client.
What do you think ?
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.
Approved this too early, tests are still failing. Please fix them
Closing this as it hasn't been updated in a while and the fix is included in Parcel 2's HMR |
↪️ Pull Request
I believe this PR solves #1783 and amends #1794. I think the merged fix was doing nothing basically (this one --> a1a5422)
It was giving Websocket.Server an
origin
option which is not even accepted by the constructor of Websocket.Server: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callbackThis would mean that this (apparently high) security vulnerability is still present up to the latest version as of now (1.11.0)
I used the proper
verifyClient
hook to check the origin.I also included a default
hmrHostname
oncli.js
since there was nohmrHostname
by default !💻 Examples
localhost:1234
works the same as before. Everything works.example.com
and not localhost.🚨 Test instructions
I adapted about half the HMR tests and they pass.
The other half use the Node
vm
library and I couldn't find a way for this isolated V8 environment to send an origin header with the WebSocket connection. Therefore they fail. I need some help here 😛I used the proof of concept found in this blog to test the fix (before and after): https://blog.cal1.cn/post/Sniffing%20Codes%20in%20Hot%20Module%20Reloading%20Messages. I basically set up a remote server, serving some JS that fetches
http://localhost:1234
and gets the random port number of the websocket server, then connects to it. All the details are in the blog post.Of course the issue with the static assets (where the random port is found, actually) and CORS is still there, and I will look into it next.
✔️ PR Todo