在客户端对XSS使用输出编码是否安全?

时间:2014-10-30 08:43:09

标签: security xss code-injection cross-site

防止XSS攻击的常用技术是在将不受信任的数据显示在HTML页面上之前对其进行编码。在页面内部可以出现不同的上下文,每个上下文都需要不同的编码。

在服务器端对响应进行编码没有意义,因为在此层我们不知道HTML页面中数据的显示位置。

因此在客户端编码更方便,更合理。问题是它是否安全。在第一印象中,听起来不安全,因为攻击者可以修改客户端代码(比如JavaScript)。但是当你考虑它时,修改后的代码只能供攻击者的浏览器使用。该网站的其他访问者不会受到这些变化的影响。

它是否仍然安全或我遗失了什么?

2 个答案:

答案 0 :(得分:3)

理论上,编码客户端并不比编码服务器端更危险。确保其安全的关键在于如何在呈现数据的所有位置放置合适的编码。您当然可以在客户端和服务器端安全地创建用于提交用户提交数据的良好实现。实际上,实现输出编码客户端的一个缺点是潜在的攻击者可以轻松地检查您的源代码是否存在缺陷。这意味着如果您的客户端编码实现中存在错误,那么在服务器端(假设是一个封闭的源系统)将更容易找到。如果您正在开发开源软件,那么这一点就没有用了。

另外正如您所说,攻击者修改您的客户端编码代码不是问题,因为他们只会修改自己的代码副本,不会影响其他访问者。

IMO让客户端处理编码实际上更加清晰,特别是如果您正在开发由Web和本机移动应用程序共享的API。您不希望移动应用程序必须将HTML编码值转换回原始格式。

答案 1 :(得分:2)

在服务器端使用XSS进行战斗并不像您想象的那么困难。目标是知道您应该在哪个上下文中编码哪个字符。

基本上我们应该考虑有关XSS的4种不同背景。

HTML上下文

如果您想在此上下文中将XSS作为攻击者,则需要<和>字符。因此只对这两个字符进行编码就可以解决基于HTML Context的XSS。

   /**
     * XSS protection function for HTML context only
     * @usecases
     * <title>use this function if output reflects here or as a content of any HTML tag.</title>
     * e.g.,  <span>use this function if output reflects here</span>
     * e.g., <div>use this function if output reflects here</div>
     * @description
     * Sanitize/Filter < and > so that attacker can not leverage them for JavaScript execution.
     * @author Ashar Javed
     * @Link https://twitter.com/soaj1664ashar
     * @demo http://xssplaygroundforfunandlearn.netai.net/final.html
     */
    function htmlContextCleaner($input) {
        $bad_chars = array("<", ">");
        $safe_chars = array("&lt;", "&gt;");
        $output = str_replace($bad_chars, $safe_chars, $input);
        return stripslashes($output);
    }

Javascript背景

最常见的用例如下面的代码。

<script> var name = 'USERINPUTISHERE';</script>

<script> var name = "USERINPUTISHERE";</script>

<button type="submit" onclick="return callSomeFunction('USERINPUTHERE')">

为了防止您的应用程序针对JS Context Based XSS攻击。您需要编码6个特定字符。请阅读以下描述以了解脚本上下文的攻击向量。

/**
 * XSS protection function for script context only
 * @usecases
 * @double quoted case e.g.,
 * <script> var searchquery = "use this function if output reflects here"; </script>
 * @single quoted case e.g.,
 * <script> var searchquery = 'use this function if output reflects here'; </script>
 * @description
 * Sanitize/Filter meta or control characters that attacker may use to break the context e.g.,
 * "; confirm(1); " OR '; prompt(1); // OR </script><script>alert(1)</script>
 * \ and % are filtered because they may break the page e.g., \n or %0a
 * & is sanitized because of complex or nested context (if in use)
 * @author Ashar Javed
 * @Link https://twitter.com/soaj1664ashar
 * @demo http://xssplaygroundforfunandlearn.netai.net/final.html
 */
function scriptContextCleaner($input) {
    $bad_chars = array("\"", "<", "'", "\\\\", "%", "&");
    $safe_chars = array("&quot;", "&lt;", "&apos;", "&bsol;", "&percnt;", "&amp;");
    $output = str_replace($bad_chars, $safe_chars, $input);
    return stripslashes($output);
}

属性上下文

