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

时间:2010-01-26 20:46:22

标签: php methods form-submit

我在这里看过很多帖子,说不要使用$_REQUEST变量。我通常不这样做,但有时它很方便。怎么了?

16 个答案:

答案 0 :(得分:183)

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

  • 对于通常通过GET提交的普通幂等请求,您希望的数据量可能不适合URL,因此它已经变为POST请求而非实际问题。

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

不,$_REQUEST的问题与混淆GET和POST参数无关。它默认情况下还包括$_COOKIE。并且cookie根本不像表单提交参数:你几乎从不想把它们视为同一个东西。

如果您不小心在您的网站上设置了与您的某个表单参数同名的Cookie,那么由于Cookie值会覆盖预期的参数,依赖该参数的表单将会神秘地停止正常工作。如果您在同一个站点上有多个应用程序,这很容易做到,并且当您只有几个使用旧cookie的用户时,如果您不再使用旧的cookie并以不同的方式破坏表单,则可能非常难以调试 - 其他人可以重现。

您可以使用PHP 5.3中的request_order配置将此行为更改为更明智的GP(无C)顺序。如果无法做到这一点,我个人会避免$_REQUEST,如果我需要一个组合的GET + POST阵列,请手动创建它。

答案 1 :(得分:71)

我一直在浏览PHP Internals上的一些新闻组帖子,并发现了有关该主题的有趣讨论。最初的主题是关于其他的东西,但是由PHP世界中的一个(如果不是 )安全专家Stefan Esser发表的一篇评论将讨论转向了使用$ _REQUEST进行一些帖子的安全问题。

引用Stefan Esser on PHP Internals

  

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

并在later reply to the same thread

  

这不是因为有人可以伪造GET,POST; COOKIE变量。   这是关于COOKIE将覆盖GET和POST数据的事实   REQUEST。

     

因此,我可以通过一个cookie来感染您的浏览器,例如   action = logout从那天开始就无法使用该应用程序   因为REQUEST [action]将永远退出(直到你   手动删除cookie。)

     

用COOKIE感染你是如此简单......
  a)我可以在子域上的任何应用程序中使用XSS vuln   b)曾经尝试过设置* .co.uk或* .co.kr的cookie   单域有吗?
  c)其他跨领域无论如何......

     

如果您认为这不是问题,那么我可以告诉您   有一个简单的可能性设置f.e.结果是一个* .co.kr cookie   在几个PHP版本中只返回白页。   想象一下:只需一个cookie来杀死* .co.kr

中的所有PHP页面      

通过在一个有效的* .co.kr的cookie中设置一个非法的会话ID   变量名为+ PHPSESSID = 非法你仍然可以DOS每个PHP   使用PHP会话在韩国申请......

继续讨论更多帖子,阅读很有意思。


正如你所看到的,$ _REQUEST的主要问题不在于它有来自$ _GET和$ _POST的数据,而是来自$ _COOKIE。列表中的其他一些人建议改变$ _REQUEST被填充的顺序,例如首先用$ _COOKIE填充它,但是this could lead to numerous other potential problems, for instance with Session handling

