PHP 安全最佳实践

由于 PHP 是几乎每个网站的主干,因此,PHP 安全性不应被视为可以忽略不计。但是,PHP 开发人员有权避免跨站点请求伪造、SQL 注入和数据篡改等常见威胁。而这一切都在 PHP 内置安全功能的帮助下派上用场,使开发人员更容易保护网站。

PHP 被认为是最强大的服务器端语言,PHP 使用了全球 80% 的网络,拥有前 1000 万个域名。出于这个原因,请理解 PHP 将帮助您防御攻击者。

保护 Web 应用程序免受各种伪造攻击尝试是 Web 开发人员的最终职责。您应该构建足够保护的 Web 应用程序,以确保没有安全问题或漏洞。

PHP 是世界上最常用的服务器端 Web 编程语言。不同的 PHP 应用程序与其他 Web 应用程序共享其代码和脚本的不同部分。如果发现共享代码段存在漏洞,则使用该共享代码段的所有应用程序都将面临风险并被视为易受攻击。

在安全性方面,PHP 是最受批评的脚本语言。 大部分开发人员和 QA 专家认为 PHP 没有可靠的技术来保护应用程序。这个结论也有一定的道理,因为 PHP 是最古老且广泛使用的 Web 应用程序开发语言。但是自 PHP 5.6 以来的很长一段时间内,我们还没有看到任何有关安全性的重大更新,因此该语言面临一些安全问题。

PHP 有多安全

PHP 与任何其他主要语言一样安全。  PHP 与任何主要的服务器端语言一样安全。随着过去几年引入的新 PHP 框架和工具,现在比以往任何时候都更容易管理一流的安全性。

如果我们做一个比较,PHP 是均匀安全的。Rails、Java、Javascript 和其他语言多年来都存在漏洞。“如果你发现一种语言没有某种形式或形式的漏洞,你可以用 PHP 完美地编写安全代码。

PHP CMS 中的安全问题

WordPress、Joomla、Magento 和 Drupal 等流行的 CMS 都是用 PHP 构建的,根据 Sucuri 的说法,PHP CMS 中的大多数漏洞在 2017 年都暴露出来了:

  • WordPress 安全问题从 2016 年第三季度的 74% 上升到 2017 年的 83%。
  • Joomla 安全问题从 2016 年第三季度的 17% 下降到 2017 年的 13.1%。
  • Magento 安全问题从 2016 年第三季度的 6% 小幅上升到 2017 年的 6.5%。
  • Drupal 安全问题从 2016 年第三季度的 2% 小幅下降到 2017 年的 1.6%。

目前的情况还不够好,但感谢开源贡献者,他们正在努力克服这些问题,我们最近看到 PHP 发生了一些剧烈的变化。PHP 7.x 于去年推出,包含各种更新和修复。PHP 7.x 最好的地方在于安全升级,它真正改进了语言的安全协议。

本 PHP 安全教程包含什么内容?

很长一段时间以来,我一直致力于解决 PHP 安全和性能问题,在 PHP 社区中非常活跃,向顶级开发人员询问他们在实际项目中使用的技巧和窍门。因此,本PHP 安全教程的主要目的是让您了解PHP Web 应用程序中的安全最佳实践。我将定义以下问题并提及可能的解决方案。

  • 定期更新 PHP
  • 跨站脚本 (XSS)
  • SQL 注入攻击
  • 跨站请求伪造 XSRF/CSRF
  • 会话劫持
  • 从浏览器中隐藏文件
  • 安全上传文件
  • 对 HTTP 使用 SSL 证书
  • 在云端部署 PHP 应用程序

注意:请不要将其视为完整的备忘单。必须有更好的方法和更独特的解决方案开发人员将应用于他们的应用程序以使其完全安全。

PHP 安全最佳实践

在创建 PHP Web 应用程序时,Web 工程师应该关注安全最佳实践。不安全的 Web 应用程序使黑客有机会获取有价值的数据,例如客户信息或信用卡详细信息。此外,数据泄露可能会对您组织的有效性和未来运营产生极端影响。

定期更新 PHP

目前,可用的最稳定和最新的 PHP 版本是 PHP 8。我建议您必须将 PHP 应用程序更新到这个新版本。如果您仍在使用 PHP 5.6 或 7,那么在升级 PHP 应用程序时会遇到很多弃用。您还需要更新代码并更改一些功能逻辑,如密码哈希等。还有一些工具可用于检查代码的弃用情况并帮助您迁移这些代码。我在下面列出了一些工具:

  1. PHP Compatibility Checker
  2. PHP MAR
  3. Phan

