导语:php.ini 是PHP运行周期内的最主要的配置文件,该配置文件中的很多配置选项都与PHP应用程序的安全性有关。
之前有一段时间,我在本网站撰写了一篇有关于使用php.ini配置文件的一些与安全相关的最佳实践的文章。对于那些不知道的php.ini文件的人(如果你使用过PHP,你就应该知道这个文件),我要说的是,php.ini文件是你在安装PHP后的“主设置”文件。这是PHP解释器(在Web和命令行方面)寻找如何设置自己和一些选项打开/关闭的地方。
由于它是全局的配置文件,因此可以包括许多不同类型的设置:
· 输出缓冲限制 · 禁用PHP函数 · 最大执行时间/内存使用量 · 错误处理和显示首选项 · 允许include或打开访问远程的资源
…当然还有更多的设置选项。这也是你可以加载外部扩展并配置更多特定字段的设置,如会话处理,正则表达式,邮件服务器配置和各种数据库扩展。现在你可以很明显的明白此文件的重要性,并且内部选项的错误设置可能会在你的应用程序的安全性上留下 “裂缝” 。
在这有一点需要指出 – 有一个选项(with-config-file-scan-dir)你可以编译成指向另一个安装了PHP的目录,并将其中的*.ini文件进行加载,寻找PHP设置。这个操作是在php.ini生成之后做的,所以在这里总是有机会可以覆盖掉一些主要的设置。
不要误会我的解释,在应用程序代码级别上可以做很多事情,可以帮助你提高应用程序的安全性以及一些通过配置设置无法轻松完成的事情。当你谈论php.ini安全性的时候,你其实正在看的是一些非常基本的东西。即使在PHP附带的默认配置文件中也有很多地方你可以进行潜在的滥用行为,甚至你不需要了解这些选项。有很多文章提出了一些关于某些设置要禁用的建议,以及其他选项的应该设置的合理级别,但似乎没有哪篇文章是保持了最新的信息。
我不得不向Ed Finkler提出需求,在他原来编写的概念验证工具—— PHPSecInfo中打破了这一点。他的工具是一个PHP实用程序,你可以放入你的Web应用程序,这个工具可以可视化地指出你的应用程序的痛点在哪里。工具会根据通过/失败状态对HTML进行着色,并提供有关该问题的更多信息以及设置选项值的良好建议。不幸的是,它已经有很长一段时间没有更新了,但它仍然是一个有用的工具。如果你使用它,请注意一点——它可以为访问你的站点的用户提供大量的信息披露。它不建议在生产经常使用,但可能是在你初始的配置和安装过程中非常有用的一个工具。
正如我所提到的,我收集了我可以找到的所有与php.ini相关的安全信息,并决定对这些信息进行分析能有一些实际的意义。而不是只是写一篇文章这么简单,我决定让这些信息对普通用户更加有用,这些用户将在任何框架或应用程序平台之外吸取有关安全的PHP服务器端配置的教训。所以,我创建了Iniscan工具 —— 一个命令行实用程序,你可以针对你的php.ini文件运行安全扫描,并在建议你在此基础级别上保护应用程序时提供一些最佳做法。
Iniscan – 概述
Iniscan项目背后的目标是聚集各种最佳做法来保证配置文件的安全性。这包括更普通的PHP大众以及那些正在寻找他们所运行的特定版本的PHP的内容的用户。扫描器会使用给定的选项值(默认或从命令行选项中指定)扫描php.ini文件,并将php.ini的一些设置与其自己的规则集进行比较,来寻找安全问题。
要在自己的系统上进行尝试,可以使用Composer轻松安装它:
{ "require": { "psecio/iniscan": "dev-master" } }
一旦下载完成,你可以通过命令行针对你自己的php.ini来启动执行:
bin/iniscan scan --path=/path/to/php.ini
这将产生类似于下面这样的扫描结果:
== Executing INI Scan [12.05.2013 17:59:40] == Results for php.ini: ============ Status | Severity | Key | Description ---------------------------------------------------------------------- PASS | ERROR | session.use_cookies | Accepts cookies to manage sessions PASS | ERROR | session.use_only_cookies | Must use cookies to manage sessions, don't accept session-ids in a link FAIL | WARNING | session.cookie_domain | It is recommended that you set the default domain for cookies. PASS | ERROR | session.cookie_httponly | Setting session cookies to 'http only' makes them only readable by the browser
扫描的结果输出提供了这几个事情:
· 检查通过或失败的状态
· 问题的严重程度
· php.ini中进行检查的“key”
· 对检查出的问题和原因的总结描述
如果你对实际的检查过程很感兴趣,请查看src/Psecio/Iniscan/rules.json文件中的定义和工具将会检查的一些值。
当报告出任何检查失败的情况时,命令将以非零状态退出,使你更容易以编程的方式检查整体的通过或失败的状态。
还有一组可以提供的命令行选项,这些选项可以使扫描更加灵活:
· –path定义要检查的php.ini文件的路径。如果没有给出,它会尝试从PHP的内部设置中寻找。
· –fail-only 告诉Iniscan只显示检查失败的选项,而不需要显示检查通过的内容。
· –format 允许你以各种格式输出扫描结果(目前支持默认的CLI输出以及JSON和XML)
· –threshold 定义你想要看到的最低失败值(例如–threshold = ERROR将显示错误而不是警告)
· –php指定你要用于评估的PHP版本。如果没有指定这个值,Iniscan则会从中PHP_VERSION 中读取
· –output 定义要将扫描结果输出写入的目录(如使用JSON和XML的输出格式)
因此,如果你只想查看安全问题并将结果输出到JSON数据集,则可以使用下面的命令:
bin/iniscan scan –path=/path/to/php.ini –fail-only –format=json –output=/path/to/output-dir
还包括两个“列表”命令,以便你了解该工具执行的检查:
bin/iniscan list-tests
以及你当前正在处理的php.ini设置文件:
bin/iniscan show
PHP.ini安全性一瞥
接下来,我会尝试通过规则列表中的每个条目,并讨论这些条目为什么需要被检查,我会将其分解成几个部分,并描述一些基本的可能会因为糟糕的设置而出现的安全问题。其中一些已经在另一篇文章中提及。
一般的PHP设置选项
有几个设置与任何特定的PHP功能无关,这些功能更加通用一些。其中有些是有争议的,尽管它们可能导致一些问题(如expose_php),但其中几个可以产生真正的影响。例如,如果你知道你的应用程序永远不会通过任何类似于include / require或fopen打开远程位置的文件,那么你可以关闭allow_url_fopen和allow_url_include设置。这可以防止意外的远程文件包含问题所导致的代码执行,例如将用户上传的“.php”文件放在可公开访问的目录中,然后包含执行。
还有一些涉及到与最终用户共享什么样的信息有关的错误处理。如果启用error_reporting和display_errors,那么在开发过程中输出的错误值是绝对有助于调试脚本并跟踪错误的。然而,在生产和面向公众的环境中,相同的信息可能会泄露你的应用程序的某些敏感信息,你可能不希望存在潜在的攻击。例如,假设生产中没有关闭错误开关,最终用户正在尝试通过一些SQL注入测试来实施入侵。如果由于这些请求而出现错误,那么该攻击者将获得有关应用程序内部的一些信息,并且由于PHP本身倾向于在某些错误上提供堆栈跟踪,因此有关组成应用程序的实际文件的信息也会泄露。
会话设置选项
Session是使用PHP有用性方面的重要组成部分。在其他语言可能需要引入单独的会话处理程序的情况下,PHP包括了其默认的功能(并且已有很长时间)。正如你所料,这意味着配置就在这个文件里,一般来说PHP都在php.ini里进行配置。这个文件里已经定义了很多有关会话的设置,但这并不意味着它们是最安全的选项。当前默认的设置更多的是“这些将在大多数系统上工作”为目的的。
那么我们需要注意哪些呢?最初的几个选项是有关于处理会话处理程序的cookie。默认情况下,PHP会话使用带有PHPSESSID哈希值的cookie 作为值。Iniscan工具会检查以确保你的session.use_cookies和session.use_only_cookies设置被启用,以防止会话被以任何其他方式注入。还有三个其他设置选项,更多的是保护实际的Cookie本身:session.cookie_domain限制可以访问它们的域,cookie_httponly防止从Web环境以外的来源进行访问,cookie_secure设置以及阻止访问HTTPS / SSL连接之外的Cookie 。
除此之外,还有一些更多的自定义检查工作,一个是处理脚本将其会话写入的路径,另一个处理熵文件的路径。第一个设置选项——session.save_path告诉PHP在哪里写会话文件。默认情况是写入/tmp也就是本地文件系统上的临时目录。这有一个明显的问题,它与该目录的默认权限有关。原来的意图/tmp是要有一个任何应用程序可以读写的地方,包括运行PHP的Web服务器。所以,想象一下如果有人通过另一种方法来破坏服务器,并且能够读取到这些会话文件的内容时会发生什么呢。默认情况下,PHP只需要在会话中使用数据,使用base64将其编码并将其写入文件。Iniscan会检查你设置的路径——save_path并确保它不是对任何人都是可读/写的。
第二个自定义会话检查可以帮助增强PHPSESSID——PHP会话cookie值使用的哈希值的随机性。虽然默认散列生成的结果是可以接受的,但PHP开发组希望允许用户可以帮助它更随机。而不是试图将更多的功能引入到你的代码中,他们在一个较低的级别定义了session.entropy_file设置选项。默认情况下,此设置未定义,但在PHP 5.4.0及更高版本中,它使用/dev/urandom或/dev/arandom,作为值,如果可用的话。
这些都是随机数据的良好来源,但如果你的版本低于PHP 5.4.0呢?你可以分配任何你想要的设置的entropy_file文件,PHP将会在该会话ID的随机生成过程中使用该文件的内容。过去有一些问题,PHP的会话ID生成是可预测的,因为它的实现是“随机的”(注意那里的引号),并且可以预测其他请求的结果,并允许进行会话固定攻击。
自定义安全检查
还有一些是Iniscan的定制检查,这些检查不仅仅只是检查“某个选项的值设置了没?”或“某个选项确认是否关闭了”。一个与通过disable_functions设置选项禁用函数有关的设置,允许你阻止PHP执行某些函数,并可以关闭诸如exec,passthru或其他文件系统执行功能之类的函数。这可以防止未经授权的代码进行系统调用,并且可能(取决于执行用户的访问级别)对本地文件进行更改。
另一个更为具体的检查,是在特定版本的PHP上检查一个安全问题。CVE-2013-1635引用的问题影响了PHP 5.3.22和5.4.13+版本,并且与SOAP扩展的WSDL缓存目录的问题相关soap.wsdl_cache_dir-可以在open_basedir限制之外设置为启用。虽然本身并不完全是“最佳实践”,但这是值得注意的事情。自定义检查允许Iniscan使用更复杂的逻辑来查看是否有风险(例如检测当前的PHP版本)。
开源!
最后的一个提醒,在写这篇文章之前 – Iniscan项目是开放源代码的,并托管在Github上,并且始终保持开放贡献的态度。它不一定是代码,总是会有一些事情没有想到或特定于你的配置,可能会让它失败。如果你遇到这些问题,请提交一个有关该问题的issue,这将有助于你解决遇到的问题。该项目已经受到Github和Packagist的大量安装的关注,但它总是可以使用input或pull请求来帮助它更加好用。
希望这个工具能够帮助PHP社区以简单而有效的方式加强服务器端的安全。该项目一直在寻找好的想法和“下一步”要做的事情,所以如果你有一些好的建议,甚至只是一般的反馈,请让我知道!
资源