拒绝服务缓解措施#
客户端有多种方法可以使服务器过载并拒绝为其他客户端提供服务。一个简单的例子可以是调用一个昂贵的路由,其频率高到足以耗尽服务器的资源。虽然这可能是无意中发生的(如果一个路由很受欢迎),但这需要大量的客户端资源,有一些恶意方法可以耗尽服务器资源。
这里讨论并缓解了两种攻击方法,第一种方法旨在尽可能多地打开与服务器的连接,而不释放它们,从而最终耗尽所有连接并阻止其他客户端连接。由于大多数请求响应循环在连接关闭之前持续几毫秒,因此关键是通过某种方式保持连接打开。
第二种方法旨在耗尽服务器的内存,从而使服务器运行缓慢或终止服务器应用程序,从而阻止服务器回复其他客户端。这里的关键是通过某种方式使服务器向内存写入大量信息。
非活动连接#
此攻击属于第一种类型,旨在耗尽服务器的连接。它通过打开与服务器的连接然后对连接不做任何操作来工作。配置不当的服务器只会简单地等待客户端执行某些操作,从而保持连接打开。
ASGI 服务器需要负责抵御这种攻击,通常通过可配置的保持活动或超时设置。
大型请求体#
此攻击属于第二种类型,旨在通过邀请服务器接收大型请求体(从而将主体写入内存)来耗尽服务器的内存。配置不当的服务器对请求体的大小没有限制,并可能允许单个请求耗尽服务器。
为了缓解这种情况,Quart 将请求体的大小限制为应用程序配置[‘MAX_CONTENT_LENGTH’]中设置的值。任何请求体大于此限制的请求都会触发“请求实体过大”,413,响应。
MAX_CONTENT_LENGTH 的默认值为 16 MB,之所以选择这个值是因为它是 Flask 文档中讨论的限制。
从技术上讲,此限制指的是 Quart 允许在内存中为请求体保留的最大数据量。这允许在需要时接收和使用更大的主体。关键是数据被使用而不是存储在内存中。例如,
async def route():
async for data in request.body:
# Do something with the data
...
建议在流式传输请求时在每个块内添加超时。
缓慢的请求体#
此攻击属于第一种类型,旨在通过邀请服务器等待很长时间来接收请求体来耗尽服务器的连接。配置不当的服务器会无限期地等待请求体。
为了缓解这种情况,Quart 默认情况下不会等待请求体,允许路由处理程序在可能的情况下进行响应,例如,如果请求没有正确的授权。如果需要主体,则应用程序配置[‘BODY_TIMEOUT’]定义了等待主体完全接收的秒数。如果超时时间已到,Quart 会以“请求超时”,408 响应。
默认值为 60 秒,之所以选择这个值是因为它是典型的默认超时值。
从技术上讲,超时只应用于 Response 数据方法(get_data、data、json、get_json、form 和 files),而不应用于 body 属性。这允许按需使用已知的流式请求,参见使用请求体.
没有响应使用#
此攻击属于第二种类型,旨在通过不使用发送到客户端的数据来耗尽服务器的内存。这种失败会导致服务器上的背压,这会导致响应被写入内存而不是连接。配置不当的服务器会忽略背压并耗尽其内存。(注意,这需要一个返回大量数据的路由,例如视频流)。
ASGI 服务器需要负责抵御这种攻击。
缓慢的响应使用#
此攻击属于第一种类型,旨在通过邀请服务器花费很长时间来发送响应,例如通过无限期地施加背压,来耗尽服务器的连接。配置不当的服务器只会简单地无限期地等待尝试发送响应。
为了缓解这种情况,Quart 会将尝试发送响应的时间限制为应用程序配置[‘RESPONSE_TIMEOUT’]中设置的时间。如果此时间已到,连接将被突然关闭。
默认值为 60 秒,之所以选择这个值是因为它是典型的默认超时值。
从技术上讲,如果需要,此限制可以为每个响应进行配置,例如,如果有一个返回大型文件的路由。以下是一个示例,
async def route():
response = await make_response(...)
response.timeout = 120
return response
大型 websocket 消息#
此攻击属于第二种类型,旨在通过邀请服务器接收非常大的 websocket 消息来耗尽服务器的内存。配置不当的服务器对消息大小没有限制,并可能允许单个消息耗尽服务器。
ASGI 服务器需要负责抵御这种攻击。