使用 $_ REQUEST []有什么错?

我在这里看到很多帖子说不要使用 $_REQUEST变量。我通常不会,但有时候很方便。有什么问题吗?

59451 次浏览

很模糊。您不知道 真的是如何获取数据的,因为它携带 post、 get 和 cookie 数据。我不一定认为这总是一件坏事,除非你 需要知道或限制的方法交付。

$_REQUEST指的是所有类型的请求(GET、 POST 等).这有时很有用,但通常指定确切的方法($_ GET、 $_ POST 等)更好。

GET requests should be idempotent and POST requests are generally not. This means that data in $_GET and $_POST should generally be used in different ways.

如果您的应用程序正在使用来自 $_REQUEST的数据,那么它对 GET 和 POST 请求的行为将是相同的,这违反了 GET 的幂等性。

使用 $_REQUEST的唯一好处就是使用 GET。

  • 如果使用它来加载 POST 值,则存在跨站点请求伪造的风险
  • If you use it to load cookie values, you again risk cross-site request forgeries

即使使用 GET,$_GET的类型也比 $_REQUEST短;)

I actually like using it. It gives you the flexibility to use GET or POST which can come in handy for things like search forms where most of the time data is POSTed, but sometimes you'll want to say link to a particular search, so you can use GET parameters instead.

另外,如果您查看许多其他语言(例如 ASP.NET) ,它们根本不区分 GET 和 POST 变量。

预计抵达时间:

我从来没有使用过 REQUEST 来获取 COOKIE 值,但是我认为 Kyle Butt 在这篇文章的评论中提出了一个很好的观点。使用 REQUEST 获取 COOKIE 值并不是一个好主意。我相信他是对的,如果你这样做,跨站请求伪造确实有潜力。

另外,将内容加载到 REQUEST 中的顺序由 php.ini 中的配置参数(variable _ order 和 REQUEST _ order)控制。因此,如果通过 POST 和 GET 传入相同的变量,那么实际进入 REQUEST 的变量取决于这些 ini 设置。如果您依赖于特定的顺序,并且这些设置的配置与您预期的不同,那么这可能会影响可移植性。

非常没有安全感。另外,这也很尴尬,因为你不知道你是否得到一个 POST 或 GET,或另一个请求。在设计应用程序时,您确实应该知道它们之间的区别。GET 是非常不安全的,因为它是在 URL 中传递的,除了页面导航之外几乎不适合其他任何东西。虽然 POST 本身也不安全,但它提供了一定程度的安全性。

了解何时使用 POST、何时使用 GET 以及何时使用 cookie 非常重要。使用 $_ REQUEST,您正在查看的值可能来自其中任何一个。如果您希望从 POST 或 GET 或 COOKIE 中获取值,那么对于正在阅读您的代码的人来说,使用特定的变量而不是 $_ REQUEST 会提供更多信息。

还有人指出,您不希望所有的 POST 或 cookie 都被 GET 覆盖,因为它们都有不同的跨站点规则,例如,如果您在使用 $_ REQUEST 时返回 ajax 数据,那么您很容易受到跨站点脚本攻击。

我可能只在您想要检索当前的 URL 或主机名时使用,但是对于实际解析来自该 URL 的数据(如使用 & 符号的参数)来说,这可能不是一个好主意。一般来说,你不想用一个模糊的描述你正在尝试做什么。如果您需要具体说明 $_ REQUEST 在哪里不好,如果您不需要具体说明,那么您可以随意使用它。我会这么想。

$_GET$_POST以一种组合的方式获取输入绝对没有什么错。事实上,你几乎总是想这么做:

  • 对于通常通过 GET 提交的普通幂等请求,存在这样一种可能性,即您想要的数据量无法放入 URL 中,因此作为一个实际问题,它已经被突变为一个 POST 请求。

  • 对于具有实际效果的请求,必须检查它是否由 POST 方法提交。但是这样做的方法是显式地检查 $_SERVER['REQUEST_METHOD'],而不是依赖于对于 GET 来说 $_POST是空的。无论如何,如果该方法是 POST,您仍然可能希望从 URL 中提取一些查询参数。

