php常见安全问题实例讲解

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 = https://www.isolves.com/it/cxkf/yy/php/2019-07-10/$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>
【php常见安全问题实例讲解】问:JS 代码被执行有什么大不了的?
JavaScript 可以:
偷走你用户浏览器里的 Cookie;
通过浏览器的记住密码功能获取到你的站点登录账号和密码;
盗取用户的机密信息;
你的用户在站点上能做到的事情,有了 JS 权限执行权限就都能做,也就是说 A 用户可以模拟成为任何用户;
在你的网页中嵌入恶意代码;
...
问:如何防范此问题呢?
好消息是比较先进的浏览器现在已经具备了一些基础的 XSS 防范功能,不过请不要依赖与此 。
正确的做法是坚决不要相信用户的任何输入,并过滤掉输入中的所有特殊字符 。这样就能消灭绝大部分的 XSS 攻击:
<?php
$searchQuery = htmlentities($searchQuery, ENT_QUOTES);
或者你可以使用模板引擎 Twig ,一般的模板引擎都会默认为输出加上 htmlentities 防范 。
如果你保持了用户的输入内容,在输出时也要特别注意,在以下的例子中,我们允许用户填写自己的博客链接:
<body>
<a href=https://www.isolves.com/it/cxkf/yy/php/2019-07-10/"">Visit Users homepage
</body>
以上代码可能第一眼看不出来有问题,但是假设用户填入以下内容:
#" onclick="alert(1)
会被渲染为:
<body>
<a href=https://www.isolves.com/it/cxkf/yy/php/2019-07-10/"#" onclick="alert(1)">Visit Users homepage
</body>
永远永远不要相信用户输入的数据,或者,永远都假设用户的内容是有攻击性的,态度端正了,然后小心地处理好每一次的用户输入和输出 。


推荐阅读