使用$ _REQUEST []有什么问题?


116

我在这里看到许多帖子说不要使用该$_REQUEST变量。我通常不这样做,但有时很方便。它出什么问题了?


2
请参阅相关的问题和答案:stackoverflow.com/questions/1149118/...
戈登

2
自php 5.3起,默认的php.ini表示仅将GET和POST数据放入$_REQUEST。请参阅php.net/request_order,当我期望cookie数据进入$_REQUEST并想知道为什么它不起作用时,我偶然发现了这个向后兼容中断!因此,避免使用$ _REQUEST的最大原因是您的脚本无法自行设置request_order(它是PHP_INI_PERDIR),因此php.ini更改很容易破坏您的脚本所基于的假设。最好将这些假设直接放入脚本中。
Darren Cook

Answers:


184

但绝对没有错,采取从两个输入$_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


2
这些情况(数据太长,通过GET提交)是一个例外,不是规则
本·詹姆斯

1
好答案。我还注意到,使用Zend Framework这样的框架,GET和POST参数被组合为1个请求对象。直到我阅读您的帖子,它才触动我。
杰伊·西德里

默认情况下,从PHP 5.4+起,request_order配置在php.ini中设置为“ GP”,所以我会说吧...但还是一如既往,请谨慎行事。
bcmoney 2013年

如果$ _POST是a="foo"和$ _COOKIE a="bar",那么这里会有任何覆盖/冲突吗?
Rust

75

我一直在研究有关PHP Internals的一些新闻组帖子,并找到了关于该主题的有趣讨论。初始线程是别的事情,但此话出自Stefan Esser,如果一个(如果不是在PHP世界)的安全专家转向使用$ _REQUEST几个职位的安全性问题的讨论。

在PHP Internals上引用Stefan Esser

$ _REQUEST是PHP中最大的设计弱点之一。每个使用$ _REQUEST的应用程序很可能容易受到“跨站点请求伪造”问题的影响。(这基本上意味着,例如,如果存在一个名为(age)的cookie,它将始终覆盖GET / POST内容,因此将执行不需要的请求)

并在以后回复同一主题

这与某人可以伪造GET,POST无关;COOKIE变量。关于COOKIE将覆盖REQUEST中的GET和POST数据这一事实。

因此,我可能会用一个说“ action = logout”的cookie感染您的浏览器,并且从那天起您将无法再使用该应用程序,因为REQUEST [action]将永远注销(直到您手动删除cookie)。

用COOKIE感染您非常简单...
a)我可以在子域上的任何应用程序中使用XSS vuln
b)曾经尝试在拥有* .co.uk或* .co.kr时设置cookie单域?
c)其他跨域方式...

如果您认为这不是问题,那么我可以告诉您,可以简单地将fe设置为* .co.kr cookie,从而导致多个PHP版本仅返回白页。想象一下:只需一个cookie即可杀死* .co.kr中的所有PHP页面

并且通过在一个有效于* .co.kr的cookie中为一个名为+ PHPSESSID = 非法的变量设置一个非法的会话ID,您仍然可以使用PHP会话来DOS DOS韩国的每个PHP应用程序...

讨论仍在继续,还有更多的帖子,阅读起来很有趣。


如您所见,$ _ REQUEST的主要问题不仅仅在于它具有来自$ _GET和$ _POST的数据,而且还具有来自$ _COOKIE的数据。列表中的其他一些人建议更改$ _REQUEST的填充顺序,例如,先用$ _COOKIE填充它,但这可能导致许多其他潜在的问题,例如会话处理

您可以从$ _REQUEST全局变量中完全省略$ _COOKIES,这样它就不会被其他任何数组覆盖(实际上,您可以将其限制为标准内容的任意组合,例如variable_order ini设置上的PHP手册)告诉我们:

variable_order设置EGPCS(环境,获取,发布,Cookie和服务器)变量解析的顺序。例如,如果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注入技巧并破坏朴素的应用程序。

无论如何,希望能有所启发。


1
+1很高兴看到对此的一些讨论...我以为我快疯了!
bobince 2010年

2
我认为讨论有些笼统。实际的问题是开发人员没有意识到,而不是$ _REQUEST本身中存在cookie。例如,固定的PHPSESSID无论如何都将使用现代会话处理代码通过每个域cookie进行重置。对于某些应用程序,可能真的需要cookie覆盖请求变量(例如sort_order = ASC覆盖搜索表单GET var)。尽管以这种方式进行显式编码更为明智。
马里奥

1
非常全面的帖子,这应该是答案。也许人们担心长期发表;)
Dzung Nguyen 2011年

可悲的是,拉斯穆斯(Rasmus)在2009年对此发表了评论,但是$ _REQUEST现在在2015
。– Kzqai

10

$_REQUEST指各种请求(GET,POST等。)。有时这很有用,但通常最好指定确切的方法($ _GET,$ _ POST等)。


19
此答案描述了$ _REQUEST是什么,但未回答该问题。
zombat 2010年

