使用$ _REQUEST 有什么问题?

我在这里看到了一些post,说不要使用$_REQUESTvariables。 我通常不会,但有时候很方便。 它出什么问题了?

综合考虑$_GET$_POSTinput是绝对没有问题的。 事实上,这就是你几乎总是想要做的事情:

  • 对于通常通过GET提交的普通幂等请求,有可能你想要的数据量不适合在一个URL中,所以它被改变为一个POST请求,而不是实际的问题。

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

不,与$_REQUEST的问题与合并GET和POST参数无关。 这也是,默认情况下,它包含$_COOKIE 。 而cookies实际上不像表单提交参数那样:你几乎从不想把它们看作是一样的东西。

如果您不小心在您的网站上设置了与您的某个表单参数同名的Cookie,则由于Cookie值覆盖了预期的参数,依赖该参数的表单将神秘地停止正常工作。 如果你在同一个网站上有多个应用程序,这很容易做到,而当你只有几个用户使用旧的cookies时,你可能会很难debugging,你不会再用任何方式来挂断, – 其他人可以重现。

您可以使用PHP 5.3中的request_orderconfiguration将此行为更改为更合理的GP (无C )顺序。 如果这是不可能的,我个人会避免$_REQUEST ,如果我需要一个组合的GET + POST数组,手动创build它。

我一直在挖掘PHP内幕的一些新闻组post,并发现了一个有趣的话题讨论。 最初的主题是关于别的东西,但是在PHP世界中(如果不是)安全专家Stefan Esser把这个讨论转向了使用$ _REQUEST几个post的安全隐含的讨论。

引用PHP内部的Stefan Esser

$ _REQUEST是PHP中最大的devise弱点之一。 每个使用$ _REQUEST的应用程序最有可能容易出现延迟跨站点请求伪造问题。 (这基本上意味着,如果例如名为(年龄)的cookie存在,它将总是覆盖GET / POST内容,因此不需要的请求将被执行)

并在稍后的回复相同的线程

这不是关于有人可以伪造GET,POST的事实。 COOKIEvariables。 COOKIE会在REQUEST中覆盖GET和POST数据。

因此,我可以用一个cookie来感染你的浏览器,例如action = logout,从那天起你不能再使用这个应用程序了,因为REQUEST [动作]将永远注销(直到你手动删除这个cookie)。

用COOKIE感染你真是太简单了
a)我可以在子域上的任何应用程序中使用XSS vuln
b)当您拥有一个单一的域名时,曾尝试为* .co.uk或* .co.kr设置一个cookie?
c)其他跨域的任何方式…

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

通过在一个名为+ PHPSESSID = 非法的variables中设置一个非法会话ID在一个有效的* .co.kr的cookie中,您仍然可以使用PHP会话在韩国境内对每一个PHP应用程序进行DOS操作。

讨论继续了几个post,很有趣的阅读。


正如你所看到的,$ _REQUEST的主要问题并不在于$ _GET和$ _POST,而是$ _COOKIE。 列表中的其他人build议更改$ _REQUEST的填充顺序,例如首先填充$ _COOKIE,但这可能会导致许多其他潜在的问题,例如使用会话处理 。

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

variable_order设置EGPCS(Environment,Get,Post,Cookie和Server)variablesparsing的顺序。 例如,如果variables_order设置为“SP”,那么PHP将创build超全局variables$ _SERVER和$ _POST,但不会创build$ _ENV,$ _GET和$ _COOKIE。 设置为“”意味着不会设置超全球。

但是再一次,你也可以考虑不要完全使用$ _REQUEST,因为在PHP中你可以在他们自己的全局variables中访问Environment,Get,Post,Cookie和Server,并且只有一个攻击vector。 您仍然需要清理这些数据,但是这是一个不必担心的问题。


现在你可能会想,为什么$ _REQUEST毕竟存在,为什么它不被删除。 这也是PHP内部的问题。 引用Rasmus Lerdorf 为什么$ _REQUEST存在? 在PHP内部