如果您使用的是 PHPStorm,那么您可以使用 PHP 7 兼容性检查,它会告诉您哪些代码会导致您出现问题。

 

跨站脚本 (XSS)

跨站脚本是一种恶意 Web 攻击,其中将外部脚本注入到网站的代码或输出中。攻击者可以将受感染的代码发送给最终用户,而浏览器无法将其识别为受信任的脚本。这种攻击主要发生在用户有能力输入和提交数据的地方。攻击可以访问 cookie、会话和其他有关浏览器的敏感信息。让我们看一个通过 URL 发送一些数据的 GET 请求的例子:

URL: http://example.com/search.php?search=<script>alert('test')</script>

$search = $_GET['search'] ?? null;

echo 'Search results for '.$search;

您可以使用htmlspecialchars找出这种攻击。此外,通过使用 ENT_QUOTES,您可以转义单引号和双引号。

$search = htmlspecialchars($search, ENT_QUOTES, 'UTF-8');

echo 'Search results for '.$search;

同时,XSS 攻击还可以通过属性、编码的 URI 方案和代码编码来执行。

阅读更多: 在 Laravel 中防止 XSS

SQL 注入攻击

SQL 注入是 PHP 脚本中最常见的攻击。单个查询可能会危及整个应用程序。在 SQL 注入攻击中,攻击者试图更改您通过查询传递的数据。假设你在 SQL 查询中直接处理用户数据,突然,一个匿名攻击者偷偷使用不同的字符绕过它。请参阅下面提到的 SQL 查询:

$sql = "SELECT * FROM users WHERE username = '" . $username . "';

$username 可以包含可能损坏数据库的更改数据,包括在眨眼之间删除整个数据库。那么,解决方案是什么?PDO。我建议您始终使用准备好的语句。PDO 可帮助您保护 SQL 查询。

$id = $_GET['id'] ?? null;

数据库和应用程序之间的连接是通过以下语句建立的:

$dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'dbusername', 'dbpassword');

您可以根据上述 ID 选择用户名,但请稍等!在这里,SQL 代码“GET 数据”被注入到您的查询中。小心避免这样的编码,而是使用准备好的语句:

$sql = "SELECT username, email FROM users WHERE id = ".$id." ;

foreach ($dbh->query($sql) as $row) {

   printf ("%s (%s)\n", $row['username'], $row['email']);

}

现在您可以通过使用来避免上述 SQL 注入的可能性

$sql = "SELECT username, email FROM users WHERE id = :id";

$sth = $dbh->prepare($sql, [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]);

$sth->execute([':id' => $id]);

$users = $sth->fetchAll();

此外,一个好的做法是使用 ORM 之类的学说或 eloquent,因为在其中注入 SQL 查询的可能性最小。

阅读更多: 保护 PHP 网站免受 SQL 注入

跨站请求伪造 XSRF/CSRF

CSRF 攻击与 XSS 攻击完全不同。在 CSRF 攻击中,最终用户可以在经过身份验证的网站上执行不需要的操作,并且可以将恶意命令传输到站点以执行任何不需要的操作。CSRF 无法读取请求数据,并且主要通过在 HTML 标签中发送任何链接或更改数据来针对状态更改请求。它可以强制用户执行状态更改请求,例如转移资金、更改他们的电子邮件地址等。让我们看看这个 GET 请求将钱发送到另一个帐户的 URL:

GET http://bank.com/transfer.do?acct=TIM&amount=100 HTTP/1.1

现在,如果有人想利用 Web 应用程序,他/她将更改带有名称和数量的 URL,如下所示

http://bank.com/transfer.do?acct=Sandy&amount=100000

现在这个 URL 可以通过电子邮件在任何文件、图像等中发送,攻击者可能会要求你下载

文件或单击图像。一旦你这样做,你就会立即发送大量你永远不知道的钱。

会话劫持

会话劫持是一种特殊类型的恶意 Web 攻击,攻击者在其中秘密窃取用户的会话 ID。该会话 ID 被发送到相关联的 $_SESSION 数组验证其在堆栈中的存储并授予对应用程序的访问权限的服务器。会话劫持可能通过 XSS 攻击或当某人获得对存储会话数据的服务器上的文件夹的访问权限时。

