Skip to content
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

http: setEncoding error for incoming packets #18178

Closed
wants to merge 2 commits into from
Closed

http: setEncoding error for incoming packets #18178

wants to merge 2 commits into from

Conversation

iSkore
Copy link
Contributor

@iSkore iSkore commented Jan 16, 2018

added wrapping on socket.setEncoding to not allow encoding changes
on incoming packets.

Because HTTP must be in US-ASCII, this function should either not
be allowed, or should throw a standard stackTrace error if invoked
on an incoming packet.

Currently, the process encounters a fatal v8 error and crashes.
error report detailed in: issue #18118

Fixes: #18118

Ref: #19344

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)
  • _http_server (specifically: connectionListenerInternal method -> socket variable)

@nodejs-github-bot nodejs-github-bot added the http Issues or PRs related to the http subsystem. label Jan 16, 2018
@addaleax
Copy link
Member

I don’t think ascii should be allowed either; that would still give the assertion failure from the linked issue, right?

@jasnell
Copy link
Member

jasnell commented Jan 17, 2018

hmm... yeah, I think what we'd want is to just eliminate the ability to setEncoding on these sockets entirely.

@iSkore
Copy link
Contributor Author

iSkore commented Jan 18, 2018

@jasnell: Yes, setting the encoding on incoming packets (for HTTP based transactions) should not be allowed. Setting the encoding on outgoing packets could be allowed (?) but I can't think of a practical use case. Nevertheless, any HTTP response should not allow other encodings.
Ref: RFC20
Ref: RFC2616

@addaleax: yup, the linked issue is a the result of setting the encoding on incoming packets transferred via HTTP. Incoming HTTP packets have to be ascii encoded already. Not sure why, but running setEncoding( 'ascii' ) results in the same failure. Redacting setEncoding is probably the best solution for the http/https subsystem.

@addaleax
Copy link
Member

Not sure why, but running setEncoding( 'ascii' ) results in the same failure.

Because setEncoding('ascii') still makes the stream emit strings, not buffers, and the parser is expecting buffers -- that's all, I think.

@iSkore
Copy link
Contributor Author

iSkore commented Jan 18, 2018

Ah, that makes since. I see that now in the http_parser.c file - this pull request is broken.
How would you approach solving this issue?

Because http extends net, should setEncoding not be inherited? As in "deleted" at the point where http inherits net? (seems hacky to me)

Or should it be removed from the net module as well?

Or perhaps just overriding the setEncoding method to throw an error if used?

socket.setEncoding = undefined;

Should throw a TypeError TypeError: socket.setEncoding is not a function

Ref: RFC20 suggests that all network transactions should be in ascii. But, perhaps there are considerations for other protocol's, maybe someone wants to make a "custom" protocol that sends utf8 or something like that.

@jasnell
Copy link
Member

jasnell commented Jan 18, 2018

The method should be overridden to throw.

@jasnell
Copy link
Member

jasnell commented Jan 18, 2018

Forcing the socket data to ASCII is definitely not the right thing to do. With http, for instance, while the protocol bits themselves are generally ascii, the payload data typically is not. Forcing the socket to always ascii would result in data corruption. The best thing here is to simply require the socket to use buffers and let the bits that handle the parsing for specific bits to deal with the encoding.

@iSkore
Copy link
Contributor Author

iSkore commented Jan 18, 2018

@jasnell @addaleax per this discussion, I updated the setEncoding method to be undefined in the incoming packet handler connectionListenerInternal

@addaleax
Copy link
Member

The method should be overridden to throw.

+1, I agree that’s the right thing to do here.

@iSkore could you also make sure that this interacts well with Connection: upgrade? It’s not obvious to me whether that case is affected, but you should be able to set .setEncoding() after a protocol switch.

@iSkore
Copy link
Contributor Author

iSkore commented Jan 18, 2018

@addaleax - do you think this fix would be in the _http_server.js method or should I go into the parsing handlers in the _http_common.js? Still figuring out where things are, but I've narrowed it down to the onParserExecute method. I'm having an issue with detecting if it's an upgrade request before the execute function is invoked on line 377

So my first thought was to check if the headers are requesting an upgrade, if not, override the setEncoding method. But I can't see if it's an upgrade until the onParserExecuteCommon - but it breaks before the first line in that method is called because parser.consume(external); is running first.

Any pointers on what file(s) I should focus on to fix this?

@jasnell
Copy link
Member

jasnell commented Jan 18, 2018

@iSkore ... rather than setting setEncoding to undefined, it should be something like...

  1. first, create a new top level function to avoid creating a closure:
function socketSetEncoding() {
  throw new errors.Error('ERR_METHOD_NOT_IMPLEMENTED',
                         'setEncoding');
}
  1. then....
socket.setEncoding = socketSetEncoding;
  1. if/when the socket instance is ever released by the http implementation, the original setEncoding implementation should be restored, if possible.

@iSkore
Copy link
Contributor Author

iSkore commented Jan 18, 2018

Upon further research, I'm seeing that any encoding changes should not be allowed.

RFC6455 Section 10.7

