安全性

Scrapy 的默认设置针对网络抓取进行了优化,而非针对处理不可信输入或在共享/暴露环境中运行的软件所期望的安全态势。对于许多抓取用例而言,一些常见的安全实践是不必要的,甚至有些还会阻碍正常的抓取(例如,您必须抓取的网站可能使用配置错误的 TLS 证书或通过未加密协议提供内容)。

本页重点介绍了 Scrapy 默认设置中涉及安全性的部分,以便您能就保留这些设置做出明智的决定,并解释了如何在增强其安全性的同时权衡利弊。

注意

以下选项均非万能药。它们是否适用取决于您的威胁模型:您抓取的 URL 是否来自可信来源,运行 Scrapy 的机器是否暴露在您无法控制的网络中,您处理的数据是否敏感,等等。

将响应视为不可信输入

无论任何设置如何,请记住响应数据来自您无法控制的服务器,即使您信任正在抓取的网站,因为响应可能在传输过程中被篡改,或者服务器本身可能已受损。

切勿将响应数据传递给可能执行代码或以不安全方式操作其输入的函数,例如 eval()exec()pickle.loads(),并在将响应数据写入从响应本身派生的路径时务必小心。

TLS 连接

证书验证

默认情况下,Scrapy **不**验证 HTTPS 服务器的 TLS 证书,这由 DOWNLOAD_VERIFY_CERTIFICATES 设置控制(默认值:False)。

此默认设置倾向于可达性而非安全性:许多原本可以正常抓取的网站可能拥有过期、自签名或其他无效证书,而验证证书会导致对它们的请求失败。

如果连接的完整性对您很重要(例如,为了检测中间人攻击),请设置

DOWNLOAD_VERIFY_CERTIFICATES = True
  • 优点: 对具有无效或不可信证书的服务器的请求将失败,而非静默成功,从而保护您免受某些中间人攻击。

  • 缺点: 您将无法再抓取具有配置错误证书的网站,除非重新禁用对它们的验证。

协议版本和密码套件

您可以通过 DOWNLOAD_TLS_MIN_VERSIONDOWNLOAD_TLS_MAX_VERSION 设置来限制 Scrapy 接受的 TLS 协议版本,例如拒绝过时的协议版本。

默认情况下,Scrapy 使用 OpenSSL 的 DEFAULT 密码套件列表(DOWNLOADER_CLIENT_TLS_CIPHERS),这有利于兼容性,但仍允许一些较旧、较弱的密码套件。将其设置为 None 可转而使用底层 TLS 实现(Twisted)的精选密码套件列表,该列表排除了弱密码套件。

DOWNLOADER_CLIENT_TLS_CIPHERS = None
  • 优点: 协商弱密码套件的连接会失败,而非成功。

  • 缺点: 您将无法再连接到仅支持被排除密码套件的服务器。

未加密协议

默认情况下,Scrapy 为未加密协议(即 http://ftp://)启用了下载处理器(参见 DOWNLOAD_HANDLERS_BASE)。通过这些协议发送和接收的数据,包括任何凭据,以纯文本形式传输,并且可能被网络路径上的任何人读取或修改。

如果您只通过加密协议抓取,可以禁用未加密协议,以防止任何请求意外地以未加密方式发送。

DOWNLOAD_HANDLERS = {
    "http": None,
    "ftp": None,
}
  • 优点: 配置错误或恶意重定向的请求不会通过未加密连接泄露数据,因为此类请求会失败。

  • 缺点: 您将无法再抓取仅通过这些协议可用的资源。

请注意,禁用 http 处理器还会阻止因遵循 http:// 重定向或链接而产生的纯 HTTP 请求,这通常是禁用它的目的。

本地和非网络资源

默认情况下,Scrapy 为 file://data: 方案启用了下载处理器(参见 DOWNLOAD_HANDLERS_BASE)。file:// 处理器从本地文件系统读取任意文件,仅受限于运行 Scrapy 进程的权限。

这很方便(例如,解析本地 HTML 文件),但如果您的调度中包含来自不可信来源的 URL,则存在风险:精心构造的 file:///etc/passwd URL 可能会读取本地文件。

如果您不需要它们,请禁用这些处理器。

DOWNLOAD_HANDLERS = {
    "file": None,
    "data": None,
}
  • 优点: 抓取的 URL 不能用于读取本地文件或内联数据。

  • 缺点: 您将无法再抓取 file://data: URL。

更一般地,如果您从不可信来源抓取 URL,请在调度请求之前考虑验证其方案(以及在适用情况下,其主机),以避免服务器端请求伪造(SSRF)和类似问题。

Telnet 控制台

Scrapy 默认启用 telnet 控制台TELNETCONSOLE_ENABLED)。telnet 控制台是一个在 Scrapy 进程内部运行的 Python shell,因此任何能够连接到它的人都可以在该进程中运行任意代码。

默认情况下,该控制台绑定到 127.0.0.1TELNETCONSOLE_HOST),并通过用户名(TELNETCONSOLE_USERNAME,默认 scrapy)和自动生成的密码(TELNETCONSOLE_PASSWORD)进行保护,因此它只能从本地机器访问。

警告

Telnet 不提供任何传输层安全性,因此用户名/密码认证无法保护凭据或会话免受任何能够观察流量的人的攻击。切勿通过将 TELNETCONSOLE_HOST 更改为非本地地址,将 telnet 控制台暴露在不可信网络上。

如果您不使用 telnet 控制台,请完全禁用它。

TELNETCONSOLE_ENABLED = False

跨域凭据泄露

某些 Scrapy 功能会将凭据或其他敏感头部信息附加到请求中,而跨多个域的抓取可能会将这些信息泄露给非预期的主机。

  • 通过 HttpAuthMiddleware 设置的 HTTP 认证凭据仅发送到 HTTPAUTH_DOMAIN 中设置的域。将其设置为预期域而非 None,以确保凭据不会发送到您抓取的每个域。

  • Referer 头部可能会将您抓取的 URL 泄露给其他网站。默认的 REFERRER_POLICY 已经避免将 HTTPS 的 referrer 发送到 HTTP,但如果需要,您可以进一步收紧它(例如,设置为 same-originno-referrer)。