PHP 伪协议:使用 php:input 访问原始 POST 数据
作者:mmseoamin日期:2023-12-13

文章目录

  • 参考
  • 环境
  • 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

                                    环境

                                    项目描述
                                    PHP5.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:input 访问原始 POST 数据,第1张

                                    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 伪协议:使用 php:input 访问原始 POST 数据,第2张

                                    更灵活的数据处理

                                    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 的一些 主要 特点和功能:

                                    1. HTTP 请求和响应拦截

                                      HackBar 允许用户 查看编辑浏览器发送的 HTTP 请求报文及接收到的 HTTP 响应报文。在需要的时候,你可以通过 修改 HTTP 请求报文 来实现 对请求的精细化控制。

                                    2. Cookie 编辑和管理

                                      HackBar 允许用户轻松编辑和管理浏览器中的 Cookie,这对于模拟不同的用户会话非常有用。

                                    3. 表单处理

                                      HackBar 提供了表单提交和数据包装功能,以帮助用户测试应用程序的输入验证和表单处理。你 可以手动构建 POST 或 GET 请求,并查看服务器对此进行的响应。

                                    4. 编码和加密工具

                                      HackBar 包括一些编码和加密工具,可用于处理 Base64、MD5、SHA1 等的相关数据。

                                    5. XSS 攻击测试

                                      HackBar 提供了一些工具,用于 检测和测试跨站脚本(XSS)漏洞。

                                    6. SQL 注入测试

                                      HackBar 还包括用于 测试 SQL 注入漏洞 的工具,可以帮助用户评估 Web 应用程序的数据库安全性。

                                    由于微软的 Edge 浏览器的插件官网没有提供 HackBar 这款扩展工具,而 Google 的 Chrome 浏览器的插件官网由需要科学上网,所以推荐需要这款插件的朋友可以使用 Firefox 浏览器。

                                    HackBar 插件的获取

                                    首先,打开 Firefox 浏览器并进入其 插件官网,搜索插件 HackBar,你将得到如下类似界面。

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第3张

                                    选择图中 红色箭头指向的两个插件中的其中一个 进行安装即可。

                                    $_POST
                                    ';
                                    # 获取名为 X 的 POST 参数的值
                                    var_dump($_POST['X']);
                                    

                                    访问上述 PHP 页面,你将得到如下内容:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第4张

                                    PHP 解释器抛出了 Notice 异常信息,这是由于我们还未提交 POST 数据,导致 $_POST['X'] 正在 尝试访问一个不存在的元素 从而引发了异常。

                                    打开 HackBar 插件

                                    右键 当前页面,得到如下类似界面:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第5张

                                    点击其中的 检查,得到如下类似界面:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第6张

                                    选择其中的 HackBar 分栏,得到如下类似界面:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第7张

                                    通过 HackBar 插件发起 POST 请求

                                    点击 LOAD 按钮 加载与当前页面相关的 URL 至输入框中,当然你也可以自己输入 URL,URL 所指向的页面是插件将处理的页面,不一定需要是当前页面的 URL。

                                    点击 Use POST method 旁边的按钮尝试进行 POST 请求,enctype 下拉框中提供了 可供选择的 POST 请求数据的编码方式。

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第8张

                                    默认选项 application/x-www-form-urlencode 允许我们使用 同 URL 查询字符串相同的格式编写 POST 数据。于是构造如下 POST 数据:

                                    name=RedHeart&X=BinaryMoon&special_symbol=%26%25%24
                                    

                                    点击 EXECUTE 发起请求,得到如下类似界面:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第9张

                                    基操

                                    php://input 提供了一个方式来 读取 POST 请求 的原始内容。对此,请参考如下实例:

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第10张

                                    index.php

                                     实现换行功能
                                    echo '
                                    '; # 经 PHP 整理的 POST 数据 var_dump($_POST);

                                    执行效果

                                    在执行上述示例程序后,php://input 获取了 POST 请求过程中提交的原始数据,而 $_POST 则提供了一个经 PHP 处理 POST 数据后得到的关联数组。

                                    PHP 伪协议:使用 php:input 访问原始 POST 数据,第11张

                                    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,我们可以逐步分解它:

                                    1. multipart

                                      multipart 意味着 POST 主体中包含多个数据部分,每个部分之间通过边界进行分隔。

                                    2. form-data

                                      form-data 表明数据来源于一个 HTML 表单。

                                    3. 边界

                                      当指定 multipart/form-data 作为内容类型时,会有一个 boundary 参数与之关联。boundary 参数用于指定边界,边界是一个随机生成的字符串,与消息主体的任何部分冲突。

                                    4. 每个部分的大致结构

                                      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 仍然可以用来访问这些数据。