A common class of security problems arises when sending text data
using the wrong encoding. This protocol specifies that messages with
a Text data type (as opposed to Binary or other types) contain UTF-8-
encoded data. Although the length is still indicated and
applications implementing this protocol should use the length to
determine where the frame actually ends, sending data in an improper
encoding may still break assumptions that applications built on top
of this protocol may make, leading to anything from misinterpretation
of data to loss of data or potential security bugs.

I interpret this as a fairly generic statement (compared to other RFC literature) suggesting that it should not be allowed at all:

leading to anything from misinterpretation of data to loss of data or potential security bugs.

For the language as a whole, particularly the net module, I can see this being too strict - but for the scope of HTTP, it's a relevant concern.

@BridgeAR
Copy link
Member

BridgeAR commented Feb 1, 2018

@iSkore would you be so kind and change the implementation accordingly to @jasnell s suggestion? And adding a test case that would normally result in a crash would be awesome.

As far as I see it, it should not matter if there is a upgrade is used or not but I did not look into that closely to be sure.

@iSkore
Copy link
Contributor Author

iSkore commented Feb 1, 2018

@BridgeAR - Yup, the crash report is detailed in #18118
Should I add a test to the test/async-hooks/test-httpparser.response.js file?

@BridgeAR
Copy link
Member

BridgeAR commented Feb 2, 2018

@iSkore this has nothing to do with async-hooks, so it should be in test/parallel/test-http*.js. I am not sure if there is a good file to add another test to but it is probably also fine to create a new one.

added override to socket.setEncoding to not allow encoding changes for
incoming HTTP requests
added tests to ensure method throws JavaScript error
because an HTTP buffer must be in US-ASCII, this function should not
be allowed and should throw an Error
currently, the process encounters a fatal v8 error and crashes

error report detailed in
[issue #18118](#18118)

Fixes: #18118
Ref: #18178
added override to socket.setEncoding to not allow encoding changes for
incoming HTTP requests
added tests to ensure method throws JavaScript error
because an HTTP buffer must be in US-ASCII, this function should not
be allowed and should throw an Error
currently, the process encounters a fatal v8 error and crashes

error report detailed in
[issue #18118](#18118)

Fixes: #18118
Ref: #18178
Copy link
Contributor Author

@iSkore iSkore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added setEncoding override error and tests

@iSkore
Copy link
Contributor Author

iSkore commented Feb 4, 2018

@BridgeAR - should the Net module documentation be edited in someway to say "this method can only be used for response encodings?

@BridgeAR
Copy link
Member

@iSkore I do not have a strong opinion. But maybe someone else might say something about that.

@BridgeAR
Copy link
Member

Ping @nodejs/http @nodejs/http2 PTAL

iSkore added a commit to iSkore/node that referenced this pull request Apr 3, 2018
added override to socket.setEncoding to not allow encoding changes for
incoming HTTP requests
added tests to ensure method throws JavaScript error
because an HTTP buffer must be in US-ASCII, this function should not
be allowed and should throw an Error
currently, the process encounters a fatal v8 error and crashes

error report detailed in
[issue nodejs#18118](nodejs#18118)

Fixes: nodejs#18118
Ref: nodejs#18178
iSkore added a commit to iSkore/node that referenced this pull request Apr 3, 2018
added test to ensure setEncoding inside socket connection
would throw an error

Fixes: nodejs#18118
Ref: nodejs#18178
iSkore added a commit to iSkore/node that referenced this pull request Apr 3, 2018
added ERR_HTTP_INCOMING_SOCKET_ENCODING error and error docs
throw ERR_HTTP_INCOMING_SOCKET_ENCODING error when incoming request
socket encoding is manipulated

error report detailed in nodejs#18118

Fixes: nodejs#18118
Ref: nodejs#18178
iSkore added a commit to iSkore/node that referenced this pull request Apr 3, 2018
added note and link to RFC7230

>A recipient MUST parse an HTTP message as a sequence of octets in an
encoding that is a superset of US-ASCII [USASCII].

Ref: https://tools.ietf.org/html/rfc7230#section-3

Ref: nodejs#18118
Ref: nodejs#18178
Ref: nodejs#19344
iSkore added a commit to iSkore/node that referenced this pull request Apr 3, 2018
iSkore added a commit to iSkore/node that referenced this pull request May 14, 2020
applied updates from previous pull-requests to disallow
socket.setEncoding before a http connection is parsed.
wrapped socket.setEncoding to throw an error.
previously resulted in a fatal error

Fixes: nodejs#18118
Ref: nodejs#18178
Ref: nodejs#19344
BridgeAR pushed a commit to BridgeAR/node that referenced this pull request May 23, 2020
Applied updates from previous pull-requests to disallow
socket.setEncoding before a http connection is parsed.
Wrapped `socket.setEncoding` to throw an error.
This previously resulted in a fatal error.

PR-URL: nodejs#33405
Fixes: nodejs#18118
Refs: nodejs#18178
Refs: nodejs#19344
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fatal error when attempting to (wrongly) set incoming packet encoding
10 participants