你可以从$ _REQUEST全局中完全省略$ _COOKIES,这样它就不会被任何其他数组覆盖(事实上,你可以将它限制为它的标准内容的任意组合,比如{{3}告诉我们:

  

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关于PHP内部的PHP manual on the variable_order ini setting

  

我们删除的东西越多,人们就越难   快速转向更新,更快,更安全的PHP版本。那   导致每个人的挫折感比一些“丑陋”的遗产更令人沮丧   特征。如果有一个体面的技术原因,性能或   安全,那么我们需要认真看待它。在这种情况下,   我们应该关注的不是我们是否应该删除$ _REQUEST   但是我们是否应该从中删除cookie数据。许多配置   已经做到了,包括我自己的所有,并且有一个强大的有效性   $ _REQUEST中不包含cookie的安全原因。大多数人使用   $ _REQUEST表示GET或POST,没有意识到它也可以包含   饼干和坏人可能会做一些cookie注入   欺骗和打破天真的应用程序。

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

答案 2 :(得分:10)

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

答案 3 :(得分:8)

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

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

答案 4 :(得分:8)

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

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

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

当检查format参数的内容时,它可以通过querystring或postdata发送,具体取决于多种因素,其中最重要的是调用应用程序是否需要“&amp; 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. 不要直接访问用户提供的超全球数据。养成每次清理数据的习惯,并将数据移动到清理变量,即使它只是$post_clean。或者,您可以直接在超级全局中清理,但我提倡使用单独的变量的原因是因为这样做可以很容易地发现代码中的漏洞,因为任何直接指向超全局而不是它消毒等效物被认为是一种危险的错误。
  3. 了解数据的来源。从上面引用我的示例,允许通过GET或POST发送响应格式变量是完全合理的。我还允许通过任一方法发送“action”变量。但是,操作本身对于哪个HTTP谓词可接受具有非常具体的要求。例如,对服务使用的数据进行更改的功能只能通过POST发送。可以响应来自任一方法的请求来提供对某些类型的非特权或低特权数据(例如动态生成的地图图像)的请求。
  4. 总之,请记住这条简单的规则:

    安全就是你做的,人们!

    编辑:

    强烈推荐bobince的建议:如果可以,请将php.ini中的request_order参数设置为“GP”;也就是说,没有cookie组件。在98%以上的情况下几乎没有理性的推理,因为cookie数据几乎永远不会被认为与查询字符串或postdata相当。

    P.S。,轶事!

    我认识一位程序员,他认为$_REQUEST只是存储一个可以超全局方式访问的数据的地方。重要的用户名和密码,文件路径,您为其命名并将其存储在$_REQUEST中。当我告诉他变量如何表现时,他有点惊讶(虽然不幸的是,但不是很滑稽)。毋庸置疑,这种做法已被废除。

答案 5 :(得分:7)

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

答案 6 :(得分:3)

我其实喜欢用它。它为您提供了使用GET或POST的灵活性,这对于大多数时间数据被POST的搜索表单都很方便,但有时您会想要指向特定搜索的链接,因此您可以使用GET参数代替

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

ETA

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

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

答案 7 :(得分:2)

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

  • 如果您使用它来加载POST值,则存在跨站点请求伪造的风险
  • 如果您使用它来加载Cookie值,则会再次冒险跨站请求伪造

即使使用GET,$_GET的输入时间也会短于$_REQUEST;)

答案 8 :(得分:2)

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

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

答案 9 :(得分:0)

我可能仅在您想要检索当前网址或主机名时使用,而是用于实际解析来自该网址的数据,例如使用&amp;符号它可能不是一个好主意。一般而言,您不希望对您尝试执行的操作进行模糊描述。如果您需要具体说明$ _REQUEST是坏的,如果您不需要具体,那么随意使用它。我想。

答案 10 :(得分:0)

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

当脚本可能以相同方式响应GET或POST时,使用$ _REQUEST会很方便。我认为这应该是极其罕见的情况,并且在大多数情况下,两个单独的函数来处理两个单独的概念,或者至少检查方法并选择正确的变量是优选的。当没有必要交叉引用变量可能来自哪里时,程序流程通常更容易遵循。善待那些必须在6个月内维护你的代码的人。可能是你。

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

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

答案 11 :(得分: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; 
    } 
  }
}

答案 12 :(得分:0)

  

Darren Cook:&#34;自php 5.3起,默认的php.ini表示只有GET和POST数据被放入$_REQUEST。见php.net/request_order我就是   在期待cookie时偶然发现了这种向后兼容性的突破   数据在$_REQUEST,并想知道为什么它不起作用!&#34;

哇...由于升级到PHP 5.3 ,我的一些脚本停止工作了。做了同样的事情:假设在使用$_REQUEST变量时会设置cookie。 升级完全停止了工作。

我现在使用$_COOKIE["Cookie_name"] ...

分别调用cookie值

答案 13 :(得分:0)

只需确保在您的 php.ini 中设置正确的参数(以下为默认设置,只要未设置为GP C ,这里没有使用Cookie)

request_order = "GP"

这意味着 POST 会覆盖 GET ,您会没事的。

$_REQUEST的原因仅仅是合并中的$ _GET和$ _POST。 在通过页面上的大量链接发送表单和导航时,一个地方用于保存状态非常有用:$_REQUEST

答案 14 :(得分:-1)

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

在PHP 7中,您可以这样做:

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

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

答案 15 :(得分:-2)

这是非常不安全的。它也很尴尬,因为你不知道你是在获得POST或GET,还是其他请求。在设计应用程序时,您真的应该知道它们之间的区别。 GET非常不安全,因为它在URL中传递,除了页面导航之外几乎不适用于任何其他内容。 POST虽然本身也不安全,但提供了一个安全级别。