防止XSS

XSS代表跨站脚本,它允许注入一个客户端的脚本(通常是JavaScript)到被用户观看的网页。考虑客户端脚本的能力,这会导致非常严重的后果,比如绕过安全检查、获取其它用户的身份或者数据泄露。

在本小节中,我们将会看到如何使用\yii\helpers\Html\yii\helpers\HtmlPurifier来转义输出从而防止XSS。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 创建controllers/XssController.php
  1. <?php
  2. namespace app\controllers;
  3. use Yii;
  4. use yii\helpers\Html;
  5. use yii\web\Controller;
  6. /**
  7. * Class SiteController.
  8. * @package app\controllers
  9. */
  10. class XssController extends Controller
  11. {
  12. /**
  13. * @return string
  14. */
  15. public function actionIndex()
  16. {
  17. $username = Yii::$app->request->get('username', 'nobody');
  18. return $this->renderContent(Html::tag('h1',
  19. 'Hello, ' . $username . '!'
  20. ));
  21. }
  22. }
  1. 通常情况下,他会被使用为/xss/simple?username=Administrator。然而,因为没有考虑安全准则过滤输入,转移输出,恶意的用户能够使用如下方式使用它:
  1. /xss/simple?username=<script>alert('XSS');</script>
  1. 上边的代码将会导致一个脚本注入,如下截图所示:

防止XSS - 图1

如何做…

执行如下步骤:

  1. 为了防止上边屏幕截图中的XSS警报,我们需要将其传给浏览器之前进行转义。方法如下:
  1. <?php
  2. namespace app\controllers;
  3. use Yii;
  4. use yii\helpers\Html;
  5. use yii\web\Controller;
  6. /**
  7. * Class SiteController.
  8. * @package app\controllers
  9. */
  10. class XssController extends Controller
  11. {
  12. /**
  13. * @return string
  14. */
  15. public function actionIndex()
  16. {
  17. $username = Yii::$app->request->get('username', 'nobody');
  18. return $this->renderContent(Html::tag('h1', Html::encode('Hello, ' . $username . '!')));
  19. }
  20. }
  1. 现在你就不会看到警告了,而是得到正确的转义的HTML,截图如下所示:

防止XSS - 图2

  1. 因此,基本的规则是,转义所有动态的数据。例如,我们应该为名字链接做同样的转义:
  1. use \yii\helpers\Html;
  2. echo Html::a(Html::encode($_GET['username']), array());

完成了。你的页面能防止XSS。如果我们希望一些HTML能通过怎么办?我们不能再使用\yii\helpers\Html::encode,因为它会将HTML输出为代码,而我们需要是的是实际的表示。幸运的是,Yii有一个工具,它能让你过滤恶意的HTML。这个工具名叫HTML Purifier,使用方法如下:

  1. <?php
  2. namespace app\controllers;
  3. use Yii;
  4. use yii\helpers\Html;
  5. use yii\helpers\HtmlPurifier;
  6. use yii\web\Controller;
  7. /**
  8. * Class SiteController.
  9. * @package app\controllers
  10. */
  11. class XssController extends Controller
  12. {
  13. /**
  14. * @return string
  15. */
  16. public function actionIndex()
  17. {
  18. $username = Yii::$app->request->get('username', 'nobody');
  19. $content = Html::tag('h1', 'Hello, ' . $username . '!');
  20. return $this->renderContent(
  21. HtmlPurifier::process($content)
  22. );
  23. }
  24. }

现在如果我们使用如下地址访问/xss/index?username=<i>username</i>!<script>alert('XSS')</script>,HTML净化器会移除恶意的部分,我们将会得到如下结果:

防止XSS - 图3

工作原理

  1. 深入底层看,\yii\helpers\Html::encode类似如下所示:
  1. public static function encode($content, $doubleEncode = true)
  2. {
  3. return htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE,
  4. Yii::$app ? Yii::$app->charset : 'UTF-8',
  5. $doubleEncode);
  6. }
  1. 所以本质上是用PHP的htmlspecialchars函数,只要第三个参数能正确传递,这个函数非常安全。

\yii\helpers\HtmlPurifier使用HTML净化库,这是解决HTML中XSS最先进的解决方案。我们使用了它的默认配置,这对绝大部分用户输入的内容都是有效的。

更多…

关于XSS和HTML净化器需要多了解一些东西。接下来的部分就会讨论。

XSS类型

XSS注入有两个主要的类型,如下:

  • 非持久
  • 持久

第一种类型是本小节中最常用的XSS类型;在大部分不安全的web应用中都可以发现。用户传递的数据不会被存储,所以注入脚本只有当用户输入的时候才会执行。但是,这看上去仍然不安全。恶意的用户可以将XSS放在一个链接中,然后放在别的网站上;当其它用户点击访问时,就会发生XSS注入。

第二种情况更验证,因为由恶意用户输入的数据被存储在了数据库中,并被展示给了很多网络用户。使用这种类型的XSS,恶意用户甚至可以通过命令,使其它用户删除他们能访问的数据,摧毁你的网站。

参考

欲了解更多关于XSS以及如何处理它,参考如下资源: