PUT 请求

PUT 请求,拥有对服务器文件系统的直接“写”权限。

如果说 GET 是“读”,POST 是“递交处理”,那么 PUT 就是“上传覆盖”

对于一些配置不当的服务器,PUT 允许客户端直接在服务器目录下创建文件。

攻击逻辑: 攻击者不再寻找复杂的上传表单漏洞,而是直接发送一个 PUT 请求,路径指向 /shell.jsp/cmd.php

在网络安全和渗透测试中,PUT 请求之所以备受青睐,并不是因为它比其他方法更“高级”,而是因为它具备一个独特的权限漏洞:它拥有对服务器文件系统的直接“写”权限。

如果说 GET 是“读”,POST 是“递交处理”,那么 PUT 就是“上传覆盖”

以下是黑客(或安全研究员)经常利用 PUT 构造 Payload 的几个核心原因:


1. 任意文件上传与 WebShell 植入

这是 PUT 最具杀伤力的用途。在配置不当的服务器(如开启了 WebDAV 扩展的 IIS 或配置疏忽的 Apache/Nginx)上,PUT 允许客户端直接在服务器目录下创建文件。

  • 攻击逻辑: 攻击者不再寻找复杂的上传表单漏洞,而是直接发送一个 PUT 请求,路径指向 /shell.jsp/cmd.php

  • Payload 构造:

    HTTP

    1
    2
    3
    4
    5
    PUT /uploads/backdoor.php HTTP/1.1
    Host: target.com
    Content-Type: text/plain

    <?php eval($_POST['cmd']); ?>
  • 结果: 如果服务器支持该方法且权限过滤不严,木马文件就直接“空降”到了服务器上。


2. 绕过传统的 Web 应用防火墙 (WAF)

很多传统的防火墙和安全策略会重点检查 POSTGET 请求,因为绝大多数业务逻辑和用户交互都通过这两者完成。

  • 隐蔽性: 开发者有时会忽略对 PUTMOVECOPY 等 HTTP 扩展方法的过滤。

  • Payload 传递: 攻击者可以将攻击载荷藏在 PUT 的请求体中,试图绕过那些只针对 POST 参数进行正则匹配的安全规则。


3. 利用 WebDAV 的连锁反应

PUT 往往是 WebDAV(Web 分布式创作和版本控制)协议的一部分。当 PUT 方法开启时,通常意味着服务器还支持其他危险方法:

  • MOVE 方法: 攻击者可以先用 PUT 上传一个看似无害的 .txt 文件(绕过后缀检查),然后利用 MOVE 方法将其重命名为 .asp.exe

  • PROPFIND 方法: 用于探测服务器的目录结构,寻找存放 Payload 的最佳位置。


4. 覆盖敏感配置文件

由于 PUT 的定义是“完整替换”,如果目标服务器的权限控制存在逻辑错误,攻击者可以尝试 PUT 一些关键的系统文件或配置文件。

  • 例如: 尝试覆盖 .htaccess(Apache 分散配置文件)来改变目录访问权限,或者覆盖 robots.txt 来修改爬虫规则。

5. 简单直接,无需复杂编码

相比于 POST 请求可能需要的 multipart/form-data 复杂格式(包含 boundary、表单字段名等),PUT 请求的 Payload 更加简洁。

PUT 请求体即数据本身。这使得构造攻击脚本时更加方便,减少了因格式解析错误导致攻击失败的概率。


如何防御?

在生产环境中,防御此类威胁的手段通常非常直接:

  1. 关闭不必要的方法: 在 Web 服务器(Nginx/Apache/IIS)配置中明确禁用 PUTDELETETRACE 等方法。

  2. 最小权限原则: 即使需要开启上传功能,也要确保 Web 进程对存放目录没有“执行”权限,且严格限制上传文件的类型。

  3. WAF 全量检查: 配置 WAF 监控所有 HTTP 谓词,而不仅仅是 GET 和 POST。

你想实际看一看如何在 Nginx 或 Apache 中通过配置来禁用这些危险的 HTTP 方法吗?

方法 行为 类比 幂等性
POST 新增/处理 在文件夹里新增一封信
PUT 替换/创建 拿一张新纸覆盖掉旧纸
PATCH 局部修改 用涂改液修改纸上的一个错别字 否 (通常)

在 HTTP 协议中,PUT 请求主要用于更新服务器上的资源。它与 POST 经常被拿来比较,但其核心特性在于它的“替换”逻辑。

简单来说,PUT 就像是你在云盘里上传一个文件:如果文件已存在,它会覆盖旧文件;如果不存在,它就创建一个新文件。


1. PUT 的核心特点

幂等性 (Idempotency)

这是 PUT 最关键的特性。幂等意味着:无论你发送一次还是连续发送一百次相同的 PUT 请求,服务器上资源的状态最终都是一样的。

  • 对比: POST 通常不是幂等的。如果你点一百次“提交订单”,可能会产生一百个订单。但如果你发一百次“更新头像”,头像还是那一个。

资源定位

PUT 请求的 URL 指向的是具体的资源路径

  • PUT /users/123:明确告诉服务器,我要操作的是 ID 为 123 的用户。

  • 相比之下,POST /users 通常是告诉服务器:“在用户列表里帮我建个新用户,ID 你看着办”。

完整替换

PUT 请求通常要求提供资源的完整版本

注意: 如果你只想修改用户的一个电话号码,但在 PUT 请求里只传了电话号码,很多服务器实现会把该用户的其他信息(如姓名、地址)置为空或默认值,因为它认为你在用新内容“替换”旧内容。


2. PUT 的工作流程

当客户端发起一个 PUT 请求时,服务器通常会经历以下判断:

  1. 查找资源: 服务器检查 URL 指定的资源是否存在。

  2. 存在时: 使用请求体(Body)中的数据完全覆盖现有资源。返回 200 OK204 No Content

  3. 不存在时: 根据配置,服务器可能会根据该 URL 创建一个新资源。返回 201 Created


3. PUT vs POST vs PATCH

为了让你更直观地理解,我们可以用“修改文档”来做类比:

方法 行为 类比 幂等性
POST 新增/处理 在文件夹里新增一封信
PUT 替换/创建 拿一张新纸覆盖掉旧纸
PATCH 局部修改 用涂改液修改纸上的一个错别字 否 (通常)

4. 实际案例

假设我们要更新 ID 为 5 的书的信息:

请求头:

PUT /books/5 HTTP/1.1

Content-Type: application/json

请求体:

JSON

1
2
3
4
5
6
{
"id": 5,
"title": "深入理解计算机系统",
"author": "Randal Bryant",
"price": 99.00
}
  • 如果 /books/5 原本的价格是 88 元,执行后会变成 99 元。

  • 如果你不小心点快了发了两次,第二次执行时,服务器发现书的信息已经是 99 元了,结果不会有任何变化。

你想了解如何在代码(比如 Python 或 JavaScript)中实现一个 PUT 请求,还是想深入探讨它与 PATCH 在 API 设计中的选择建议?