1
他说的是,更好的做法是知道将要传入的请求类型并对该特定请求进行编码。
Polaris878 2010年

8

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

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

但是,这是由于PHP程序员(或者至少没有经验)犯了简单的错误。首先,知道什么时候适合什么类型的数据。例如,我有一个Web服务,可以返回URLEncoding,XML或JSON的响应。该应用程序通过检查HTTP_ACCEPT标头来决定如何格式化响应,但是可以通过发送format参数将其强制转换为一个格式。

检查format参数的内容时,可以根据多种因素,通过查询字符串或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”变量。但是,这些操作本身对于哪个HTTP Verb是可以接受的有非常具体的要求。例如,更改服务所用数据的功能只能通过POST发送。对于某些类型的非特权或低特权数据(例如动态生成的地图图像)的请求可以响应于来自任何一种方法的请求而被提供。

总之,请记住以下简单规则:

人民就是安全的保障!

编辑:

强烈建议bobince的建议:如果可以,请将request_orderphp.ini中的参数设置为“ GP”;也就是说,没有cookie组件。在98%以上的案例中,几乎没有合理的理由,因为cookie数据几乎永远不应被视为与查询字符串或后数据具有可比性。

PS,轶事!

我认识一个程序员,他想到了$_REQUEST一个地方,可以简单地存储以超全局方式访问的数据。重要的用户名和密码,文件路径,您都将其命名并存储在中$_REQUEST。当我告诉他该变量的行为方式时,他感到有些惊讶(尽管不幸的是,并非如此)。不用说,这种做法已被废除。


8

GET请求应该是幂等的,而POST请求通常不是。这意味着,在数据$_GET$_POST一般应该以不同的方式使用。

如果您的应用程序使用的数据$_REQUEST,则它对于GET和POST请求的行为将相同,这违反了GET的幂等性。


1
但这不取决于实现吗?“ Indempotent”对我来说是一个新词,但是如果我正确理解它,那么可以很容易地想象到设置不是非幂等的GET情况。例如,每次您请求给定的URL时,页面计数器通常都会增加。
sprugman 2010年

1
@sprugman-同样,您可能会遇到在同一请求中同时具有GET数据 POST数据的情况,在这种情况下,将请求方法与请求数据进行上下文关联时,该请求方法实际上是毫无意义的。
zombat 2010年

sprugman,显然任何GET请求都会修改某些内容,因为它是由Web服务器记录的。它在该元数据并不重要的应用程序域中仍然可以独立存在。
本·詹姆斯

@sprugman-这里的一般想法是,您不应具有修改数据的GET请求。造成这种情况不好的一个典型示例是网络蜘蛛对您的网站进行爬网,并跟踪无意间修改数据的链接。例如,SO帖子上的“标志”链接。
埃里克·彼得罗列

那是一个简单的例子。如果我通过ajax使用GET会怎么样,因为它更快(如carsonified carsonified.com/blog/dev/the-definitive-guide-to-get-vs-post上的这篇文章中所建议)。
sprugman 2010年

7

含糊不清。你不真正了解数据得到了你,因为它携带后,获得和cookie数据。我不一定认为这总是一件坏事,除非您需要了解或限制交付方式。


3

我实际上很喜欢使用它。它使您可以灵活地使用GET或POST,这对于大多数情况下都发布POST的搜索表单之类的事情很方便,但是有时您需要说链接到特定的搜索,因此可以改用GET参数。

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

预计到达时间

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

另外,将东西装入REQUEST的顺序由php.ini中的配置参数(variables_order和request_order)控制。因此,如果您通过POST和GET传递了相同的变量,那么实际上进入REQUEST的变量取决于这些ini设置。如果您依赖于特定的顺序,并且这些设置的配置与预期不同,则可能会影响可移植性。


那是一个可怕的错误。如何保证在POST上执行了非幂等动作?
凯尔·巴特

1
@Kyle-通过不将其用于非等幂动作。我当然不会将它用于所有内容,只是指出它很有用,例如在示例中提到的搜索。
埃里克·彼得罗里耶

1
_POST是安全的,而_GET不是安全的这种神奇的想法必须走。如果我没有正确使用您的软件,那么发送POST请求和GET请求对我的影响就很小(如果有的话)。安全性在于您对数据的处理方式,而不是数据的来源。至于简单的XSS / Request漏洞利用,很可能仅将_REQUEST用于仅适用于POST或GET的值,而仅将_POST用于应发布的内容。常识,而不是不可思议的超全局用法。
2010年

1
@Kyle-我仍然看不到如何使用curl()或ajax post之类的东西通过POST和COOKIE传递相同的数据一样轻松地做您提到的事情。无论您使用REQUEST,GET,POST还是COOKIE,所有数据最终都是来自客户端的,并且总是可以被伪造的。
埃里克·彼得罗列

1
@zombat:您形成的curl请求不会以易受攻击的用户身份登录。您创建并放置在您网站上的链接将会。@Dereleased:这不是神奇的想法,GET仍然存在许多漏洞。但是信任登录用户的POST比登录用户的GET更安全。
凯尔·巴特