为防止会话劫持,请始终将会话绑定到您的 IP 地址以:

$IP = getenv ( "REMOTE_ADDR" );

在 localhost 上工作时请注意它,因为它不会为您提供确切的 IP 而是 :::1 或 :::127 类型值。每当发生违规行为时,您应该尽快使会话无效(未设置 cookie、未设置会话存储、删除跟踪),并且在任何情况下都应始终尽量不公开 ID。

对于 cookie,最佳实践是永远不要使用存储在 cookie 中的序列化数据。黑客可以轻松地操纵 cookie,从而在您的范围内添加变量。像这样安全地删除 cookie:

setcookie ($name, "", 1);

setcookie ($name, false);

unset($_COOKIE[$name]);

代码的第一行确保 cookie 在浏览器中过期,第二行描述了删除 cookie 的标准方法(因此您不能在 cookie 中存储 false)。第三行从脚本中删除 cookie。

阅读更多: Redis 服务器作为 PHP 会话处理程序

从浏览器中隐藏文件

如果您使用过 PHP 的微框架,那么您一定已经看到了确保文件正确放置的特定目录结构。框架允许在该目录中有不同的文件,如控制器、模型、配置文件(.yaml)等,但大多数时候浏览器不会处理所有文件,但它们可以在浏览器中查看。要解决此问题,您不能将文件放在根目录中,而是放在公共文件夹中,这样它们就不会一直在浏览器中访问。下面看一下Slim 框架的目录结构:

安全上传文件

文件上传是任何用户数据处理应用程序的必要部分。但请记住,在某些情况下,文件也用于 XSS 攻击,正如我在上文中已经解释过的那样。回归基础,始终在表单中使用 POST 请求,并在 <form> 标签中声明属性enctype=”multipart/form-data” 。然后使用 finfo 类验证文件类型,如下所示:

$finfo = new finfo(FILEINFO_MIME_TYPE);
$fileContents = file_get_contents($_FILES['some_name']['tmp_name']);

$mimeType = $finfo->buffer($fileContents);

开发人员可以创建自己的自定义和超安全的文件验证规则,但一些框架,如 Laravel、Symfony 和 codeigniter 已经有预定义的方法来验证文件类型。

让我们看另一个例子。表单的 HTML 应该是这样的:

<form method="post" enctype="multipart/form-data" action="upload.php">

   File: <input type="file" name="pictures[]" multiple="true">

   <input type="submit">

</form>

upload.php 包含以下代码:

foreach ($_FILES['pictures']['error'] as $key => $error) {

   if ($error == UPLOAD_ERR_OK) {

       $tmpName = $_FILES['pictures']['tmp_name'][$key];

       $name = basename($_FILES['pictures']['name'][$key]);

       move_uploaded_file($tmpName, "/var/www/project/uploads/$name");

   }

}

正确声明UPLOAD_ERRbasename()可以防止目录遍历攻击,但也需要很少的其他验证(如文件大小、文件重命名和将上传的文件存储在私有位置)来加强应用程序的安全性。

阅读更多: PHP 中的图像和文件上传

为 HTTPS 使用 SSL 证书

所有现代浏览器,如 Google Chrome、Opera、Firefox 等,都建议对 Web 应用程序使用 HTTPS 协议。HTTPs 为不受信任的站点提供了一个安全和加密的访问通道。您必须通过在您的网站中安装 SSL 证书来包含 HTTPS。它还可以增强您的 Web 应用程序免受 XSS 攻击,并防止黑客使用代码读取传输的数据。Cloudways一键提供免费的SSL证书,有效期为90天,您可以轻松地一键撤销或续订。您可以按照指南在 PHP 、WordPress、Magento 和 Drupal 应用程序中设置SSL 证书。

在云端部署 PHP 应用程序

托管是任何 Web 应用程序的最后也是最重要的一步,因为您总是在本地PHP 服务器上创建项目并将它们部署在提供共享、云或专用托管的实时服务器上。我总是推荐使用像 DigitalOcean、Linode、AWS这样的云托管。对于任何类型的网站和应用程序,它们都是快速、安全和可靠的。它们始终提供安全层来防止对 Web 应用程序非常有害的 DDOS、蛮力和网络钓鱼攻击。

