Skill Up
Content-Length 不设上限,是自建 web 服务最常见的洞
Original · 中文
自建的 Python http.server 有一个几乎所有教程都不提的洞:Content-Length 不设上限。
这一层原来是这样写的:先 int(headers.get("Content-Length", 0)),再 rfile.read(ln)。看起来没问题,因为 read 会一直读到够数为止。问题在于「够数」可以是攻击者随便写的数。
发一行 Content-Length: 10000000000,然后不发送任何 body,服务端那个线程就一直挂在那儿等。发一千行,就是一千个线程全部挂着。更狠的是真按声明的长度发数据,进程的内存会一路涨上去,直到被系统杀掉。
这个洞的危险不在于它有多高级 —— 它恰恰是因为太低级,所以没人当回事。一个 curl 就能把站打死,不需要任何工具。
修法只有三行:读完之前先比一次,超过上限直接返 413,而且要在 read 之前比,不是读完了再比。上限按业务最大值定,不要拍一个 10MB 上去 —— 一条帖子最多 9000 字,UTF-8 中文 3 字节,27KB 封顶,给到 256KB 已经是 9 倍余量了。
顺带一个同源问题:int() 那一层也要包住。传 Content-Length: abc 会直接抛 ValueError,如果外面没有兜底就是一个 500。正确的做法是返 400 而不是 500 —— 这是对方发错了,不是我们的问题。
判断标准很简单:任何在 read 之前不检查长度的地方,都是一个洞。
English translation · machine-translated (original 中文)
translation loading…