作为开发人员,您必须知道如何构建安全且防弹的应用程序。您的职责是确保应用程序的安全性并防止攻击。
确保在将应用程序部署到生产环境时整理好这些项目:
当客户端代码(通常是 JavaScript)被注入 PHP 脚本的输出时,就会发生 XSS 攻击。这可以通过 URL,但也可以通过诸如数据库之类的存储技术进行。
- // GET data is sent through URL: http://example.com/search.php?search=
- $search = $_GET['search'] ?? null;
- echo 'Search results for '.$search;
-
- // This can be solved with htmlspecialchars
- $search = htmlspecialchars($search, ENT_QUOTES, 'UTF-8');
- echo 'Search results for '.$search;
ENT_QUOTES
用于转义 HTML 实体旁边的单引号和双引号htmlspecialchars()
.从您的应用程序访问数据库时,SQL 注入攻击可能通过将恶意 SQL 部分注入您现有的 SQL 语句来发生。
目录遍历攻击,也称为../
(点、点、斜线)攻击,发生在用户提供文件名作为可以遍历父目录的输入时。数据可以设置为index.php?page=../secret
、 或 /var/www/secret
,或者更具灾难性的东西:
- $page = $_GET['page'] ?? 'home';
-
- require $page;
- // or something like this
- echo file_get_contents('../pages/'.$page.'.php');
在这种情况下,您必须检查是否有人尝试访问父文件夹或某个远程文件夹:
- // Checking if the string contains parent directory
- if (strstr($_GET['page'], '../') !== false) {
- throw new \Exception("Directory traversal attempt!");
- }
-
- // Checking remote file inclusions
- if (strstr($_GET['page'], 'file://') !== false) {
- throw new \Exception("Remote file inclusion attempt!");
- }
-
- // Using whitelists of pages that are allowed to be included in the first place
- $allowed = ['home', 'blog', 'gallery', 'catalog'];
- $page = (in_array($page, $allowed)) ? $page : 'home';
- echo file_get_contents('../pages/'.$page.'.php');
在处理执行您不信任的功能和数据的命令时要小心。
exec('rm -rf '.$GET['path']);
当可以通过该eval()
函数注入恶意代码时,就会发生代码注入,因此请记住在使用数据时始终清理您的数据:
eval('include '.$_GET['path']);
跨站点请求伪造、一键式攻击或会话骑行是一种利用,用户可借此在 Web 应用程序上执行不需要的操作。
确保将所有应用程序文件、配置文件和 Web 应用程序的类似部分移动到当您访问 Web 应用程序的 URL 时不可公开访问的文件夹中。.yml
您的网络服务器可能无法处理某些类型的文件(例如文件),用户可以在线查看它们。
良好文件夹结构的示例:
- app/
- config/
- parameters.yml
- src/
- public/
- index.php
- style.css
- javascript.js
- logo.png
将您的 Web 服务器配置为从该public
文件夹而不是从您的应用程序根文件夹提供文件。公共文件夹包含前端控制器 ( index.php
)。如果 Web 服务器配置错误导致 PHP 文件无法正确提供,源代码index.php
将对公众可见。
使用用户密码时,请使用该 password_hash()
函数正确地对它们进行哈希处理。
当用户可以将文件上传到服务器时,就会发生许多安全漏洞。确保检查与上传文件相关的所有漏洞,并对这些漏洞采取适当的预防措施,例如重命名上传的文件、将它们移动到公共无法访问的文件夹、检查上传的文件类型等。由于这里有很多问题需要检查,更多信息也位于单独的常见问题解答中:
会话劫持是一种攻击者窃取用户会话 ID 的攻击。会话 ID 被发送到$_SESSION
填充相关阵列的服务器。会话劫持可能通过 XSS 攻击或当某人获得对存储会话数据的服务器上的文件夹的访问权限时。
RFI(远程文件包含)攻击是指攻击者可以包含自定义脚本:
- $page = $_GET['page'] ?? 'home'
-
- require $page . '.php';
在上面的代码中,$_GET
可以设置一个远程文件http://yourdomain.tld/index.php?page=http://example.com/evilscript
php.ini
除非您知道自己在做什么,否则请确保禁用此功能:
- ; Disable including remote files
- allow_url_fopen = off
- ; Disable opening remote files for include(), require() and include_once() functions.
- ; If above allow_url_fopen is disabled, allow_url_include is also disabled.
- allow_url_include = off
始终保持已安装的 PHP 版本更新。您可以使用 versionscan检查您的 PHP 版本可能存在的漏洞。更新开源库和应用程序,并保持您的 Web 服务器得到良好维护。
以下是php.ini
您应该检查的一些重要设置。您还可以使用iniscan扫描您的 php.ini
文件以获得最佳安全实践。
在您的生产环境中,您必须始终关闭在屏幕上显示错误。如果您的应用程序中出现错误并且它们对外界可见,那么攻击者可能会获取有价值的数据来攻击您的应用程序。display_errors
和文件log_errors
中的指令php.ini
:
- ; Disable displaying errors to screen
- display_errors = off
- ; Enable writing errors to server logs
- log_errors = on
PHP 版本在 HTML 标头中可见。您可能需要考虑通过关闭expose_php
指令来隐藏您的 PHP 版本,以防止 Web 服务器发回X-Powered-By
标头:
expose_php = off
在大多数情况下,禁用对远程文件的访问很重要:
- ; disabled opening remote files for fopen, fsockopen, file_get_contents and similar functions
- allow_url_fopen = 0
- ; disabled including remote files for require, include ans similar functions
- allow_url_include = 0
此设置定义一个或多个目录(包括子目录),PHP 可以在其中读取和写入文件。这包括文件处理(fopen
, file_get_contents
),也包括文件(include
, require
):
open_basedir = "/var/www/test/uploads"
session.use_cookies和session.use_only_cookies
PHP 默认配置为将会话数据存储在服务器上,并在客户端(通常称为PHPSESSID
)上存储一个跟踪 cookie,该 cookie 具有会话的唯一 ID。
- ; in most cases you'll want to enable cookies for storing session
- session.use_cookies = 1
- ; disabled changing session id through PHPSESSID parameter (e.g foo.php?PHPSESSID=
) - session.use_only_cookies = 1
- session.use_trans_sid = 0
- ; rejects any session ID from user that doesn't match current one and creates new one
- session.use_strict_mode = 1
session.cookie_httponly
如果攻击者设法注入 JavaScript 代码来窃取用户当前的 cookie(document.cookie
字符串),那么HttpOnly
您设置的 cookie 将不会显示在列表中。
session.cookie_httponly = 1
session.cookie_domain
这设置了 cookie 应用的域。对于通配符域,您可以使用.example.com
,或将其设置为应应用的域。默认情况下,它未启用,因此强烈建议您启用它:
session.cookie_domain = example.com
session.cookie_secure
对于 HTTPS 站点,这仅接受通过 HTTPS 发送的 cookie。如果你还没有使用 HTTPS,你应该考虑一下。
session.cookie_secure = 1
HTTPS 是一种用于通过网络进行安全通信的协议。强烈建议您在所有站点上启用它。在专门的常见问题解答中阅读有关 HTTPS 的更多信息: 如何安装 SSL 证书并启用 HTTPS。
上面我们介绍了很多安全问题。安全性、攻击和漏洞不断发展。花点时间阅读一些好的资源,以了解有关安全性的更多信息并将此检查清单变成一种习惯: