我在这里看到很多帖子说不要使用该$_REQUEST
变量。我通常不会,但有时它很方便。它出什么问题了?
16 回答
$_GET
从两者以及$_POST
以组合方式获取输入绝对没有错。事实上,这就是你几乎总是想做的事情:
对于通常通过 GET 提交的普通幂等请求,您想要的数据量可能不适合 URL,因此实际上已将其更改为 POST 请求。
对于一个有实际效果的请求,你必须检查它是否是通过 POST 方法提交的。但这样做的方法是
$_SERVER['REQUEST_METHOD']
明确检查,而不是依赖$_POST
GET 为空。无论如何,如果方法是POST
,您仍然可能希望从 URL 中获取一些查询参数。
不,问题与$_REQUEST
混淆 GET 和 POST 参数无关。默认情况下,它还包括$_COOKIE
. 而且 cookie 根本不像表单提交参数:你几乎不想把它们当作同一个东西对待。
如果您不小心在您的网站上设置了一个与您的表单参数之一同名的 cookie,那么依赖该参数的表单将神秘地停止正常工作,因为 cookie 值覆盖了预期的参数。如果您在同一个站点上有多个应用程序,这很容易做到,并且当您只有几个使用旧 cookie 的用户时很难调试- 其他人可以复制。
您可以使用PHP 5.3 中的request_order配置将此行为更改为更明智GP
(否C
)的顺序。如果这是不可能的,我个人会避免,如果我需要一个组合的 GET+POST 数组,请手动创建它。$_REQUEST
我一直在挖掘关于PHP Internals的一些新闻组帖子,并发现了关于该主题的有趣讨论。最初的主题是关于其他内容的,但是 PHP 世界的安全专家(如果不是 )Stefan Esser 的评论将讨论转向了在一些帖子中使用 $_REQUEST 的安全含义。
在 PHP 内部引用Stefan Esser
$_REQUEST 是 PHP 中最大的设计缺陷之一。每个使用 $_REQUEST 的应用程序很可能容易受到延迟跨站点请求伪造问题的影响。(这基本上意味着如果存在一个名为 (age) 的 cookie,它将始终覆盖 GET/POST 内容,因此将执行不需要的请求)
这不是关于有人可以伪造 GET、POST 的事实;COOKIE 变量。这是关于 COOKIE 将覆盖 REQUEST 中的 GET 和 POST 数据的事实。
因此我可以用一个 cookie 感染你的浏览器,比如 action=logout,从那天起你就不能再使用这个应用程序了,因为 REQUEST[action] 将永远注销(直到你手动删除 cookie)。
用 COOKIE 感染你是如此简单......
a) 我可以在子域上的任何应用程序中使用 XSS 漏洞
b) 曾经尝试为 *.co.uk 或 *.co.kr 设置 cookie单域有吗?
c) 其他跨域无论如何...如果您认为这不是问题,那么我可以告诉您,设置 fe 一个 *.co.kr cookie 的简单可能性会导致几个 PHP 版本只返回白页。想象一下:只需一个 cookie 即可杀死 *.co.kr 中的所有 PHP 页面
通过在一个对 *.co.kr 有效的 cookie 中设置一个非法会话 ID,在一个名为 +PHPSESSID=非法的变量中,您仍然可以使用 PHP 会话对韩国的每个 PHP 应用程序进行 DOS...
讨论继续进行一些帖子,阅读起来很有趣。
正如你所看到的,$_REQUEST 的主要问题不在于它有来自 $_GET 和 $_POST 的数据,还有来自 $_COOKIE 的数据。列表中的其他一些人建议更改填充 $_REQUEST 的顺序,例如首先使用 $_COOKIE 填充它,但这可能会导致许多其他潜在问题,例如会话处理。
您可以从 $_REQUEST 全局中完全省略 $_COOKIES,这样它就不会被任何其他数组覆盖(实际上,您可以将其限制为标准内容的任意组合,例如关于variable_order ini 设置的PHP 手册告诉我们:
variable_order 设置 EGPCS(Environment、Get、Post、Cookie 和 Server)变量解析的顺序。例如,如果 variables_order 设置为“SP”,那么 PHP 将创建超全局变量 $_SERVER 和 $_POST,但不会创建 $_ENV、$_GET 和 $_COOKIE。设置为 "" 意味着不会设置超全局变量。
但是话又说回来,您也可能会考虑完全不使用 $_REQUEST,这仅仅是因为在 PHP 中,您可以在自己的全局变量中访问 Environment、Get、Post、Cookie 和 Server,并且减少了一个攻击向量。您仍然需要清理这些数据,但不必担心这一点。
现在您可能想知道,为什么 $_REQUEST 到底存在,为什么它没有被删除。这也是在 PHP Internals 上提出的。引用 Rasmus Lerdorf 关于为什么 $_REQUEST 存在?关于 PHP 内部
我们删除的此类内容越多,人们就越难快速迁移到更新、更快和更安全的 PHP 版本。与一些“丑陋”的遗留功能相比,这给每个人带来了更多的挫败感。如果有一个不错的技术原因、性能或安全性,那么我们需要仔细研究一下。在这种情况下,我们应该关注的不是我们是否应该删除 $_REQUEST,而是我们是否应该从中删除 cookie 数据。许多配置已经这样做了,包括我自己的所有配置,并且在 $_REQUEST 中不包括 cookie 有一个强大的有效安全理由。大多数人使用 $_REQUEST 来表示 GET 或 POST,没有意识到它也可能包含 cookie,因此坏人可能会使用一些 cookie 注入技巧并破坏幼稚的应用程序。
无论如何,希望能有所启发。
$_REQUEST
指各种请求(GET、POST 等)。这有时很有用,但通常最好指定确切的方法($_GET、$_POST 等)。
$_REQUEST
通常被认为是有害的,原因与简单到中等复杂性的数据转换通常在应用程序代码中执行而不是在 SQL 中声明的原因相同:一些程序员很烂。
因此,如果一个人倾向于在$_REQUEST
任何地方使用,我可以通过 GET 做任何我可以通过 POST 做的事情,这意味着在我的(恶意)网站上设置<img>
标签,导致登录到您的电子商务模块的用户静默购买产品,或者我可能导致他们点击会导致危险行为或泄露敏感信息(可能对我而言)的链接。
然而,这是因为一个新手,或者至少是没有经验的 PHP 程序员犯了简单的错误。首先,知道什么类型的数据什么时候合适。例如,我有一个 Web 服务,它可以返回 URLEncoding、XML 或 JSON 的响应。应用程序通过检查 HTTP_ACCEPT 标头来决定如何格式化响应,但可以通过发送format
参数专门强制转换为一个。
检查格式参数的内容时,它可以通过查询字符串或 postdata 发送,这取决于多种因素,其中最重要的是调用应用程序是否希望将“&format=json”与其请求混合。在这种情况下,$_REQUEST
非常方便,因为它让我不必输入如下内容:
$format = isset($_POST['format']) ? $_POST['format']
: (isset($_GET['format']) ? $_GET['format'] : null);
我不会再啰嗦太多了,但我只想说这种$_REQUEST
用法并没有被劝阻,因为它本质上是危险的——它只是另一种工具,可以完全按照要求做,无论你是否理解这些含义——它是导致此问题的贫穷、懒惰或缺乏经验的程序员做出的糟糕、懒惰或不知情的决定。
如何$_REQUEST
安全使用
- 了解您的数据:您应该对您将获得什么样的数据有一些期望,因此请相应地对其进行清理。数据库的数据?
addslashes()
或*_escape_string()
。要将其展示给用户吗?htmlentities()
或htmlspecialchars()
。期待数字数据?is_numeric()
或ctype_digit()
。事实上,filter_input()
它的相关功能旨在检查和清理数据。始终使用这些工具。 - 不要直接访问用户提供的超全局数据。养成每次清理数据的习惯,并将数据移动到干净的变量中,即使它只是
$post_clean
. 或者,您可以直接在超全局变量中进行清理,但我提倡使用单独变量的原因是因为这样做可以很容易地发现代码中的漏洞,因为任何直接指向超全局变量而不是其净化等效项的东西都被认为是危险的错误. - 知道你的数据应该来自哪里。从上面引用我的示例,允许通过 GET 或 POST 发送响应格式变量是完全合理的。我还允许通过任一方法发送“动作”变量。但是,操作本身对于可接受的 HTTP 动词有非常具体的要求。例如,对服务使用的数据进行更改的函数只能通过 POST 发送。对某些类型的非或低权限数据(例如动态生成的地图图像)的请求可以响应来自任一方法的请求而提供服务。
总之,记住这个简单的规则:
安全是你做的,人们!
编辑:
我强烈推荐 bobince 的建议:如果可以的话,将request_order
php.ini 中的参数设置为“GP”;也就是说,没有 cookie 组件。在 98% 以上的情况下,几乎没有合理的理由,因为 cookie 数据几乎不应该被认为与查询字符串或 postdata 相当。
PS,轶事!
我认识一个程序员,他想在$_REQUEST
一个地方简单地存储可以以超全局方式访问的数据。重要的用户名和密码,文件路径,你命名它并且它被存储在$_REQUEST
. 当我告诉他该变量的行为方式时,他有点惊讶(尽管不幸的是,这并不滑稽)。不用说,这种做法已被废除。
GET 请求应该是幂等的,而 POST 请求通常不是。这意味着数据通常应该以不同的方式使用$_GET
。$_POST
如果您的应用程序使用来自 的数据$_REQUEST
,则它对 GET 和 POST 请求的行为相同,这违反了 GET 的幂等性。
这是模糊的。你并不真正知道数据是如何到达你的,因为它携带了 post、get 和 cookie 数据。我不一定认为这总是一件坏事,除非您需要了解或限制交付方式。
我其实很喜欢用它。它为您提供了使用 GET 或 POST 的灵活性,这对于大多数时间都发布数据的搜索表单之类的事情非常有用,但有时您会想说链接到特定搜索,因此您可以使用 GET 参数代替.
此外,如果您查看许多其他语言(例如 ASP.NET),它们根本不会区分 GET 和 POST 变量。
预计到达时间:
我从来没有使用 REQUEST 来获取 COOKIE 值,但我认为 Kyle Butt 在这篇文章的评论中提出了一个很好的观点。使用 REQUEST 获取 COOKIE 值不是一个好主意。我相信他是对的,如果你这样做,跨站点请求伪造的真正可能性是存在的。
此外,将内容加载到 REQUEST 的顺序由 php.ini 中的配置参数(variables_order 和 request_order)控制。因此,如果您通过 POST 和 GET 传入相同的变量,则实际进入 REQUEST 的变量取决于这些 ini 设置。如果您依赖特定订单并且这些设置的配置与您预期的不同,这可能会影响可移植性。
唯一一次使用$_REQUEST
不是一个坏主意是使用 GET。
- 如果您使用它来加载 POST 值,则存在跨站点请求伪造的风险
- 如果您使用它来加载 cookie 值,您将再次冒跨站点请求伪造的风险
即使使用 GET,$_GET
键入也比$_REQUEST
;)
了解何时使用 POST、何时使用 GET 以及何时使用 cookie 很重要。使用 $_REQUEST,您正在查看的值可能来自其中任何一个。如果您希望从 POST 或 GET 或从 COOKIE 获取值,那么对于阅读您的代码的人使用特定变量而不是 $_REQUEST 会提供更多信息。
其他人还指出,您不希望所有 POST 或 cookie 都被 GET 覆盖,因为它们都有不同的跨站点规则,例如,如果您在使用 $_REQUEST 时返回 ajax 数据,那么您很容易受到攻击跨站点脚本攻击。
我可能仅在您想检索当前 url 或主机名时使用,但对于实际解析来自该 URL 的数据,例如使用 & 符号的参数,这可能不是一个好主意。一般来说,您不想对您正在尝试做的事情进行模糊的描述。如果您需要具体说明,那就是 $_REQUEST 不好的地方,如果您不需要具体说明,请随意使用它。我会想。
如果你知道你想要什么数据,你应该明确地要求它。IMO、GET 和 POST 是两种不同的动物,我想不出为什么您需要混合发布数据和查询字符串的充分理由。如果有人有的话,我会很感兴趣。
当您的脚本可能以相同的方式响应 GET 或 POST 时,使用 $_REQUEST 会很方便。尽管我认为这应该是一种极其罕见的情况,并且在大多数情况下,两个独立的函数来处理两个独立的概念,或者至少检查方法并选择正确的变量是首选。当不需要交叉引用变量可能来自哪里时,程序流程通常更容易遵循。善待必须在 6 个月内维护您的代码的人。可能是你。
除了由 REQUEST 变量中的 cookie 和环境变量引起的安全问题和 WTF(不要让我开始使用 GLOBAL),请考虑如果 PHP 开始原生支持其他方法(例如 PUT 和 DELETE)将来会发生什么。虽然它们极不可能被合并到 REQUEST 超全局中,但它们可能会作为 on 选项包含在 variable_order 设置中。所以你真的不知道 REQUEST 是什么,什么是优先的,特别是如果你的代码部署在第三方服务器上。
POST 比 GET 更安全吗?并不真地。最好在可行的情况下使用 GET,因为在您的日志中更容易看到您的应用程序在受到攻击时是如何被利用的。POST 更适合影响域状态的操作,因为蜘蛛通常不会跟随它们,并且预测获取机制不会在您登录 CMS 时删除您的所有内容。但是,问题不在于 GET 与 POST 的优点,而在于接收器应如何处理传入的数据以及为什么合并它不好,所以这实际上只是一个顺便说一句。
我认为 没有问题$_REQUEST
,但是我们在使用它时必须小心,因为它是来自 3 个源 (GPC) 的变量的集合。
我想$_REQUEST
仍然可以使旧程序与新的 php 版本兼容,但是如果我们启动新项目(包括新库),我认为我们不应该再使用$_REQUEST
以使程序更清晰。$_REQUEST
我们甚至应该$_REQUEST
考虑删除$_POST
.
// delete $_REQUEST when program execute, the program would be lighter
// when large text submitted
unset($_REQUEST);
// wrapper function to get request var
function GetRequest($key, $default = null, $source = '')
{
if ($source == 'get') {
if (isset($_GET[$key])) {
return $_GET[$key];
} else {
return $default;
}
} else if ($source == 'post') {
if (isset($_POST[$key])) {
return $_POST[$key];
} else {
return $default;
}
} else if ($source == 'cookie') {
if (isset($_COOKIE[$key])) {
return $_COOKIE[$key];
} else {
return $default;
}
} else {
// no source specified, then find in GPC
if (isset($_GET[$key])) {
return $_GET[$key];
} else if (isset($_POST[$key])) {
return $_POST[$key];
} else if (isset($_COOKIE[$key])) {
return $_COOKIE[$key];
} else {
return $default;
}
}
}
Darren Cook: “从 php 5.3 开始,默认的 php.ini 表示只有 GET 和 POST 数据被放入
$_REQUEST
. 见php.net/request_order我只是在期望 cookie 数据进入时偶然发现了这个向后兼容中断,$_REQUEST
并想知道为什么它没有”不工作!”
哇......我的一些脚本因为升级到 PHP 5.3而停止工作。做了同样的事情:假设在使用$_REQUEST
变量时会设置 cookie。随着升级完全停止工作。
$_COOKIE["Cookie_name"]
我现在使用...分别调用 cookie 值
Just make sure to set correct parameter in your php.ini (below is default, as long as not set to GPC, no Cookies are used here)
request_order = "GP"
which means POST overwrites GET and you'll be fine.
The reason for $_REQUEST
is simply consolidation of $_GET and $_POST.
When sending a form and navigation through lots of links on your page, it is very usefull to have one place which holds the state: $_REQUEST
正如其他人所说,核心问题是它包含 cookie。
在 PHP 7 中,您可以这样做:
$request = array_merge($_GET ?? [], $_POST ?? []);
这避免了 cookie 问题,并且在最坏的情况下为您提供一个空数组,最好是 $_GET 和 $_POST 的合并,后者优先。如果您不太介意通过查询字符串允许 URL 注入参数,这非常方便。
这是非常不安全的。这也很尴尬,因为您不知道您收到的是 POST 还是 GET 或其他请求。在设计应用程序时,您真的应该知道它们之间的区别。GET 非常不安全,因为它是在 URL 中传递的,除了页面导航之外几乎不适合任何东西。POST 虽然本身也不安全,但提供了一个安全级别。