您可能还喜欢: Laravel 共享托管项目的陷阱

要在云服务器上部署 PHP 应用程序,您必须具备良好的 Linux 技能来创建强大的 Web 堆栈(如 LAMP 或 LEMP),这通常会花费您的时间和 Linux 专业人员的预算。相反,Cloudways 托管的PHP 和 MySQL 托管平台为您提供了使用 Thunderstack 部署服务器的简单方法,只需点击上述云提供商。Thunderstack 帮助您的 PHP 应用程序完全免受各种恶意攻击并保证优化的性能。

 

文档根设置

任何服务器上的 PHP 应用程序的文档根必须设置为var/www/ html,以便用户可以通过浏览器访问您的网站。但在某些情况下,当您使用 Laravel、Symfony 和 Slim 等框架开发 API 时,您需要将 webroot 更新到 ` /public文件夹。

/public 提供类似于带有 index.php 文件的简单 PHP 网站的应用程序输出。将 webroot 设置为var/www/html/public的目的是隐藏敏感文件,如 .htaccess 和 .env,其中包含环境变量和数据库、邮件、支付 API 的凭据。

此外,Laravel、Symfony 等框架建议不要将所有文件移动到根文件夹,而是创建一个很好的目录结构来保存视图、模型和控制器等相关文件是一种更合理的方法。

记录所有错误并隐藏在生产环境中

一旦您开发了网站并部署在实时服务器上。您必须做的第一件事是禁用错误显示,因为黑客可能会从错误中获得相同的有价值信息。在 php.ini 文件中设置此参数:

display_errors=Off

现在,关闭显示后,将PHP 错误记录到特定文件中以备将来需要:

log_errors=On

error_log=/var/log/httpd/php_scripts_error.log

显然,您可以根据需要更改文件名。

您可能还喜欢: 使用 PHP Rollbar 集成简化 Laravel 错误记录

Mysql 的白名单公共 IP

使用 PHP 应用程序时,您经常需要在内部脚本和 mysql 客户端中设置 mysql 数据库。大多数客户端用于建立MySQL 远程连接,需要主机服务器提供的 IP 地址或其他主机名来创建连接。

远程 Mysql 连接的公共 IP 必须在您的托管服务器中列入白名单,以便匿名用户无法访问数据库。

经常问的问题

问:如何测试 PHP 的安全性?

答:市场上很少有代码扫描工具可以帮助您分析 PHP 应用程序的代码质量和安全性。PHP Malware Finder (PMF) 是帮助在文件中查找恶意代码的顶级安全测试工具之一。您也可以使用 RIPS,这是一种流行的代码分析工具,可帮助实时查找代码漏洞。

Q:如何保证PHP数据库的安全?

答:为确保数据库安全,您应该始终使用 SQL 注入保护、数据库防火墙、常规数据加密和类似其他方法。

问:在 PHP 中加密密码的安全方法是什么?

A: Md5 是 Message Process 5 的缩写,sha1 是 Secure Hash Algorithm 1 的缩写。它们都用于加密字符串。一旦字符串被加密,它就会重复解码。Md5 和 sha1 在数据库中存储密码时特别有用。

问:什么是 PHP 漏洞?

答:PHP 对象注入是一种应用程序级漏洞,它似乎允许攻击者执行各种有害攻击,例如代码注入、SQL 注入、路径遍历和拒绝服务。

DDoS 攻击危害多个计算机系统攻击。通常的目标是服务器、网站或其他网络资源。

当用户提供的输入在传递给 unserialize() PHP 函数之前未进行管理时,就会发生这种情况。由于 PHP 允许对象序列化,攻击者可以将临时序列化字符串传递给无防御的 unserialize() 调用。

包起来!

那么, PHP 安全最佳实践是一个非常广泛的话题。来自世界各地的开发人员倾向于开发不同的用例来保护 Web 应用程序。虽然许多公司运行不同的赏金计划,以找出其应用程序中的安全漏洞和漏洞,从而奖励那些指出应用程序中严重漏洞的安全专家。本文涵盖基本的PHP 安全问题,以帮助您了解如何保护您的 PHP 项目免受不同的恶意攻击。我还将在未来写一些更多的PHP 安全提示和技巧。在此之前,您可以在下面的评论部分中贡献您的想法和安全实践。

猜你喜欢

转载自blog.csdn.net/allway2/article/details/126105106