$_SERVER[ ] 是 PHP 中的安全数据源吗?

信息安全 Web应用程序 应用安全 php 源代码 编码
2021-08-17 02:00:01

我可以 100% 依赖于$_SERVER[]成为我不需要像我一样清理的安全数据源$_GET[]$_POST[]

4个回答

这取自我关于 Stack Overflow 的一个问题:哪些 $_SERVER 变量是安全的?

服务器控制

这些变量由服务器环境设置,完全取决于服务器配置。

  • 'GATEWAY_INTERFACE'
  • 'SERVER_ADDR'
  • 'SERVER_SOFTWARE'
  • 'DOCUMENT_ROOT'
  • 'SERVER_ADMIN'
  • 'SERVER_SIGNATURE'

部分服务器控制

这些变量取决于客户端发送的特定请求,但只能采用有限数量的有效值,因为所有无效值都应被 Web 服务器拒绝,并且不会导致脚本的调用开始。因此它们可以被认为是可靠的

  • 'HTTPS'
  • 'REQUEST_TIME'
  • 'REMOTE_ADDR' *
  • 'REMOTE_HOST' *
  • 'REMOTE_PORT' *
  • 'SERVER_PROTOCOL'
  • 'HTTP_HOST'
  • 'SERVER_NAME'
  • 'SCRIPT_FILENAME'
  • 'SERVER_PORT'
  • 'SCRIPT_NAME'

* 这些REMOTE_值保证是客户端的有效地址,由 TCP/IP 握手验证。这是将发送任何响应的地址。REMOTE_HOST虽然依赖于反向 DNS 查找,因此可能会被针对您的服务器的 DNS 攻击所欺骗(在这种情况下,无论如何您都会遇到更大的问题)。该值可能是一个代理,它是 TCP/IP 协议的一个简单现实,您无能为力。

† 如果您的网络服务器响应任何请求而不管HOST标头,这也应该被认为是不安全的。请参阅$_SERVER[“HTTP_HOST”] 有多安全?.
另请参阅http://shiflett.org/blog/2006/mar/server-name-versus-http-host

完全任意的用户控制值

这些值根本不检查,也不依赖于任何服务器配置,它们完全是客户端发送的任意信息。

  • 'argv', 'argc'(仅适用于 CLI 调用,通常与 Web 服务器无关)
  • 'REQUEST_METHOD'
  • 'QUERY_STRING'
  • 'HTTP_ACCEPT'
  • 'HTTP_ACCEPT_CHARSET'
  • 'HTTP_ACCEPT_ENCODING'
  • 'HTTP_ACCEPT_LANGUAGE'
  • 'HTTP_CONNECTION'
  • 'HTTP_REFERER'
  • 'HTTP_USER_AGENT'
  • 'AUTH_TYPE' §
  • 'PHP_AUTH_DIGEST' §
  • 'PHP_AUTH_USER' §
  • 'PHP_AUTH_PW' §
  • 'PATH_INFO'
  • 'ORIG_PATH_INFO'
  • 'REQUEST_URI' (可能包含受污染的数据)
  • 'PHP_SELF' (可能包含受污染的数据,即 /index.php/evilstring)
  • 'PATH_TRANSLATED'
  • 任何其他'HTTP_'

‡只要网络服务器只允许某些请求方法,就可以认为是可靠的。

§如果身份验证完全由 Web 服务器处理,则可能被认为是可靠的。

超全局$_SERVER还包括几个环境变量。这些是否“安全”取决于它们的定义方式(和位置)。它们的范围可以从完全服务器控制到完全用户控制。

我是否可以 100% 依赖 $_SERVER[] 作为安全的数据源,而无需像 $_GET[] 和 $_POST[] 那样进行清理?

您的问题立即表明失败。必须对所有输入源进行消毒。输入不仅仅是用户可以直接控制的通道,还包括应用程序之外的所有数据源。

这样想,您的应用程序有两种获取数据的方式:在您的应用程序中硬编码的信息和输入。即使它是由同一系统上的另一个程序生成的,它仍然会输入到您的程序中。

通用习惯用法Filter-In, Escape-Out不仅适用于用户输入,还适用于进入和离开应用程序的任何内容。

因此,如果它在 中$_SERVER,则必须对其进行过滤/消毒。您永远不应依赖应用程序中未硬编码的任何内容。

为什么这很重要?假设您过滤了来自用户的所有输入,但随后信任来自您的数据库的数据。如果我可以利用您过滤中的漏洞,我可以注入随后变得可信的数据。这可能导致二阶 XSS 或 SQLi。但是如果你过滤所有进入你的应用程序的东西,当它进来时,不管它来自哪里,那么你就是安全的!

所以不,你永远不能 100% 依赖$_SERVER, $_GET, $_POST, $_COOKIE, $_REQUEST, $_ENV, $argc, 中的任何内容$argv,来自你的数据库、来自文件系统(除了你的版本控制代码)等等......

根本不是一个愚蠢的问题!

许多(但不是全部)$SERVER 变量是从用户浏览器传递的(或可能受用户影响),例如 QUERY_STRING、REQUEST_URI 和所有 HTTP_* 变量。

甚至 REMOTE_ADDR 变量也可以使用原始套接字进行欺骗(尽管据我所知,只有有效的 IP)。

作为一项好的政策,我会避开他们。

http://php.net/manual/en/reserved.variables.server.php

没有“安全的数据来源”这样的东西。在将数据传递给其他东西时,您应该始终确保数据格式正确。

如果要在撇号 (') 分隔的字符串 [1] 内输出到 SQL,则应转义撇号(或任何其他可能破坏字符串的内容)。如果您要输出到 Javascript 撇号分隔的字符串 [2],您应该转义任何 HTML 和撇号。这完全取决于您要输出的内容。一个完全安全的字符串可以破坏目标脚本,即使不是恶意的。(但通常,如果它可以被破坏,它也可以被利用。)

[1] 示例:$db->query("SELECT * FROM users WHERE name = '$username'");
[2] 示例:<script>alert('Hi <?php echo $username;?>');</script>

我已经在我的博客上讨论过这种转义,虽然我的帖子专门针对 XSS,但我认为同样的原则也适用于这里:什么是 XSS 以及如何保护您的网站

除非您知道 PHP 本身已经强制执行特定格式,并且您几乎无法确定这一点,否则您可以认为一切都是不安全的。IP 地址通常采用 xxxx 格式,但对于 IPv6,它也可能是 x:x:x:x:x:x:x:x。甚至 0:0:0:0:0:ffff:xxxx 用于 IPv6 数据包中的 IPv4 目标。如果你没有意识到这一点,它可能会导致一些非常有趣的错误。

现在 IP 地址永远不会包含撇号,对吧..?好吧,有些人在使用远程地址之前会检查 $_SERVER["HTTP_X_FORWARDED_FOR"] 标头。这很好,只要标题设置正确(正如@Ladadadada 在对@GBC 响应的评论中所指出的那样),但这也可能是一个恶搞。然后,当您使用其他人存储在数据库中的数据时,您可能会得到恶意的东西......所以最后,永远不要相信输入。更好地保护它,而不是忘记它一次。