作为开发人员,您必须知道如何构建安全且防弹的应用程序。您的职责是确保应用程序的安全性并防止攻击。
PHP 和 Web 安全问题清单
确保在将应用程序部署到生产环境时整理好这些项目:
跨站脚本 (XSS)
当客户端代码(通常是 JavaScript)被注入 PHP 脚本的输出时,就会发生 XSS 攻击。这可以通过 URL,但也可以通过诸如数据库之类的存储技术进行。
// GET data is sent through URL: http://example.com/search.php?search=<script>alert('test')</script>
$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 实体旁边的单引号和双引号- UTF-8 用于 PHP 5.4 之前的环境(现在是默认设置)。在某些浏览器中,某些字符可能会通过
htmlspecialchars()
.
注射
SQL注入
从您的应用程序访问数据库时,SQL 注入攻击可能通过将恶意 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']);
跨站请求伪造(XSRF/CSRF)
跨站点请求伪造、一键式攻击或会话骑行是一种利用,用户可借此在 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
将对公众可见。
- 更多详细信息可在专门的常见问题解答中找到: 如何在 PHP 应用程序中使用配置?
密码
使用用户密码时,请使用该 password_hash()
函数正确地对它们进行哈希处理。
- 更多详细信息可在“如何使用用户密码以及如何在 PHP 中安全地散列密码?“ 常问问题。
上传文件
当用户可以将文件上传到服务器时,就会发生许多安全漏洞。确保检查与上传文件相关的所有漏洞,并对这些漏洞采取适当的预防措施,例如重命名上传的文件、将它们移动到公共无法访问的文件夹、检查上传的文件类型等。由于这里有很多问题需要检查,更多信息也位于单独的常见问题解答中:
- 如何使用 PHP 安全地上传文件?常问问题。
会话劫持
会话劫持是一种攻击者窃取用户会话 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 配置
始终保持已安装的 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 版本
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 id>)
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 是一种用于通过网络进行安全通信的协议。强烈建议您在所有站点上启用它。在专门的常见问题解答中阅读有关 HTTPS 的更多信息: 如何安装 SSL 证书并启用 HTTPS。
接下来是什么?
上面我们介绍了很多安全问题。安全性、攻击和漏洞不断发展。花点时间阅读一些好的资源,以了解有关安全性的更多信息并将此检查清单变成一种习惯:
- 一般的:
- Awesome AppSec - 用于学习应用程序安全性的精选资源列表。
- OWASP - 开放 Web 应用程序安全项目,该组织专注于提高软件的安全性。
- 开发人员安全指南
- Web 应用程序安全基础,Martin Fowler 着。
- 专注于 PHP:
- PHP 手册- 必须阅读官方文档中的安全章节。
- Codecourse 视频- 有关最常见 PHP 安全领域的演示和建议。
- DVWA,该死的易受攻击的 Web 应用程序- 用于测试您的技能和工具的不安全 Web 应用程序示例。
- OWASP PHP 安全备忘单- 面向开发人员和管理员的基本 PHP 安全提示。
- 保护 PHP - 网站和书籍,其中包含身份验证/授权和漏洞利用预防方面的基本主题和特定案例。
- SensioLabs Security - SensioLabs 安全建议检查器,用于检查您的 PHP 项目是否存在已知安全问题
- 最被遗忘的网络漏洞- 推荐的 PDF 文章。
- websec.io - 致力于通过与一般安全基础知识、新兴技术和 PHP 特定信息相关的主题向开发人员提供安全教育。
- 2018 年构建安全 PHP 软件指南
- 工具:
- iniscan - 用于最佳安全实践的 php.ini 扫描程序。
- Kali Linux - 渗透测试 Linux 发行版。
- Mozilla 的 Observatory - 在线安全检查器。
- versionscan - 用于报告可能漏洞的 PHP 版本扫描程序。
- Roave Security Advisories - 此软件包可确保您的应用程序没有安装具有已知安全漏洞的依赖项。
- OWASP Zed Attack Proxy - 免费安全工具,也可在GitHub 上获得。