In ASP.NET 4.5, how should I encode a string that will be used as a JavaScript variable to prevent XSS attacks

I know several ways to do this, but they all have a flaw. Is there an “acceptable” way to do this, which is considered the best?

I used to use Microsoft.Security.Application.AntiXss.JavaScriptEncode() , which was great, but AntiXSS was at the end of my life, because now the encoder is now included in .NET with 4.5.

However, for some reason, System.Web.Security.AntiXss.AntiXssEncoder does not include the JavaScriptEncode method.

There is System.Web.HttpUtility.JavaScriptStringEncode() , but it uses a blacklist method to encode, so it is unlikely to be as good as a whitelist encoder.

And I saw some recommendations for using System.Web.Script.Serialization.JavaScriptSerializer.Serialize() , but that just calls HttpUtility.JavaScriptStringEncode() .

So, what is currently the most acceptable, white list of methods for encoding values ​​written out as JS variables?

+2
source share
3 answers

If you want to include JavaScript code in the <script> block as follows:

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

Then, in this context, you should use HttpUtility.JavaScriptStringEncode . This function also correctly encodes special characters, so if </script> should appear in the script tag when trying to close the HTML script tag, ready for an XSS attack, it will display as:

 \u003c/script\u003e 

which is the correct encoding for JavaScript to understand as </script> but without a browser interpreting it as a literal closing tag script. Some naively written JavaScript coding procedures will not convert this because the sequence does not contain the characters \ , " or ' .

If you are not sure that closing script tags is not displayed, such an attack is possible. Imagine this is the input for your application:

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

which is displayed in the browser as

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

and the browser interprets the script tag ending in alert('</script> , and simply executes what is in the new script tag.

Using the JavaScriptStringEncode function is safe because it displays as:

 <script type="text/javascript"> alert('\u003c/script\u003e\u003cscript\u003ealert(1)\u003c/script\u003e'); </script> 

which does not contain </script> for interpreting the browser.

There is System.Web.HttpUtility.JavaScriptStringEncode (), but it uses a blacklist to encode, so it is unlikely to be as good as a whitelist encoder.

Some of the other encoding functions in .NET use blacklist methods, however in my own testing, JavaScriptStringEncode seems to be enough.

OWASP Recommendation for JavaScript

With the exception of alphanumeric characters, avoid all characters less than 256 with the \ xHH format to prevent the data value from being turned off in a script context or other attribute.

so you can easily write your own to fit that.

Note that if you want to include code in attribute tags:

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

then the OWASP method means that you also do not need to worry about HTML encoding (because in fact no HTML characters with a special meaning are output). Without (e.g. with JavaScriptScriptEncode ) you also need to encode HTML.

Having said all this, a safer way to get closer to it is as an answer to my question. A safe way to insert dynamic values ​​into external JavaScript files . Use the data- attributes to place dynamic values ​​in the DOM (in HTML), and then use JavaScript to extract these values. This will prevent all headaches in JavaScript encoding.

+4
source

The source code for Encoder.cs is available and "subject to a Microsoft licensing license"

  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); } 
+2
source

Unless you put an insecure string in a place where it can be interpreted as a script (for example, between <script> tags), you will never have to worry about XSS. I know that not everything can be easily redone, but if I were you, I would try to put the data (HTML encoded) in a hidden HTML element and read the value of this element in JavaScript or execute an AJAX request for a variable in JSON format.

+2
source

Source: https://habr.com/ru/post/988557/


All Articles