在ASP.. NET 4.5,我应该如何编码字符串用作JavaScript变量,以防止XSS攻击



我知道有几种方法可以做到这一点,但它们都有一些缺点。有没有一种"公认的"、被认为是最好的方法?

我曾经使用Microsoft.Security.Application.AntiXss.JavaScriptEncode(),这是伟大的,但AntiXSS已经结束了生命,因为编码器现在包含在。net 4.5。

然而,由于某种原因,System.Web.Security.AntiXss.AntiXssEncoder不包括JavaScriptEncode方法。

System.Web.HttpUtility.JavaScriptStringEncode(),但它使用黑名单方法进行编码,所以它不太可能像白名单编码器那样好。

我看到一些建议使用System.Web.Script.Serialization.JavaScriptSerializer.Serialize(),但这只是调用HttpUtility.JavaScriptStringEncode()

所以什么是目前最好的接受,白名单方法编码值写成JS变量?

如果您希望在<script>块中包含JavaScript代码,如:

<script>
var myVariable = '<%=thisIsWrong %>';
</script>

那么在这个上下文中应该使用HttpUtility.JavaScriptStringEncode。此函数还正确地编码特殊字符,因此,如果要在脚本标记中呈现</script>,试图关闭HTML脚本标记以准备接受XSS攻击,则将其呈现为:

u003c/scriptu003e

是正确的编码,JavaScript可以将其理解为</script>,但浏览器不会将其解释为文字结束脚本标记。一些天真编写的JavaScript编码例程不会转换它,因为序列不包含, "'字符。

如果您不确保关闭脚本标签没有呈现,那么像这样的攻击是可能的。假设这是应用程序的输入:

</script><script>alert(1)</script>

在浏览器中呈现为

<script type="text/javascript">
alert('</script><script>alert(1)</script>');
</script>

,浏览器将解释以alert('</script>结尾的脚本标记,并简单地执行新脚本标记中的内容。

对于JavaScriptStringEncode函数,这是安全的,因为它呈现为:

<script type="text/javascript">
alert('u003c/scriptu003eu003cscriptu003ealert(1)u003c/scriptu003e');
</script>

不包含</script>以便浏览器解释。

有system . web . httutility . javascriptstringencode(),但是它使用了黑名单方法进行编码,所以它不太可能像白名单编码器。

. net中的一些其他编码函数确实使用了黑名单方法,但是在我自己的测试中,JavaScriptStringEncode似乎是足够的。

OWASP对JavaScript的推荐值是

除字母数字字符外,转义小于的所有字符256与xHH格式,以防止切换出数据值

以便您可以轻松地编写自己的代码来遵守此规则。

注意,如果你想在属性标签中包含代码:

<a href="http://example.com" onclick="alert('<%=wrong>')">Click</a>

则OWASP方法意味着您不必太关心HTML编码(因为实际上没有输出具有特殊含义的HTML字符)。如果没有(例如使用JavaScriptScriptEncode),您还需要HTML编码。

说了这么多,一个更安全的方法是接近它,就像我的问题的答案在外部JavaScript文件中插入动态值的安全方式。使用data-属性将动态值放在DOM中(在HTML中),然后使用JavaScript提取这些值。

如果不将不安全的字符串放在可以解释为脚本的地方(例如在<script>标记之间),则永远不必担心XSS。我知道不是所有东西都可以很容易地重新设计,但如果我是您,我会尝试将数据(HTML编码)放入隐藏的HTML元素中并在JavaScript中读取该元素的值,或者以JSON格式对变量进行AJAX请求。

Encoder.cs的源代码是可用的,并且"受Microsoft许可许可"约束"

    public static string JavaScriptEncode(string input, bool emitQuotes)
    {
        // Input validation: empty or null string condition
        if (string.IsNullOrEmpty(input))
        {
            return emitQuotes ? JavaScriptEmptyString : string.Empty;
        }
        // Use a new char array.
        int outputLength = 0;
        int inputLength = input.Length;
        char[] returnMe = new char[inputLength * 8]; // worst case length scenario
        // First step is to start the encoding with an apostrophe if flag is true.
        if (emitQuotes)
        {
            returnMe[outputLength++] = ''';
        }
        for (int i = 0; i < inputLength; i++)
        {
            int currentCharacterAsInteger = input[i];
            char currentCharacter = input[i];
            if (SafeListCodes[currentCharacterAsInteger] != null || currentCharacterAsInteger == 92 || (currentCharacterAsInteger >= 123 && currentCharacterAsInteger <= 127))
            {
                // character needs to be encoded
                if (currentCharacterAsInteger >= 127)
                {
                    returnMe[outputLength++] = '\';
                    returnMe[outputLength++] = 'u';
                    string hex = ((int)currentCharacter).ToString("x", CultureInfo.InvariantCulture).PadLeft(4, '0');
                    returnMe[outputLength++] = hex[0];
                    returnMe[outputLength++] = hex[1];
                    returnMe[outputLength++] = hex[2];
                    returnMe[outputLength++] = hex[3];
                }
                else
                {
                    returnMe[outputLength++] = '\';
                    returnMe[outputLength++] = 'x';
                    string hex = ((int)currentCharacter).ToString("x", CultureInfo.InvariantCulture).PadLeft(2, '0');
                    returnMe[outputLength++] = hex[0];
                    returnMe[outputLength++] = hex[1];
                }
            }
            else
            {
                // character does not need encoding
                returnMe[outputLength++] = input[i];
            }
        }
        // Last step is to end the encoding with an apostrophe if flag is true.
        if (emitQuotes)
        {
            returnMe[outputLength++] = ''';
        }
        return new string(returnMe, 0, outputLength);
    }

相关内容

  • 没有找到相关文章

最新更新