以下代码可以是属性上下文的示例。

<input name="fname" value="USERINPUTISHERE">

或样本示例的单引号形式。

<input name='fname' value='USERINPUTISHERE'>

基本上我们需要编码非常特殊的字符以使其安全。我们还需要对back-tick进行编码,以便为旧版IE提供安全上下文。请阅读以下说明和代码。

 /**
     * XSS protection function for an attribute context only
     * @usecases
     * @double quoted case e.g.,
     * <div class="use this function if output reflects here">attribute context</div>
     * In above example class attribute have been used but it can be any like id or alt etc.
     * @single quoted case e.g.,
     * <input type='text' value='use this function if output reflects here'>
     * @description
     * Sanitize/Filter meta or control characters that attacker may use to break the context e.g.,
     * "onmouseover="alert(1) OR 'onfocus='confirm(1) OR ``onmouseover=prompt(1)
     * back-tick i.e., `` is filtered because old IE browsers treat it as a valid separator.
     * @author Ashar Javed
     * @Link https://twitter.com/soaj1664ashar
     * @demo http://xssplaygroundforfunandlearn.netai.net/final.html
     */
    function attributeContextCleaner($input) {
        $bad_chars = array("\"", "'",  "``");
        $safe_chars = array("&quot;", "&apos;", "&grave;");
        $output = str_replace($bad_chars, $safe_chars, $input);
        return stripslashes($output);
    }

风格背景

作为攻击者,使用样式上下文获取XSS通常与IE有关。请再次阅读以下说明和代码。

/**
 * XSS protection function for style context only
 * @usecases
 * @double quoted case e.g.,
 * <span style="use this function if output reflects here"></span>
 * @single quoted case e.g.,
 * <div style='use this function if output reflects here'></div>
 * OR <style>use this function if output reflects here</style>
 * @description
 * Sanitize/Filter meta or control characters that attacker may use to execute JavaScript e.g.,
 * ( is filtered because width:expression(alert(1))
 * & is filtered in order to stop decimal + hex + HTML5 entity encoding
 * < is filtered in case developers are using <style></style> tags instead of style attribute.
 * < is filtered because attacker may close the </style> tag and then execute JavaScript.
 * The function allows simple styles e.g., color:red, height:100px etc.
 * @author Ashar Javed
 * @Link https://twitter.com/soaj1664ashar
 * @demo http://xssplaygroundforfunandlearn.netai.net/final.html
 */
function styleContextCleaner($input) {
    $bad_chars = array("\"", "'", "``", "(", "\\\\", "<", "&");
    $safe_chars = array("&quot;", "&apos;", "&grave;", "&lpar;", "&bsol;", "&lt;", "&amp;");
    $output = str_replace($bad_chars, $safe_chars, $input);
    return stripslashes($output);
}

<强>结论

如果您知道哪些字符应在其特殊上下文中进行编码,则可以轻松使用XSS进行服务器端编码。当你使用返回tick(`)作为属性分隔符(例如跟随)时,只有一个复杂因素。

<input name=`fname` value=`USERINPUTHERE`>

此功能无法保护您的应用。但是我没有看到这个案例的真实例子!!!

我在上面描述的方法是针对数十名黑客/安全研究人员进行测试的,没有人利用它。 (详情:https://twitter.com/soaj1664ashar/status/478939711667712000)。 Symphonycms也使用这种方法进行XSS预防(所有代码示例都从他们的回购中抓取。https://github.com/symphonycms/xssfilter/blob/master/lib/xss.php

正如您所看到的,您需要知道变量将反映在哪个位置。通常,开发人员知道变量的输出位置,但如果你真的不知道DOMPurify对你来说可能更有用,但我相信它可能会导致代码复杂性并且难以维护。

<强> DOMPurify

DOMPurify是一种仅限DOM,超快速,超级容忍的XSS清理程序,适用于HTML,MathML和SVG。它是用JavaScript编写的,适用于所有现代浏览器(Safari,Opera(15 +),Internet Explorer(9+),Firefox和Chrome)以及使用Blink或WebKit的几乎所有其他浏览器。它不会在IE6或其他传统浏览器上中断。它根本就什么都不做。

DOMPurify是由具有广泛的Web攻击和XSS背景的安全人员编写的。不要害怕。

此处可以找到更多信息(https://github.com/cure53/DOMPurify