我们删除的东西越多,人们就越难迅速转向更新,更快,更安全的PHP版本。 这对于每个人来说都比一些“丑陋”的遗留function更令人沮丧。 如果有一个体面的技术原因,性能或安全,那么我们需要认真看待它。 在这种情况下,我们应该关注的不是我们是否应该删除$ _REQUEST,而是应该从中删除cookie数据。 许多configuration已经这样做了,包括我自己的所有configuration,并且在$ _REQUEST中没有包含cookie的强有力的安全原因。 大多数人使用$ _REQUEST来表示GET或POST,而不是意识到它也可能包含cookie,因此坏人可能会做一些cookie注入技巧,并打破天真的应用程序。

无论如何,希望能够stream露出一些光芒。

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

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

因此,如果每个人都倾向于使用$_REQUEST ,则可以通过POST进行GET操作,这意味着在我的(恶意)站点上设置<img>标签,导致用户login到您的电子商务模块或者我可以让他们点击链接,导致危险的行为或敏感信息的泄露(可能是我)。

不过,这是因为新手,或者至less没有经验的PHP程序员犯了简单的错误。 首先,知道什么types的数据是合适的。 例如,我有一个Web服务,可以在URLEncoding,XML或JSON中返回响应。 应用程序决定如何通过检查HTTP_ACCEPT头来格式化响应,但是可以通过发送format参数来强制成一个。

当检查格式参数的内容时,它可以通过查询string或postdata发送,这取决于多种因素,其中最重要的是调用应用程序是否想要与其请求混合使用“&format = json”。 在这种情况下, $_REQUEST非常方便,因为它使我不必input如下所示的内容:

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

我不会喋喋不休地说,只要说$_REQUEST用法不会被阻止,因为它本质上是危险的 – 它只是另一个工具,完全按照它的要求提供,不pipe你是否理解这些影响 – 它是导致这个问题的穷人,懒惰或缺乏经验的程序员的可怜,懒惰或不知情的决定。

如何安全地使用$_REQUEST


  1. 了解你的数据 :你应该对你将得到什么样的数据有一些期望,所以要相应地进行消毒。 数据库的数据? addslashes()*_escape_string() 。 去展示给用户? htmlentities()htmlspecialchars() 。 期待数字数据? is_numeric()ctype_digit() 。 事实上, filter_input()及其相关函数被devise为除了检查和清理数据之外什么也不做。 总是使用这些工具。
  2. 不要直接访问用户提供的超全局数据 。 养成每次清理数据的习惯,并将数据移动到清理variables,即使它只是$post_clean 。 另外,你可以直接在超级全局variables中进行清理,但是我主张使用一个单独的variables的原因是因为这样做可以很容易地发现代码中的漏洞,因为任何直接指向超全局的东西 ,而不是它的消毒等价物被认为是一个危险的错误。
  3. 知道你的数据应该来自哪里。 引用我上面的例子,允许响应格式variables通过GET或POST发送是完全合理的。 我也允许“行动”variables通过任何一种方法发送。 但是, 对于哪些HTTP动词可以接受这些操作本身具有非常具体的要求 。 例如,对服务使用的数据进行更改的function只能通过POST发送。 对于某些types的非特权数据或低特权数据(例如dynamic生成的地图图像)的请求可以响应于来自任一方法的请求而被服务。

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

安全是你所做的,人!

编辑:

强烈build议bobince的build议:如果可以,请将php.ini中的request_order参数设置为“GP”; 也就是说,没有cookie组件。 在98%以上的情况下,几乎没有理性的推理,因为cookie数据几乎不应该被视为与查询string或postdata相媲美。

PS,轶事!

我知道一位程序员认为$_REQUEST是一个简单地存储以超全球方式访问的数据的地方。 重要的用户名和密码,文件path,你的名字,它存储在$_REQUEST 。 当我告诉他这个variables是如何performance的时候,他感到有些惊讶(虽然不那么滑稽)。 不用说,这种做法被废除了。

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

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

这是模糊的。 你不知道这些数据是如何传递给你的,因为它包含post,get和cookie数据。 我不一定认为这总是一件坏事,除非你需要知道或限制交付的方法。

