在实现服务器发送事件时如何高效处理换行符漏洞?

4
在应用服务器上实现服务器发送事件时,您可以通过在消息末尾添加两个换行符\n\n来终止消息并发送它,如this documentation page所示。
那么,如果您正在接收用户输入并将其转发给所有感兴趣的方(这通常是聊天应用程序中的情况),恶意用户是否可以在其有效负载中插入两个换行符以提前终止消息?更重要的是,既然他们可以访问一行的前几个字符,他们是否不能设置特殊字段,例如idretry字段?
似乎唯一的替代方法是扫描整个有效负载,然后将\n的实例替换为\ndata:之类的内容,以便他们的整个消息有效负载必须保持在data标记中的位置。
但是,这不是非常低效吗?每个消息都需要扫描整个消息有效负载,然后进行替换,这不仅涉及扫描每个有效负载,还可能在恶意情况下重新分配。
还有其他选择吗?我目前正在尝试在WebSockets和SSE之间做出决定,因为它们非常相似,这个问题使我更倾向于使用WebSockets,因为如果它们能够避免这种潜在的漏洞,它们可能会更有效率。
编辑:为了澄清,我大多数时间都不知道是否有一种方法可以避免必须完全扫描每个消息以查找\n\n。如果没有,那么WebSockets是否也有同样的问题,需要完全扫描每个消息?因为如果是这样,那就无所谓了。但如果不是这种情况,那么似乎使用WebSockets比SSE更好。

1
字符串替换并不是很慢,当然这取决于每个消息的大小。但是简单地执行以下操作应该相当快:message = message.replace(/\n+/g, '\n') 它将字符串中任意数量的连续换行符合并为一个换行符。 - IceMetalPunk
2个回答

0

如果您正确编码用户数据,则不需要扫描负载。使用JSON时,可以安全地在服务器发送的事件中使用“data”字段,因为JSON默认解码换行符和控制字符,正如RFC所述:

字符串的表示类似于C系列编程语言中使用的约定。字符串以引号开头和结尾。除了必须转义的字符(引号、反向斜杠和控制字符(U+0000到U+001F))之外,可以在引号之间放置所有Unicode字符。

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

重要的是没有人在换行符中潜入,但这对于服务器发送事件并不新鲜,头部由单个换行符分隔,并且也可以被篡改(如果未正确编码),请参见https://www.owasp.org/index.php/HTTP_Response_Splitting

以下是使用JSON编码的服务器发送应用程序示例:https://repl.it/@BlackEspresso/PointedWelloffCircles,即使允许换行符,您也不应该能够篡改数据字段。

编码不应阻止您使用服务器端事件,但WebSocket和SSE之间存在重大差异。有关比较,请参见此答案:https://dev59.com/gW435IYBdhLWcg3w0Tnc#5326159


1
这个链接的示例不是必须要扫描每个消息吗?特别是第44行:if strings.Contains(data,"\n\n") { - Ryan Peschel
1
是的,因为sendMessageEvent的第二个参数需要一个字符串并且可以在其他上下文中使用,这只是一个额外的检查,没有人会错误地使用此函数。对于这个例子,更容易在sendMessageEvent()内部进行json序列化并删除检查。我忘记的一件事是,如果您使用sse或websocket,则应该使用一个库来为您进行消息编码。 - Marinus Pfund
1
啥?我有点糊涂了。我的问题是,SSE 是否总是比 WebSockets 差,因为前者必须要扫描每个消息的全部内容以寻找 \n\n,这样效率就会很低。我只是想知道这是否属实。 - Ryan Peschel
1
简短回答:不,SSE并不劣于Websockets。但是你可以用Websockets做到SSE所能做的一切(Websockets支持双向通信)。另一方面,Websockets的实现和处理要复杂得多。SSE只是一个“长时间加载”的HTTP站点请求。我真的建议您查看比较链接https://dev59.com/gW435IYBdhLWcg3w0Tnc#5326159。如果您确保“data”是JSON字符串并来自json.Marshal,则提供的示例将完全正常工作,而无需使用string.Contains()。SSE只是有不同的用例。 - Marinus Pfund

0
除非我错过了什么显而易见的东西,否则在Web开发中对输入进行消毒是一种常见的做法。
既然你分享的来源明确提到了一个PHP示例,那我就做了一些研究,看看这里:

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

FILTER_SANITIZE_SPECIAL_CHARS

HTML转义'“<>&”和ASCII值小于32的字符,可选择性剥离或编码其他特殊字符。
'\n' = 10 = 0x0A = line feed

所以我不确定你为什么会认为将某些输入转换为字符实体一定是一件坏事。
避免用户上传不必要的输入来滥用系统,这就是清理的作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接