实现服务器发送事件时如何有效处理换行漏洞?
Posted
技术标签:
【中文标题】实现服务器发送事件时如何有效处理换行漏洞?【英文标题】:How to efficiently handle the line break exploit when implementing server sent events? 【发布时间】:2020-03-28 11:09:30 【问题描述】:在您的应用程序服务器上实现服务器发送事件时,您可以终止一条消息并通过两个换行符结束它发送它:\n\n
,如 this documentation page 所示。
那么,如果您接收用户输入并将其转发给所有感兴趣的各方(在聊天应用程序中很常见),该怎么办?恶意用户能否不在其有效负载中插入两个换行符以提前终止消息?更重要的是,既然他们可以访问一行的第一个字符,他们就不能设置特殊字段,例如id
和retry
字段吗?
似乎唯一的选择是扫描它们的整个有效负载,然后将\n
的实例替换为\ndata:
之类的东西,这样它们的整个消息有效负载必须保持其在data
标记中的位置。
但是,这不是非常低效吗?必须为每条消息扫描整个消息负载,然后可能进行替换,这不仅涉及扫描每个整个负载,还涉及在恶意情况下重新分配。
或者有其他选择吗?我目前正在尝试在 websockets 和 SSE 之间做出决定,因为它们非常相似,这个问题让我对 WebSockets 有了更多的了解,因为如果他们能够避免这个潜在的漏洞,他们会更有效率。
编辑:澄清一下,我几乎不知道是否有办法绕过对\n\n
的完整扫描每条消息。如果没有,WebSockets 是否有同样的问题,您需要完整地扫描每条消息?因为如果是这样,那就无所谓了。但如果情况并非如此,那么似乎有利于在 SSE 上使用 websockets。
【问题讨论】:
字符串替换并不是很慢,尽管它当然取决于每条消息的大小。但是这样做应该很快:message = message.replace(/\n+/g, '\n')
它将字符串中任意数量的连续换行符折叠成一个换行符。
【参考方案1】:
除非我遗漏了一些明显的东西,否则清理输入是 Web 开发中的常见事情。
由于您分享的源明确提到了一个 php 示例,我只是在这里做了一些研究和查看:
https://www.php.net/manual/en/filter.filters.sanitize.php
FILTER_SANITIZE_SPECIAL_CHARS
html-escape '"& 和 ASCII 值小于 32 的字符, 可选择剥离或编码其他特殊字符。
和:
'\n' = 10 = 0x0A = line feed
所以我不确定我是否理解您为什么认为将某些输入转换为字符实体必然是一件坏事。 清理的目的是避免用户通过上传不需要的输入来滥用系统。
【讨论】:
【参考方案2】:如果您正确编码用户数据,则无需扫描有效负载。使用 JSON,在服务器发送的事件中使用“数据”字段是安全的,因为 JSON 解码换行符并默认控制字符,正如 RFC 所说:
字符串的表示类似于 C 中使用的约定 编程语言家族。一个字符串以 引号。所有 Unicode 字符都可以放在 引号,必须转义的字符除外: 引号、反斜线和控制字符(U+0000 通过 U+001F)。
https://www.rfc-editor.org/rfc/rfc7159#page-8
重要的是没有人潜入换行符,但这对于服务器发送的事件来说并不新鲜,标头由一个新行分隔并且也可以被篡改(如果没有正确编码)请参阅https://www.owasp.org/index.php/HTTP_Response_Splitting
这是一个使用 json 编码的服务器发送应用程序的示例: https://repl.it/@BlackEspresso/PointedWelloffCircles 即使允许换行符,您也不应该篡改数据字段
编码不会阻止您使用服务器端事件,但 websockets 和 sse 之间存在重大差异。如需比较,请参阅此答案:https://***.com/a/5326159/1749420
【讨论】:
链接的例子不是必须扫描每条消息吗?特别是第 44 行:if strings.Contains(data,"\n\n")
是的,因为 sendMesssageEvent 第二个参数接受一个字符串并且可以在其他上下文中使用,这只是一个额外的检查没有人使用这个函数不正确。对于此示例,在 sendMessageEvent() 中执行 json 序列化并删除检查会更容易。我忘了一件事,如果您使用 sse 或 websocket,您应该使用一个为您进行消息编码的库。
嗯?我糊涂了。在我的问题中,我问的是 SSE 是否总是不如 WebSockets,因为前者在扫描 \n\n
的每条消息时效率很低。我只是想知道这是不是真的。
简短回答:不,它并不逊于 websockets。但是你可以用 websockets 做任何你可以用 SSE 做的事情。 (websocket 支持两个方向)。另一方面,Websockets 是一种更复杂的实现和处理方式。 SSE 只是一个“长时间加载”的 http 站点请求。我真的会推荐比较链接***.com/a/5326159/1749420 如果您确保“数据”是 JSON 字符串并且来自 json.Marshal,我提供的示例完全可以在没有 string.Contains() 的情况下工作。在示例中始终如此。 SSE 只是一个不同的用例。以上是关于实现服务器发送事件时如何有效处理换行漏洞?的主要内容,如果未能解决你的问题,请参考以下文章
如何有效地将压缩的 json 数据推送到 azure 事件中心并在 azure 流分析中处理?
如何在 pwn 攻击中通过 netcat 发送二进制有效负载