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
add option 'clear' mask #1988
add option 'clear' mask #1988
Conversation
improves client performance while spec compliant
XORing against 0 still mutates? No? I don’t think we can just skip the xoring. |
|
Sorry. Momentary confusion. 😄 |
Sorry, but I'm comfortable with this. Using a fake mask is not spec compliant. It completely defats the point of masking. |
Assuming not comfortable. It's easy enough to fork for special needs @ronag |
Already done. Thanks! |
Too bad uws and ws are on total opposite ends on this. 😞 |
We recently added the ability to skip UTF8 validation (#1928). This is similar. I understand that they might be desirable in a trusted environment but I don't like to keep adding them. It would also open the door for an option to accept unmasked frames on the server. |
|
For this specific use case a possible tradeoff would be to accept a user provided mask. The downside is that we can't skip masking unless we check that all bytes are zero. |
I mean something like this: const mask = Buffer.alloc(4);
ws.send(message, { mask });
ws.send(message, { mask });
ws.send(message, { mask }); |
A user provided mask is probably a good option, you can choose the level of masking you need. If you control all servers and network just use a 0 'clear' mask. If you want mask but don't need high-grade random numbers use Math.random() |
FWIW I think the overhead is not a big problem on the client. I think I've never experienced entropy exhaustion. |
There is literally no reason to use random masks, even less so cryptographically secure masks. That only applies to web browsers running untrusted scripts. Any Node.js client should use the most simple mask, as it literally improves nothing whatsoever in terms of security to use cryptographically secure masks. |
A Node.js server can assume to be secure, but it can send user generated input across the network, if the user knows the mask they can choose the bytes to send. The use case this PR is referring to is for sending from Server to Server across your own network, where there is zero reason for a mask at all, no reason to waste any CPU cycles on your machines generating crypto numbers and masking bits |
Also using SSL is redundant so you can disable masking, might as well make it an option for those who want it |
No. You can't just break spec. because you feel like it. Any message sent from a client without mask is invalid and will be refused. What you can do, and what is still spec. compliant is to use a simple mask like a number that increments by 1 every time. |
This PR uses a clear mask = 0 which allows skipping XOR all bits, or even better allow user supplied mask. Server will still be happy, but you could add a server check to skip unmask on mask = 0, save some CPU cycles |
Yes but the spec says the mask must change with every message. So to hit all the criteria of the spec you can use an incrementing 4 byte integer. That's certainly spec compliant in every single way (for non-web browsers). |
The spec says sufficiently random numbers which means Crypto API, but the Spec is meant for web browsers, this is an option for advanced usage on non-browser, no one is forcing you to follow web browser spec exactly |
Have you looked at the spec at all ? RFC 6455, page 33:
RFC 4086 describes entropy sources as used in Crypto API. The spec is for web browsers to safely implement websockets over cleartext public networks. We are talking about advanced usage for non-browsers over secure or private networks. Your web server will not be affected, it won't know any difference. However if you want to optimize you are welcome to check for mask = 0 to skip unmasking every byte in every message |
Btw, I found this in spec.
So a mask of 0 is indeed allowed. And again,
This goes out the window when net.Socket.write can be accessed to emit literally anything, anyways. |
Might as well add a check on the server to skip unmask for that case, I don't know how much CPU it saves but it is some amount, especially if the client happens to send many of these
I don't think an attacker needs top level script access, they just need to supply the data that gets sent across the network, which a mask can prevent. But literally the only reason there is a mask is to protect broken http proxies that don't understand websocket protocol from a cache poison attack. If you use SSL there is no reason for mask, if you are on local network there is no reason for mask, if you are sending large amounts of messages I think you should have the option of sending a mask = 0, or a user supplied math.random etc |
websockets/ws runs in Node.js (primarily?) so it doesn't matter if it so uses an Uranium based dedicated randomness module from the Greek gods - the fact you have net.Socket.write access entirely circumvents any security whatsoever from randomness. |
@alexhultman I guess running ws in a worker could improve that security part? From the client side. |
The `generateMask` option specifies a function that can be used to generate custom masking keys. Refs: websockets/ws#1986 Refs: websockets/ws#1988 Refs: websockets/ws#1989
There was discussion here #1986 @ronag about disabling mask to improve client performance for cases when mask is not necessary, to stay semi-spec compliant can add option to use a clear mask to skip random number generation and skip XOR on all bits, and a server will not close the connection from a missing mask