No, the problem with $_REQUEST is nothing to do with conflating GET and POST parameters. It's that it also, by default, includes $_COOKIE. And cookies really aren't like form submission parameters at all: you almost never want to treat them as the same thing.

如果您不小心在站点上获得了一个与表单参数同名的 Cookie 集,那么依赖于该参数的表单将神秘地停止正常工作,原因是 Cookie 值覆盖了预期的参数。如果你在同一个站点上有多个应用程序,这是很容易做到的,而且如果你只有几个用户使用旧的 cookies,你不再使用任何其他人无法复制的方式来挂起和破坏表单,那么调试起来会非常困难。

You can change this behaviour to the much more sensible GP (no C) order with the Request _ order config in PHP 5.3. Where this is not possible, I personally would avoid $_REQUEST and, if I needed a combined GET+POST array, create it manually.

$_REQUEST通常被认为是有害的,其原因与简单到中等复杂度的数据转换通常在应用程序代码中执行而不是在 SQL 中声明的原因相同: 有些程序员烂透了。

因此,如果一个人倾向于在任何地方使用 $_REQUEST,我可以通过 GET 做任何事情,我可以通过 POST,这意味着在我的(恶意)网站上设置 <img>标签,导致用户登录到你的电子商务模块默默购买产品,或者我可以导致他们点击链接,将导致危险的行动或泄露敏感信息(可能对我来说)。

然而,这是因为一个初学者,或者至少是没有经验的 PHP 程序员犯了一些简单的错误。首先,要知道什么类型的数据是合适的。例如,我有一个 Web 服务,它可以以 URLEncoding、 XML 或 JSON 的形式返回响应。应用程序通过检查 HTTP _ ACCEPT 头来决定如何格式化响应,但是可以通过发送 format参数来强制格式化响应。

在检查 format 参数的内容时,它可以通过 querystring 或 postdata 发送,这取决于多种因素,其中最重要的因素是调用应用程序是否希望将“ & format = json”与其请求混合在一起。在这种情况下,$_REQUEST是非常方便的,因为它省去了我输入如下内容的麻烦:

$format = isset($_POST['format']) ? $_POST['format']
: (isset($_GET['format']) ? $_GET['format'] : null);

我不打算再继续下去了,但是我只想说,$_REQUEST的使用并没有被阻止,因为它本身就是危险的——它只是另一个完全按照要求去做的工具,不管你是否理解这些含义——是一个可怜的、懒惰的或者缺乏经验的程序员的可怜的、懒惰的或者不知情的决定导致了这个问题。

如何安全使用 $_REQUEST


  1. 了解您的数据 : 您应该对您将获得哪种类型的数据有一些期望,因此相应地清理它。数据库的数据?addslashes()*_escape_string()。要把它显示给用户吗?htmlentities()htmlspecialchars()。在等数据吗?is_numeric()ctype_digit()。事实上,filter_input()及其相关功能的设计目的只是检查和消毒数据。一定要用这些工具。
  2. 不要直接访问用户提供的 superglobals 数据 。养成每次清理数据的习惯,并将数据移动到清理变量,即使它只是 $post_clean。或者,你可以直接在超级全局变量中进行清理,但我提倡使用单独变量的原因是这样做可以很容易地发现代码中的漏洞,因为 什么都行直接指向一个超级全局变量,而不是它经过清理的等价变量被认为是一个危险的错误。
  3. 知道你的数据应该从哪里来。参考我上面的例子,允许通过 GET 或 POST 发送响应格式变量是完全合理的。我还允许通过任一方法发送“ action”变量。然而,the actions themselves have very specific requirements as to which HTTP Verb is acceptable。例如,对服务使用的数据进行更改的函数只能通过 POST 发送。对某些类型的非或低特权数据(例如动态生成的地图图像)的请求可以响应来自这两种方法的请求。