我其实喜欢使用它。 它使您可以灵活地使用GET或POST,它可以派上用场,例如大多数时间数据被发布的search表单,但是有时您会想要链接到特定的search,所以您可以使用GET参数。

另外,如果你看看很多其他的语言(例如ASP.NET),它们根本不会区分GET和POSTvariables。

ETA

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

此外,东西被加载到REQUEST中的顺序由php.ini(variables_order和request_order)中的configuration参数控制。 所以,如果你有通过POST和GET传入的相同variables,哪一个实际进入REQUEST取决于那些ini设置。 这可能会影响可移植性,如果您依赖于特定的顺序和这些设置configuration不同于您所期望的。

了解何时使用POST,什么时候使用GET以及何时使用cookie是很重要的。 使用$ _REQUEST,您正在查看的值可能来自其中任何一个。 如果您希望从POST或GET或COOKIE获取值,那么读取代码的人可以使用特定variables而不是$ _REQUEST来获得更多信息。

其他人也指出,你不希望所有POST或cookie被GET覆盖,因为它们都有不同的跨站点规则,例如,如果你在使用$ _REQUEST时返回ajax数据,你是脆弱的到跨站脚本攻击。

使用$_REQUEST唯一的时间不是一个坏主意是与GET。

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

即使使用GET, $_GET也比$_REQUEST更短;)

我可能只会使用,如果你想检索当前的url或主机名,但实际上使用&符号来parsing数据从这个URL,如参数它可能不是一个好主意。 一般来说,你不想使用你想要做的事情的模糊描述。 如果你需要明确的是$ _REQUEST是坏的,如果你不需要具体的话,可以随意使用它。 我会想。

如果你知道你想要什么数据,你应该明确地要求。 海事组织,GET和POST是两个不同的动物,我想不出一个很好的理由,为什么你会需要混合后数据和查询string。 如果有人有,我会感兴趣。

当脚本可能以相同的方式响应GET或POST时,使用$ _REQUEST可能会很方便。 我认为这应该是一个极其罕见的情况,在大多数情况下,处理两个单独的概念或者至less检查方法和select正确的variables的两个单独的函数是优选的。 当variables可能来自于不需要交叉引用时,程序stream通常更容易遵循。 对6个月内需要维护代码的人表示善意。 可能是你。

除了由REQUESTvariables中的cookie和环境variables引起的安全问题和WTF(不要让我开始使用GLOBAL)之外,如果PHP开始支持其他方法(如PUT和DELETE),将来可能会发生什么。 虽然这些将被合并到REQUEST超全局中是不太可能的,但是可能的是,它们可以作为选项包含在variable_order设置中。 所以你真的不知道什么是REQUEST,什么是优先,特别是如果你的代码部署在第三方服务器上。

POST比GET安全吗? 不是真的。 在实际情况下使用GET会更好,因为在日志中更容易看到应用程序在受到攻击时如何被利用。 对于影响域状态的操作,POST更好,因为蜘蛛通常不会遵循这些操作,而预测性抓取机制在您loginCMS时不会删除所有内容。 但是,这个问题不是关于GET和POST的优点,而是关于接收者应该如何处理传入的数据以及为什么合并它不好,所以这实际上只是一个BTW。

我认为$_REQUEST没有问题,但是在使用它的时候一定要小心,因为它是来自3个源(GPC)的variables的集合。

我猜$_REQUEST仍然可以使旧的程序与新的PHP版本兼容,但如果我们开始新的项目(包括新的库),我认为我们不应该再使用$_REQUEST来使程序更清晰。 我们甚至应该考虑删除$_REQUEST使用,并用一个包装函数replace它,使程序更轻,特别是在处理大量提交的文本数据时,因为$_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 ,我的一些脚本停止工作。 做了同样的事情:假设使用$_REQUESTvariables时,Cookie将被设置。 随着升级完全停止工作。

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

这是非常不安全的。 也不好意思,因为你不知道你是否得到一个POST或一个GET,或另一个请求。 在devise应用程序时,你应该知道它们之间的区别。 GET非常不安全,因为它在URL中传递,除了页面导航之外几乎不适合。 POST虽然本身不​​安全,但提供了一个安全级别。