2

了解何时使用POST,何时使用GET以及何时使用cookie至关重要。使用$ _REQUEST,您正在查看的值可能来自其中任何一个。如果您希望从POST或GET或COOKIE中获取值,那么对于阅读代码以使用特定变量而不是$ _REQUEST的人来说,这更有意义。

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


2

唯一一次使用$_REQUESTGET并不是一个坏主意。

  • 如果使用它加载POST值,则可能会冒用跨站请求伪造的风险
  • 如果使用它加载Cookie值,则再次冒着跨站点请求伪造的风险

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


虽然我同意您的看法,但我认为重要的是要指出为什么这是真实的和/或危险的:$_POST在重要的是数据为POSTDATA的情况下应该使用。$_REQUEST当数据与所使用的HTTP Verb无关时,应使用此选项。在所有这些情况下,应仔细清理所有输入数据。
2010年

1
我看不到数据源与跨站点请求伪造的可能性如何相关。攻击者可以通过向用户提供指向您站点的POST表单来轻松地完美设置POST参数。无论提交是来自GET还是POST,您都将需要相同的反XSRF保护措施。
bobince 2010年

滥用GET进行伪造要容易得多。例如,您可以简单地将img标签的src设置为所需的参数。它可以在用户不知道它在那里的情况下工作。
Jani Hartikainen

0

仅当您想检索当前的URL或主机名时,才可以使用我,但实际上要使用&符号从该URL解析数据(例如参数),这可能不是一个好主意。通常,您不想对要执行的操作使用模糊的描述。如果需要具体说明$ _REQUEST不好的地方,如果不需要具体说明,请随时使用。我会想。


你想说什么 你混淆$_REQUEST$_SERVER['QUERY_STRING']
2010年

0

如果知道所需的数据,则应明确要求它。IMO,GET和POST是两种不同的动物,我想不出为什么需要混合使用post数据和查询字符串的充分理由。如果有人有,我会很感兴趣。

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

除了由cookie和REQUEST变量中的环境变量引起的安全性问题和WTF(不要让我开始使用GLOBAL)之外,请考虑一下如果PHP开始原生支持其他方法(例如PUT和DELETE),将来会发生什么。尽管将它们合并到REQUEST超全局变量中的可能性很小,但有可能将它们作为on_option的变量包含在variable_order设置中。因此,您实际上不知道REQUEST的内容以及优先级,特别是如果您的代码部署在第三方服务器上。

POST比GET安全吗?并不是的。最好在实际情况下使用GET,因为在日志中更容易看到攻击时如何利用您的应用程序。POST更适合影响域状态的操作,因为蜘蛛通常不会跟随它们,并且当您登录CMS时,预测性提取机制不会删除您的所有内容。但是,问题不是关于GET vs POST的优点,而是关于接收方应该如何处理传入的数据以及为什么合并起来不好,所以这实际上只是一个BTW。


0

我认为没问题$_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; 
    } 
  }
}

0

达伦·库克(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值


-1

中心问题是,正如其他人所说的,它包含cookie。

在PHP 7中,您可以执行以下操作:

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

这样可以避免cookie的问题,并在最坏的情况下为您提供一个空数组,并最好将$ _GET和$ _POST合并,后者优先。如果您不太愿意允许通过查询字符串进行参数的URL注入,则非常方便。


那些选择投票的人,请解释一下我的观点。
amh15

-2

这是非常不安全的。另外,由于您不知道自己正在获取POST还是GET或其他请求,因此这很尴尬。在设计应用程序时,您确实应该了解它们之间的区别。GET是非常不安全的,因为它是在URL中传递的,除了页面导航之外,它几乎不适合其他任何内容。POST虽然本身也不安全,但可以提供一种安全级别。


4
$ _POST和$ _GET之间的安全性没有区别,只是您无法在浏览器URL栏中键入POST请求。但是,使用POST发出命令行cURL请求只需要5秒。
zombat 2010年

3
@Zombat:我们需要启动某种活动,以说服人们POST本质​​上不比GET安全,甚至不比GET更安全。安全性在于如何处理数据,而不是使用HTTP Verb将数据传输到那里的方式。
2010年

@Dereleased-我提出了云的标志性双色调图片,上面有一些闪电来代表互联网,下面是单词“ CHANGE”。
zombat 2010年

1
@GuyT:这是一个非常狭narrow的观点。这不仅关乎它的“安全性”,还关乎它的机密性。GET参数可以显示为浏览器URL中的自动完成功能,甚至可以显示为浏览器历史记录。此外,安全性并不会因浏览器而终止。例如,许多服务器记录http url,因此该URL中的任何内容都会被记录。在日志中显示用户名/密码确实有所作为。出于安全考虑,请始终避免将敏感信息作为GET参数传递。
2014年

1
特别是Apache访问日志。任何请求URL都会被记录,任何有权访问日志的人都可以看到您的凭据通过。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.