总之,记住这个简单的规则:

安全是靠你们自己做出来的,各位!

编辑:

我推荐 bobince 的建议: 如果可以的话,将 php.ini 中的 request_order参数设置为“ GP”; 也就是说,不要使用 cookie 组件。在98% 以上的情况下,几乎没有合理的推理,因为 Cookie 数据几乎从来不应该被认为与查询字符串或后期数据相比较。

附注,轶事!

我认识一个程序员,他认为 $_REQUEST是一个简单存储数据的地方,可以通过超全局方式访问。重要的用户名和密码,文件路径,你命名它,它是存储在 $_REQUEST。当我告诉他这个变量是如何工作的时候,他有点惊讶(虽然不是那么滑稽,不幸的是)。不用说,这种做法已经被废除了。

我一直在浏览 PHP 内部上的一些新闻组帖子,发现了一个关于这个话题的有趣讨论。最初的线程是关于其他事情的,但是由 Stefan Esser,PHP 世界(如果不是 的话)的安全专家所说的一句话将讨论转向了对一些帖子使用 $_ REQUEST 的安全影响。

引用 关于 PHP 内部的 Stefan Esser

$_ REQUEST 是 PHP 最大的设计弱点之一 $_ REQUEST 最有可能受到延迟跨站点请求的攻击 伪造问题。(这基本上意味着,如果,例如,一个 cookie 命名(年龄) 如果存在,它将总是覆盖 GET/POST 内容,因此 将执行不需要的请求)

还有 回复同一个帖子

它不是关于某人可以伪造 GET、 POST; COOKIE 变量的事实。 中覆盖 GET 和 POST 数据的事实 请求。

因此,我可以感染你的浏览器与一个 cookie 说,例如。 Action = 注销,从那天起你就不能使用这个应用程序了 因为请求[操作]将永远注销(直到您 手动删除 cookie)。

用饼干感染你很简单。
A)我可以在子域的任何应用程序中使用 XSS vuln
B)如果你有一个饼干,你可以尝试为 * . co.uk 或 * . co.kr 设置一个 cookie 单一域名?
C)其他跨域无论如何... < br/>

如果你认为这不是问题,我可以告诉你 有一个简单的可能性,设置 fe.a * . co.kr cookie,结果 在几个 PHP 版本中只返回白页。 Imagine: Just a single cookie to kill all PHP pages in *.co.kr

And by setting an illegal session ID in a cookie valid for *.co.kr in a 变量 + PHPSESSID = 非法的你仍然可以 DOS 每个 PHP 应用程序在韩国使用 PHP 会话..。

继续讨论更多的帖子和有趣的阅读。


正如您所看到的,$_ REQUEST 的主要问题不在于它有来自 $_ GET 和 $_ POST 的数据,而是来自 $_ COOKIE 的数据。列表中的其他一些人建议更改 $_ REQUEST 的填充顺序,例如,先用 $_ COOKIE 填充,然后用 这可能会导致许多其他潜在的问题,例如会话处理填充。

