PHP 10 个常见平安题目(实例解说)
相关于其他几种说话来说, PHP 在 web 建站方面有更大的优势,即便是新手,也能很容易搭建一个网站出来。但这种优势也容易带来一些负面影响,由于许多的 PHP 教程没有触及到平安方面的知识。
此帖子分为几部分,每部分会涵盖不一样的平安要挟和应计策略。但是,这并不是说你做到这几点今后,就必然能幸免你的网站显现任何问题。假如你想提高你的网站平安性的话,你应当连续通过阅读书籍或者文章,来研讨怎样提高你的网站平安性
出于演示需要,代码大概不是很完善。日常开发历程中,许多代码都包括在了框架跟各种库里面。作为一个后台开发,你不仅要熟练根本的 CURD,更要知道怎样庇护你的数据。
1. SQL 注入
我赌一包辣条,你必定会看到这里。 SQL 注入是对您网站最大的要挟之一,假如您的数据库受到别人的 SQL 注入的攻击的话,别人可以转出你的数据库,或许还会发生更严峻的后果。
网站要从数据库中猎取动态数据,就必需施行 SQL 语句,举例如下:
<?php $username = $_GET['username']; $query = "SELECT * FROM users WHERE username = '$username'";
攻击者操纵通过 GET 和 POST 发送的查询(或者例如 UA 的一些其他查询)。一样状况下,你但愿查询户名为「 peter 」的会员发生的 SQL 语句如下:
SELECT * FROM users WHERE username = 'peter'
但是,攻击者发送了特定的会员名参数,例如:' OR '1'='1
这就会致使 SQL 语句变成这样:
SELECT * FROM users WHERE username = 'peter' OR '1' = '1'
这样,他就能在不需要密码的状况下输出你的整个会员表的数据了。
那么,我们怎样防止这类变乱的发生呢?主流的解决办法有两种。转义会员输入的数据或者使用封装好的语句。转义的办法是封装好一个函数,用来对会员提交的数据停止过滤,去除有害的标签。但是,我不太引荐使用这个办法,由于比力容易健忘在每个地方都做此处置。
下面,我来介绍怎样使用 PDO 施行封装好的语句( mysqi 也一样):
$username = $_GET['username']; $query = $pdo->prepare('SELECT * FROM users WHERE username = :username'); $query->execute(['username' => $username]); $data = $query->fetch();
动态数据的每个部分都以:做前缀。然后将所有参数作为数组传递给施行函数,看起来就像 PDO 为你转义了有害数据一样。
几乎所有的数据库驱动程序都支撑封装好的语句,没有理由不使用它们!养成使用他们的习惯,今后就不会健忘了。
2. XSS
XSS 又叫 CSS (Cross Site Script) ,跨站足本攻击。它指的是歹意攻击者往 Web 页面里插入歹意 html 代码,当会员阅读该页之时,嵌入其中 Web 里面的 html 代码会被施行,从而到达歹意攻击会员的非凡目的。
下面以一个搜索页面为例子:
<body> <?php $searchQuery = $_GET['q']; /* some search magic here */ ?> <h1>You searched for: <?php echo $searchQuery; ?></h1> <p>We found: Absolutely nothing because this is a demo</p> </body>
由于我们把会员的内容直接打印出来,不经过任何过滤,不法会员可以拼接 URL:
search.php?q=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E
PHP 渲染出来的内容如下,可以看到 Javascript 代码会被直接施行:
<body> <h1>You searched for: <script>alert(1);</script></h1> <p>We found: Absolutely nothing because this is a demo</p> </body>
问:JS 代码被施行有什么大不了的?
Javascript 可以:
偷走你会员阅读器里的 Cookie;
通过阅读器的记住密码功效猎取到你的站点登录账号和密码;
盗取会员的秘密信息;
你的会员在站点上能做到的事情,有了 JS 权限施行权限就都能做,也就是说 A 会员可以模拟成为任何会员;
在你的网页中嵌入歹意代码;
...
问:怎样防备此问题呢?
好新闻是比力先进的阅读器此刻已经具备了一些根基的 XSS 防备功效,不外请不要依靠与此。
准确的做法是坚定不要信赖会员的任何输入,并过滤掉输入中的所有非凡字符。这样就能覆灭绝大部分的 XSS 攻击:
<?php $searchQuery = htmlentities($searchQuery, ENT_QUOTES);
或者你可以使用模板引擎 Twig ,一样的模板引擎都会默许为输出加上 htmlentities 防备。
假如你保持了会员的输入内容,在输出时也要特殊留意,在以下的例子中,我们同意会员填写本人的博客链接:
<body> <a href="<?php echo $homepageUrl; ?>">Visit Users homepage</a> </body>
以上代码大概第一眼看不出来有问题,但是假设会员填入以下内容:
#" onclick="alert(1)
会被渲染为:
<body> <a href="#" onclick="alert(1)">Visit Users homepage</a> </body>
永久永久不要信赖会员输入的数据,或者,永久都假设会员的内容是有攻击性的,态度端正了,然后当心地处置好每一次的会员输入和输出。
别的设定 Cookie 时,假如无需 JS 读取的话,请必需设定为 "HTTP ONLY"。这个设定可以令 JavaScript 没法读取 PHP 端种的 Cookie。
3. XSRF/CSRF
CSRF 是跨站恳求捏造的缩写,它是攻击者通过一些技术手段诈骗会员去拜访曾经认证过的网站并运转一些操纵。
虽然此处展现的例子是 GET 恳求,但只是相较于 POST 更容易懂得,并非防护手段,两者都不是私密的 Cookies 或者多步表单。
假设你有一个同意会员删除账户的页面,如下所示:
<?php //delete-account.php $confirm = $_GET['confirm']; if($confirm === 'yes') { //goodbye }
攻击者可以在他的站点上构建一个触发这个 URL 的表单(一样适用于 POST 的表单),或者将 URL 加载为图片引诱会员点击:
<img src="https://example.com/delete-account.php?confirm=yes" />
会员一旦触发,就会施行删除账户的指令,瞬间你的账户就消逝了。
防备这样的攻击比防备 XSS 与 SQL 注入更复杂一些。
最常用的防备办法是生成一个 CSRF 令牌加密平安字符串,一样称其为 Token,并将 Token 储备于 Cookie 或者 Session 中。
每次你在网页结构表单时,将 Token 令牌放在表单中的潜藏字段,表单恳求效劳器今后会按照会员的 Cookie 或者 Session 里的 Token 令牌比对,校验成功才给予通过。
由于攻击者没法知道 Token 令牌的内容(每个表单的 Token 令牌都是随机的),因此没法假冒会员。
<?php /* 你嵌入表单的页面 */ ?> <form action="/delete-account.php" method="post"> <input type="hidden" name="csrf" value="<?php echo $_SESSION['csrf']; ?>"> <input type="hidden" name="confirm" value="yes" /> <input type="submit" value="Delete my account" /> </form>
##
<?php //delete-account.php $confirm = $_POST['confirm']; $csrf = $_POST['csrf']; $knownGoodToken = $_SESSION['csrf']; if($csrf !== $knownGoodToken) { die('Invalid request'); } if($confirm === 'yes') { //goodbye }
请留意,这是个非常简便的示例,你可以参加更多的代码。假如你使用的是像 Symfony 这样的 PHP 框架,那么自带了 CSRF 令牌的功效。
你还可以查看关于 OWASP 更具体的问题和更多防备机制的文章: https://github.com/OWASP/CheatS....
4. LFI
LFI (当地文件包括) 是一个会员未经历证从磁盘读取文件的破绽。
我经常碰到编程不标准的路由代码示例,它们不验证过滤会员的输入。我们用以下文件为例,将它要渲染的模板文件用 GET 恳求加载。
<body> <?php $page = $_GET['page']; if(!$page) { $page = 'main.php'; } include($page); ?> </body>
由于 Include 可以加载任何文件,不仅仅是 PHP,攻击者可以将系统上的任何文件作为包括目标传递。
index.php?page=../../etc/passwd
这将致使 /etc/passwd 文件被读取并展现在阅读器上。
要防备此类攻击,你必需细心思考同意会员输入的类型,并删除大概有害的字符,如输入字符中的 “.” “/” “\”。
假如你真的想使用像这样的路由系统(我不倡议以任何方式),你可以主动附加 PHP 扩展,删除任何非 [a-zA-Z0-9-_] 的字符,并指定从专用的模板文件夹中加载,避免被包括任何非模板文件。
我在不一样的开发文档中,屡次看到造成此类破绽的 PHP 代码。从一开端就要有清楚的设计思绪,同意所需要包括的文件类型,并删除掉余外的内容。你还可以结构要读取文件的绝对途径,并验证文件可否存在来作为庇护,而不是任何位置都给予读取。
5. 不充分的密码哈希
大部分的 Web 利用需要留存会员的认证信息。假如密码哈希做的足够好,在你的网站被攻破时,即可庇护会员的密码不被不法读取。
第一,最不该该做的事情,就是把会员密码明文贮存起来。大部分的会员会在多个网站上使用统一个密码,这是不成改动的事实。当你的网站被攻破,意味着会员的其他网站的账号也被攻破了。
其次,你不该该使用简便的哈希算法,事实上所有没有专门为密码哈希优化的算法都不该使用。哈希算法如 MD5 或者 SHA 设计初衷就是施行起来非常快。这不是你需要的,密码哈希的终极目标就是让黑客花费无限尽的时间和精神都没法破解出来密码。
别的一个比力重要的点是你应当为密码哈希加盐(Salt),加盐处置幸免了两个一样的密码会发生一样哈希的问题。
以下使用 MD5 来做例子,所以请千万不要使用 MD5 来哈希你的密码, MD5 是不平安的。
假设我们的会员 user1 和 user315 都有雷同的密码 ilovecats123,这个密码虽然看起来是强密码,有字母有数字,但是在数据库里,两个会员的密码哈希数据将会是雷同的:5e2b4d823db9d044ecd5e084b6d33ea5 。
假如一个假如黑客拿下了你的网站,猎取到了这些哈希数据,他将不需要去暴力破解会员 user315 的密码。我们要尽量让他花大精神来破解你的密码,所以我们对数据停止加盐处置:
<?php //warning: !!这是一个很不平安的密码哈希例子,请不要使用!! $password = 'cat123'; $salt = random_bytes(20); $hash = md5($password . $salt);
最后在留存你的独一密码哈希数据时,请不要健忘连 $salt 也已经留存,不然你将没法验证会员。
在当下,最好的密码哈希选项是 bcrypt,这是专门为哈希密码而设计的哈希算法,同时这套哈希算法里还同意你配置一些参数来加大破解的难度。
新版的 PHP 中也自带了平安的密码哈希函数 password_hash ,此函数已经包括了加盐处置。对应的密码验证函数为 password_verify 用来检测密码可否准确。password_verify 还可有效防止 时序攻击.
以下是使用的例子:
<?php //user signup $password = $_POST['password']; $hashedPassword = password_hash($password, PASSWORD_DEFAULT); //login $password = $_POST['password']; $hash = '1234'; //load this value from your db if(password_verify($password, $hash)) { echo 'Password is valid!'; } else { echo 'Invalid password.'; }
需要澄清的一点是:密码哈希并不是密码加密。哈希(Hash)是将目标文本转换成具有雷同长度的、不成逆的杂凑字符串(或叫做新闻摘要),而加密(Encrypt)是将目标文本转换成具有不一样长度的、可逆的密文。明显他们之间最大的不同是可逆性,在贮存密码时,我们要的就是哈希这种不成逆的属性。
6. 中心人攻击
MITM (中心人) 攻击不是针对效劳器直接攻击,而是针对会员停止,攻击者作为中心人诈骗效劳器他是会员,诈骗会员他是效劳器,从而来拦截会员与网站的流量,并从中注入歹意内容或者读取私密信息,平常发生在公共 WiFi 网络中,也有大概发生在其他流量通过的地方,例如 ISP 运营商。
对此的独一防备是使用 HTTPS,使用 HTTPS 可以将你的连接加密,并且没法读取或者篡改流量。你可以从 Let's Encrypt 猎取免费的 SSL 证书,或从其他供给商处购置,这里不具体介绍怎样准确配置 WEB 效劳器,由于这与利用程序平安性无关,且在很大程度上取决于你的设定。
你还可以采取一些办法使 HTTPS 更平安,在 WEB 效劳器配置加上 Strict-Transport-Security 标示头,此头部信息告诉阅读器,你的网站始终通过 HTTPS 拜访,假如未通过 HTTPS 将返回错误报告提醒阅读器不该显示该页面。
然而,这里有个明显的问题,假如阅读器此前从未拜访过你的网站,则没法知道你使用此标示头,这时候就需要用到 Hstspreload。
可以在此注册你的网站: https://hstspreload.org/
你在此处提交的所有网站都将被标志为仅 HTTPS,并硬编码到 Google Chrome、FireFox、Opera、Safari、IE11 和 Edge 的源代码中。
你还可以在 DNS 配置中增加 Certification Authority Authorization (CAA) record ,可以仅同意一个证书颁布机构(例如: Let's encrypt)公布你的域名证书,这进一步提高了会员的平安性。
7. 命令注入
这大概是效劳器碰到的最严峻的攻击,命令注入的目标是诈骗效劳器施行任意 Shell 命令
你假如使用 shell_exec 或是 exec 函数。让我们做一个小例子,同意会员简便的从效劳器 Ping 不一样的主机。
<?php $targetIp = $_GET['ip']; $output = shell_exec("ping -c 5 $targetIp");
输出将包罗对目标主机 Ping 5 次。除非采纳 sh 命令施行 Shell 足本,不然攻击者可以施行想要的任何操纵。
ping.php?ip=8.8.8.8;ls -l /etc
Shell 将施行 Ping 和由攻击者拼接的第二个命令,这明显是非常危险的。
感激 PHP 供给了一个函数来转义 Shell 参数。
escapeshellarg 转义会员的输入并将其封装成单引号。
<?php $targetIp = escapeshellarg($_GET['ip']); $output = shell_exec("ping -c 5 $targetIp");
此刻你的命令应当是相当平安的,就个人而言,我依然幸免使用 PHP 调取外部命令,但这完全取决于你本人的喜欢。
别的,我倡议进一步验证会员输入可否相符你盼望的情势。
8. XXE
XXE (XML 外部实体) 是一种利用程序使用配置不准确的 XML 解析器解析外部 XML 时,致使的当地文件包括攻击,乃至可以长途代码施行。
XML 有一个不为人知的特性,它同意文档作者将长途和当地文件作为实体包括在其 XML 文件中。
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY passwd SYSTEM "file:///etc/passwd" >]> <foo>&passwd;</foo>
就像这样, /etc/passwd 文件内容被转储到 XML 文件中。
假如你使用 libxml 可以调取 libxml_disable_entity_loader 来庇护本人免受此类攻击。使用前请细心检查 XML 库的默许配置,以确保配置成功。
9. 在生产环境中不准确的错误报告显露敏锐数据
假如你不当心,大概会在生产环境中由于不准确的错误报告泄露了敏锐信息,例如:文件夹构造、数据库构造、连接信息与会员信息。
你是不但愿会员看到这个的吧?
一样按照你使用的框架或者 CMS ,配置办法会有不一样的转变。平常框架具有同意你将站点更换为某种生产环境的设定。这样会将所有会员可见的错误新闻重定向到日志文件中,并向会员显示非描写性的 500 错误,同时同意你按照错误代码检查。
但是你应当按照你的 PHP 环境设定: error_reporting 与 display_errors.
10. 登录限制
像登录这样的敏锐表单应当有一个严厉的速率限制,以防止暴力攻击。留存每个会员在过去几分钟内失败的登录尝试次数,假如该速率超越你定义的阈值,则回绝进一步登录尝试,直到冷却期完毕。还可通过电子邮件通知会员登录失败,以便他们知道本人的账户被成为目标。
一些其他补充
不要信赖从会员传递给你的对象 ID ,始终验证会员对恳求对象的拜访权限
效劳器与使用的库时刻保持最新
订阅关注平安相关的博客,理解最新的解决方案
从不在日志中留存会员的密码
不要将整个代码库储备在 WEB 根名目中
永久不要在 WEB 根名目创立 Git 储备库,除非你但愿泄露整个代码库
始终假设会员的输入是不平安的
设定系统制止可疑行动的 IP 显示,例如:工具对 URL 随机扫描、爬虫
不要过分信赖第三方代码是平安的
不要用 Composer 直接从 Github 猎取代码
假如不但愿站点被第三方跨域 iframe,请设定反 iframe 标示头
迷糊是不平安的
假如你是缺乏实践经历的运营商或合作开发人员,请确保尽大概经常检查代码
当你不理解平安功效应当怎样工作,或者为什么会安置,请扣问知道的人,不要无视它
永久不要本人写加密方式,这大概是个坏的办法
假如你没有足够的熵,请准确播种你的伪随机数生成并舍弃
假如在互联网上不平安,并有大概被窃取信息,请为这种状况做好预备并拟定事件响应方案
禁用 WEB 根名目列表显示,许多 WEB 效劳器配置默许都会列出名目内容,这大概致使数据泄露
客户端验证是不足的,需要再次验证 PHP 中的所有内容
小贴士
我不是一个平安专家,恐没法做到事无巨细。尽管编写平安软件是一个非常疾苦的历程,但还是可以通过遵照一些根本规则,编写合理平安的利用程序。其实,许多框架在这方面也帮我们做了许多工作。
在问题发生此前,平安性问题并不像语法错误等可以在开发阶段追踪到。因此,在编写代码的历程中,应当时刻有躲避平安风险的意识。假如你迫于业务需求的压力而不得不临时忽略一些平安防备的工作,我想你有必要事先告知大家这样做的潜在风险。
假如你从这篇文章有所收益,也请把它分享给你的伴侣们把,让我们共建平安网站。
引荐教程:《PHP教程》
以上就是PHP 10 个常见平安问题(实例讲解)的具体内容,更多请关注百分百源码网其它相关文章!