文章目录
- 参考
- 环境
- PHP 伪协议
- 概念
- 为什么需要 PHP 伪协议?
- php://input
- 为什么需要 php://input?
- 更灵活的数据处理
- 减小性能压力
- 发送 POST 数据
- HackBar
- HackBar 插件的获取
- $_POST
- 打开 HackBar 插件
- 通过 HackBar 插件发起 POST 请求
- 基操
- enable_post_data_reading
- enable_post_data_reading 配置项
- 为什么 PHP 要提供 enable_post_data_reading 配置项?
- 减小性能压力
- 使得 php://input 能够获取 multipart/form-data 类型的 POST 数据
- multipart/form-data
- 原因
- 不必要的 POST
- `php://input` 的独立性
- `GET 请求也可以携带请求体`
参考
项目 | 描述 |
---|---|
搜索引擎 | Bing、Google |
AI 大模型 | 文心一言、通义千问、讯飞星火认知大模型、ChatGPT |
PHP 官方 | ini.core.php |
PHP 官方 | PHP Manual |
环境
项目 | 描述 |
---|---|
PHP | 5.5.0 、5.6.8 、7.0.0 、7.2.5 、7.4.9 、8.0.0 、8.2.9 |
PHP 编辑器 | PhpStorm 2023.1.1(专业版) |
PHP 伪协议
概念
在 PHP 中,伪协议(Pseudo Protocols)
也被称为 流包装器
,这些伪协议以 php://
开头,后面跟着一些参数,用于指定 要执行的操作
或 需要访问的资源
。
伪协议表明这些协议并不是一个 真实的外部协议
,例如 http
或 ftp
。PHP 伪协议的出现是为了提供一个 统一的
、简洁的
接口来处理 不同的数据流
。这些伪协议可以被看作是一种 桥梁
,它们允许开发者 使用常规的文件操作函数来处理各种不同的数据流
。
为什么需要 PHP 伪协议?
PHP 所提供的伪协议带来的优点整理如下:
项目 | 描述 |
---|---|
一致性 | 开发者 不必为不同的数据流编写特定的处理代码 。通过使用伪协议,开发者能够使用 熟悉的 、标准的 文件操作函数来处理各种数据。 |
灵活性 | 伪协议提供了 多种不同的方式来访问和处理数据 。例如 ,您可以使用 php://stdin 和 php://stdout 来处理标准输入和标准输出;使用 php://memory 和 php://temp 来在内存中或临时文件中处理数据。这种灵活性允许开发人员根据具体需求选择最合适的方式来处理数据。 |
优化工作流 | php://input 伪协议可以 直接读取原始的 POST 数据 ,而不需要依赖特定的全局变量,这样可以在不同的上下文中更灵活地处理输入数据;php://temp 和 php://memory 伪协议允许在内存中 创建临时数据流 ,而 无需实际文件存储 。这对于处理临时数据或进行中间数据处理非常有用,而 不会产生硬盘 I/O 开销。 |
php://input
为什么需要 php://input?
php://input
是 PHP 提供的一个伪协议,允许开发者 访问 POST 请求的原始内容
。对于 POST 请求数据,PHP 提供了 $_POST
与 $FILES
超全局变量,在客户端发起 POST 请求时,PHP 将自动处理 POST 提交的数据并将处理结果存放至 $_POST 与 $FILES 中
。既然 PHP 已经提供了 更为高效的 $_POST 与 $FILES
,为什么还要给出 php://input
伪协议来访问原始 POST 请求数据呢?🧐
更灵活的数据处理
PHP 的 默认行为
是自动解析 POST 数据,并将解析结果填充至 $_POST
和 $_FILES
超全局变量中。但在现代的 WEB 开发中,存在许多常用的数据格式,例如 JSON
、XML
。通过 php://input
,开发者可以直接访问这些数据,然后 根据需要进行适当的处理和解析
。
减小性能压力
在某些情况下,可能 不需要一次性处理整个 POST 数据
,或者希望以流的方式处理数据以 节省内存
。在使用 php://input
读取 POST 原始数据的过程中,可以使用 流处理函数进行逐块读取
,而不是一次性将 POST 数据加载至内存中。
发送 POST 数据
由于 php://input
与 POST 存在关联,为了方便后续的研究,我们需要一个工具来发起 POST 请求。推荐使用浏览器插件 HackBar
。
HackBar
Hackbar
是一个 浏览器扩展
,该扩展工具为安全专家、渗透测试人员和开发人员提供了一组工具,用于测试和评估 Web 应用程序的安全性
。HackBar
可以帮助用户识别潜在的安全漏洞,进行渗透测试,以及执行各种与网络安全相关的任务。以下是 Hackbar 的一些 主要
特点和功能:
-
HTTP 请求和响应拦截
HackBar 允许用户查看编辑浏览器发送的 HTTP 请求报文及接收到的 HTTP 响应报文
。在需要的时候,你可以通过修改 HTTP 请求报文
来实现对请求的精细化控制
。 -
Cookie 编辑和管理
HackBar 允许用户轻松编辑和管理浏览器中的 Cookie,这对于模拟不同的用户会话非常有用。 -
表单处理
HackBar 提供了表单提交和数据包装功能,以帮助用户测试应用程序的输入验证和表单处理。你可以手动构建 POST 或 GET 请求,并查看服务器对此进行的响应
。 -
编码和加密工具
HackBar 包括一些编码和加密工具,可用于处理Base64
、MD5
、SHA1
等的相关数据。 -
XSS 攻击测试
HackBar 提供了一些工具,用于检测和测试跨站脚本(XSS)漏洞
。 -
SQL 注入测试
HackBar 还包括用于测试 SQL 注入漏洞
的工具,可以帮助用户评估 Web 应用程序的数据库安全性。
由于微软的 Edge
浏览器的插件官网没有提供 HackBar
这款扩展工具,而 Google 的 Chrome
浏览器的插件官网由需要科学上网,所以推荐需要这款插件的朋友可以使用 Firefox
浏览器。
HackBar 插件的获取
首先,打开 Firefox
浏览器并进入其 插件官网,搜索插件 HackBar
,你将得到如下类似界面。
选择图中 红色箭头指向的两个插件中的其中一个
进行安装即可。
$_POST
<?php
# 超全局变量 $_POST 保持着一个关联数组
var_dump($_POST);
# 输出一个具有换行功能的 HTML 标签
echo '</br>';
# 获取名为 X 的 POST 参数的值
var_dump($_POST['X']);
访问上述 PHP 页面,你将得到如下内容:
PHP 解释器抛出了 Notice
异常信息,这是由于我们还未提交 POST
数据,导致 $_POST['X']
正在 尝试访问一个不存在的元素
从而引发了异常。
打开 HackBar 插件
右键
当前页面,得到如下类似界面:
点击其中的 检查
,得到如下类似界面:
选择其中的 HackBar
分栏,得到如下类似界面:
通过 HackBar 插件发起 POST 请求
点击 LOAD
按钮 加载与当前页面相关的 URL 至输入框中
,当然你也可以自己输入 URL,URL 所指向的页面是插件将处理的页面,不一定需要是当前页面的 URL。
点击 Use POST method
旁边的按钮尝试进行 POST 请求,enctype
下拉框中提供了 可供选择的 POST 请求数据的编码方式
。
默认选项 application/x-www-form-urlencode
允许我们使用 同 URL 查询字符串相同的格式编写 POST 数据
。于是构造如下 POST 数据:
name=RedHeart&X=BinaryMoon&special_symbol=%26%25%24
点击 EXECUTE
发起请求,得到如下类似界面:
基操
php://input
提供了一个方式来 读取 POST 请求
的原始内容。对此,请参考如下实例:
index.php
<?php
# 尝试通过 php://input 协议获取原始 POST 数据
$raw_data = file_get_contents('php://input');
var_dump($raw_data);
# 通过输出 HTML 标签 </br> 实现换行功能
echo '</br>';
# 经 PHP 整理的 POST 数据
var_dump($_POST);
执行效果
在执行上述示例程序后,php://input
获取了 POST 请求过程中提交的原始数据,而 $_POST
则提供了一个经 PHP 处理 POST 数据后得到的关联数组。
enable_post_data_reading
enable_post_data_reading 配置项
enable_post_data_reading
是 PHP 中的一个布尔配置项,该配置项决定了 是否在 PHP 启动时读取和解析 POST 数据以填充 $_POST 与 $_FILES 超全局变量
。在 默认情况
下,enable_post_data_reading 是 开启
的。
为什么 PHP 要提供 enable_post_data_reading 配置项?
减小性能压力
在使用 php://input
读取 POST 原始数据的过程中,可以使用 流处理函数进行逐块读取
,而不是一次性将 POST 数据加载至内存中。而通过将 enable_post_data_reading
配置项关闭,则可以防止 PHP 的读取与解析。否则,即使您通过 php://input
以流的形式逐块读取,PHP 也将一次性读取并将 POST 数据解析至 $_POST
与 $_FILES
超全局变量中。
使得 php://input 能够获取 multipart/form-data 类型的 POST 数据
multipart/form-data
multipart/form-data
POST 请求中的一种 Content-Type
,常用于与文件上传相关的数据传输。multipart/form-data
允许你将表单中的内容编码为多个部分的 主体(HTTP 请求体)
,每一部分通常代表一个表单字段,每个部分都包含自己的 头部信息和数据
。
为了更好地理解 multipart/form-data
,我们可以逐步分解它:
-
multipart
multipart
意味着 POST 主体中包含多个数据部分,每个部分之间通过边界进行分隔。 -
form-data
form-data
表明数据来源于一个HTML 表单
。 -
边界
当指定multipart/form-data
作为内容类型时,会有一个boundary
参数与之关联。boundary 参数用于指定边界,边界是一个随机生成的字符串,与消息主体的任何部分冲突。 -
每个部分的大致结构
POST 数据(HTTP 请求体)
的每个部分都有自己的一组头部信息(HTTP 请求头)
,后跟一个空行和数据。- 对于普通的表单字段,数据就是字段的值。
- 对于文件上传等功能,数据是文件的描述信息及文件所包含的内容。
举个栗子
假设你有一个表单,其中包含一个名为 username
的文本字段和一个名为 profile_picture
的文件字段。当用户填写 Alice
并上传一张图片后,HTTP 请求报文可能如下:
POST /submit HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="username"
Alice
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="profile_picture"; filename="alice.jpg"
Content-Type: image/jpeg
[raw image data here]
------WebKitFormBoundary7MA4YWxkTrZu0gW--
在上述示例中:
boundary
参数是----WebKitFormBoundary7MA4YWxkTrZu0gW
。- 消息主体包含两个部分,一个是
username
字段,一个是profile_picture
字段。 - 每个部分由边界、一组头部信息、空行以及数据组成。
- 消息主体的末尾存在一个
结束边界
,它是开始边界与两个连字符(--)
的组合。
原因
在开启 enable_post_data_reading
配置项时,$_POST
、$_FILES
及 php://input
将共同发挥作用。但在 Content-Type
为 mulltipart/form-data
时,php://input
将无法获取到任何数据,PHP 将客户端发送的数据 解析存储至
$_FILES
与 $_POST
中。
若将 enable_post_data_reading
配置项关闭,则 $_POST
与 $_FILES
将无法获取到客户端传递的任何 POST
数据。在 Content-Type
为 mulltipart/form-data
时,php://input
将获取到 POST 传递的原始数据。
不必要的 POST
php://input
的独立性
在 PHP 中,php://input
是一个只读流,它允许你访问原始的 HTTP 请求体。这个特性是独立于 HTTP 请求的方法的,意味着它不仅可以在 POST 请求中使用,也可以在 GET 或其他 HTTP 方法的请求中使用。
通常,我们将 php://input
与 POST 请求关联起来,因为 POST 请求常用于提交表单数据或上传文件,这些数据通常包含在请求体中。然而,php://input
的使用并不限于 POST 请求。无论是 GET、PUT、DELETE,还是其他 HTTP 方法,只要请求包含了请求体,php://input
都可以用来访问这些数据。
GET 请求也可以携带请求体
值得注意的是,GET 请求通常不包含请求体,因为 GET 方法主要用于从服务器检索数据,其数据通常通过 URL 的查询字符串传递。然而,技术上讲,HTTP 规范并没有禁止 GET 请求携带请求体,虽然这不是常见的做法。如果一个 GET 请求异常地包含了请求体,那么 php://input
仍然可以用来访问这些数据。