你可以从 $_ REQUEST 全局中完全省略 $_ COOKIES,这样它就不会被其他数组覆盖(事实上,你可以限制它的标准内容的任何组合,就像 关于 < em > variable _ order ini 设置的 PHP 手册告诉我们的那样:

variable_order Sets the order of the EGPCS (Environment, Get, Post, Cookie, and Server) variable parsing. For example, if variables_order is set to "SP" then PHP will create the superglobals $_SERVER and $_POST, but not create $_ENV, $_GET, and $_COOKIE. Setting to "" means no superglobals will be set.

不过话又说回来,您可能还会考虑不要完全使用 $_ REQUEST,因为在 PHP 中,您可以访问 Environment、 Get、 Post、 Cookie 和 Server 在它们自己的全局变量中,并且少了一个攻击向量。您仍然需要对这些数据进行消毒,但这样就少了一件需要担心的事情。


现在您可能想知道,究竟为什么 $_ REQUEST 存在,为什么它没有被删除。PHP Internals 也提出了这个问题。在 PHP 内部引用关于 为什么存在 $_ REQUEST?的 Rasmus Lerdorf

我们移除的这种东西越多,人们就越难移除 迅速转向更新、更快、更安全的 PHP 版本 给每个人带来的挫折远远超过一些“丑陋”的遗产 如果有合适的技术原因、性能或 安全,那么我们需要认真审查它。在这种情况下, thing we should be looking at isn't whether we should remove $_REQUEST 而是我们是否应该从中删除 cookie 数据 already do that, including all of my own, and there is a strong valid $_ REQUEST 中不包含 cookie 的安全原因 $_ REQUEST 表示 GET 或 POST,没有意识到它也可以包含 像 Cookie 这样的坏人可能会做一些 Cookie 注射 欺骗和破坏幼稚的应用程序。

不管怎样,希望这能给我们一些启示。

如果您知道需要什么数据,那么应该显式地请求它。IMO,GET 和 POST 是两种不同的动物,我想不出一个好的理由为什么你需要混合后数据和查询字符串。如果有人有的话,我会很感兴趣的。

当您的脚本可能以相同的方式响应 GET 或 POST 时,使用 $_ REQUEST 会很方便。但我认为这种情况应该是极其罕见的,在大多数情况下,两个单独的函数处理两个单独的概念,或者至少检查方法并选择正确的变量,是首选的。当不需要交叉引用变量的来源时,程序流通常更容易跟踪。对那些必须在6个月内维护您的代码的人友好一些。可能是你。

除了 REQUEST 变量中的 cookie 和环境变量引起的安全问题和 WTF 之外(不要让我从 GLOBAL 开始) ,考虑一下如果 PHP 开始本机支持其他方法,比如 PUT 和 DELETE,将来会发生什么。虽然将它们合并到 REQUEST superglobal 中的可能性极小,但是它们可以作为 on 选项包含在 variable _ order 设置中。因此,您真的不知道 REQUEST 持有什么,什么是优先级,特别是当您的代码部署在第三方服务器上时。

Is POST safer than GET? Not really. It's better to use GET where practical because it's easier to see in your logs how your application is being exploited when it gets attacked. POST is better for operations that affect domain state because spiders generally don't follow them, and predictive fetching mechanisms won't delete all your content when you log into your CMS. However, the question was not about the merits of GET vs POST, it was about how the receiver should treat the incoming data and why it's bad to merge it, so this is really just a BTW.

I think there is no problem with $_REQUEST, but we must be careful when using it since it is a collection of variables from 3 sources (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: "Since php 5.3 the default php.ini says only GET and POST data are put into $_REQUEST. See Php.net/request_order I just 在期待 cookie 时无意中发现了这个向后兼容性中断 数据放在 $_REQUEST里,想知道为什么它不起作用!”

哇... 我的一些脚本因为 升级到 PHP 5.3而停止工作了。执行相同的操作: 假设在使用 $_REQUEST变量时将设置 cookie。 升级完全停止工作。

我现在使用 $_COOKIE["Cookie_name"]分别调用 cookie 值..。

正如其他人所说,核心问题在于它包含 cookie。

在 PHP7中可以这样做:

$request = array_merge($_GET ?? [], $_POST ?? []);

This avoids the cookie problem and gives you at worst an empty array and at best a merger of $_GET and $_POST with the latter taking precedence. If you are not too bothered with allowing URL injection of parameters through the query string, it's quite convenient.

只要确保在 Php.ini中设置正确的 参数(下面是默认值,只要没有设置为 GPC,这里就不会使用 Cookie)

request_order = "GP"

which means 职位 overwrites 走开 and you'll be fine.

$_REQUEST的原因仅仅是 $_ GET 和 $_ POST 的 合并。 当发送一个表单和导航通过许多链接在您的网页上,它是非常有用的有 一个地方持有的 国家: $_REQUEST