4

When implementing Server Sent Events on your application server, you can terminate a message and have it send by ending it with two line breaks: \n\n, as demonstrated on this documentation page.

So, what if you're receiving user input and forwarding it to all interested parties (as is typical in a chat application)? Could a malicious user not insert two line breaks in their payload to terminate the message early? Even more, could they not then set special fields such as the id and retry fields, now that they have access to the first characters of a line?

It seems that the only alternative is to instead scan their entire payload, and then replace instances of \n with something like \ndata:, such that their entire message payload has to maintain its position in the data tag.

However, is this not very inefficient? Having to scan the entire message payload for each message and then potentially do replacements involves not only scanning each entire payload, but also reallocating in the case of maleficence.

Or is there an alternative? I'm currently trying to decide between websockets and SSE, as they are quite similar, and this issue is making me learn more towards WebSockets, because it feels as if they would be more efficient if they are able to avoid this potential vulnerability.

Edit: To clarify, I'm mostly ignorant as to whether or not there is a way around having to scan each message in its entirety for \n\n. And if not, does WebSockets have the same issue where you need to scan each message in its entirety? Because if it does, then no matter. But if that's not the case, then it seems to be a point in favor of using websockets over SSE.

Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
  • 1
    String replacements aren't very slow, though it of course depends on the size of each message. But simply doing this should be fairly quick: `message = message.replace(/\n+/g, '\n')` It collapses any number of consecutive line breaks anywhere in the string into just a single line break. – IceMetalPunk Dec 03 '19 at 19:49

2 Answers2

0

it shouldnt be necessary to scan the payload if you're encoding the user data correctly. With JSON it is safe to use the "data" field in server-sent events because JSON decode newline and controls characters per default, as the RFC says:

The representation of strings is similar to conventions used in the C family of programming languages. A string begins and ends with quotation marks. All Unicode characters may be placed within the quotation marks, except for the characters that must be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F).

https://www.rfc-editor.org/rfc/rfc7159#page-8

the important thing is that nobody sneaks in an newline charactes but this isnt new to server sent events, header are seperate by a single new line and can be tampered too (if not correctly encoded) see https://www.owasp.org/index.php/HTTP_Response_Splitting

Heres an example of an server sent application with json encoding: https://repl.it/@BlackEspresso/PointedWelloffCircles you shouldnt be able to tampere the data field even with the newline characters are allowed

Encoding souldnt stop you from using server side events, but there are major differences between websockets and sse. For a comparison see this answer: https://stackoverflow.com/a/5326159/1749420

Community
  • 1
  • 1
Marinus Pfund
  • 239
  • 1
  • 3
  • 1
    Doesn't that linked example have to scan each message? Specifically line 44: `if strings.Contains(data,"\n\n") {` – Ryan Peschel Dec 06 '19 at 11:12
  • 1
    yes because sendMesssageEvent second parameter takes a string and can be used in other context, this is just an additional check nobody uses this function incorrect. for this example it would be easier to do the json serializition inside sendMessageEvent() and remove the check.One thing i forgot, if you work with sse or websocket you should use a library which does message encoding for you. – Marinus Pfund Dec 06 '19 at 16:55
  • 1
    Huh? I'm confused. In my question I'm asking if SSE is always going to be inferior to WebSockets because the former has to be inefficient with scanning every message in its entirety for `\n\n`. I just want to know if this is true or not. – Ryan Peschel Dec 06 '19 at 17:46
  • 1
    short answer: no, sse it not inferior to websockets. but you can do everything with websockets what you can do with SSE. (websocket support both directions). Websockets on the other hand a way more complex to implement and handle. SSE is just a "long loading" http site request. i would really recommend the comparison link https://stackoverflow.com/a/5326159/1749420 The example i provided would totaly work without the string.Contains() if you ensure that "data" is a JSON string and comes from json.Marshal. which it always is in the example. SSE has just a different use case. – Marinus Pfund Dec 06 '19 at 18:45
0

Unless I'm missing something obvious, sanitizing input is a common thing in web development.

Since the source that you shared explicitly mentioned a PHP example, I just did some research and lookie here:

https://www.php.net/manual/en/filter.filters.sanitize.php

FILTER_SANITIZE_SPECIAL_CHARS

HTML-escape '"<>& and characters with ASCII value less than 32, optionally strip or encode other special characters.

and:

'\n' = 10 = 0x0A = line feed

So I'm not sure I understand why you would assume that converting certain input to character entities would necessarily be a bad thing.
Avoiding users to abuse the system by uploading unwanted input is what sanitization is for.

html_programmer
  • 18,126
  • 18
  • 85
  • 158