Wednesday, 1 August 2012
Understanding XSS (Cross-Site Scripting) Findings in SCA
« Format Strings: Is Objective-C Objectively Safer? | Main | 150 ways to bypass ordinary WAF's but not ours, by design! »
In today’s post I am going to answer three questions that I am getting from a lot of users: 1. Why we report XSS issues when HTML encoding is applied to untrusted data, 2. Why SCA does not identify custom encoding methods, and 3. Why SCA does not understand the output context of untrusted data. I am NOT going to go into proper output encoding as it has been discussed in great detail at https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet and https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet.
It is easy to think you are immune to XSS because you are HTML output encoding your untrusted data but HTML encoding is just one of the encodings used to address XSS. XSS is a difficult problem to mitigate properly. You have to have proper input validation and contextual output encoding (i.e. HTML encoding, URL encoding, HTML Attribute encoding, CSS encoding, and Script encoding in their appropriate contexts).
Why Doesn’t HTML Encoding Mitigate XSS in All Contexts
You would think that HTML encoding in a URL context or JavaScript event handler would work fine to mitigate XSS because the parser in a JavaScript event handler or URL context would not understand HTML encoding and therefore the attack payload would fail. However, this is not the case because the browser decodes HTML-encoded content in an URL or JavaScript event handler at runtime.
All of the following are still executable even though the output is HTML encoded
HTML encoding in a URL context (the payload is “javascript:alert(123)”):
<a href=” javascript:alert(123)”>Click Me</a>
HTML encoding in a JavaScript event handler (the payload is “javascript:alert(123)”):
<a href=”#” onclick=” javascript:alert(123)”>Click Me</a>
If your application is outputting XHTML then the following will still pop even though all of the javascript code is HTML encoded (the file extension must be *.xhtml or the content type has to be set to "application/xhtml+xml"):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript"> alert(11)</script>
</head>
<body>
<div>TODO write content</div>
</body>
</html>
So HTML encoding will not mitigate XSS in all contexts and cannot be trusted as a complete solution to XSS. First question down, let’s move to the second question.
Why SCA Doesn’t Identify Custom Encoding Methods
Identifying custom encoding methods is very difficult from a practical perspective. There are many ways to implement a custom encoding method and the selection of characters to encode varies based on the implementation and context in which the untrusted data is to be output. For example, some encoding implementations believe <, >, ‘, “, and & are sufficient to mitigate against XSS in an HTML context. Other implementations only encode < and >. While others encoders add other characters including \ and /. Furthermore, each encoding context has multiple ways of encoding. HTML can used decimal or hexadecimal values. JavaScript encoding can use hexadecimal, octal, backslash, or Unicode encodings. To find such constructs would require the implementation of a new source code analyzer and would significantly prolong scan times. So trying to determine custom encoding methods is a difficult task with limited returns.
If you have a custom encoding method that you trust to stop XSS and it is applied in the appropriate contexts, then you can write a pass through rule which adds the following taints: +VALIDATED_CROSS_SITE_SCRIPTING_REFLECTED, +VALIDATED_CROSS_SITE_SCRIPTING_PERSISTENT, +POORVALIDATION.
Here is a sample rule which addresses the HTML context:
<DataflowPassthroughRule formatVersion="3.5" language="java">
…
<TaintFlags>+VALIDATED_CROSS_SITE_SCRIPTING_REFLECTED,+VALIDATED_CROSS_SITE_SCRIPTING_PERSISTENT,+POORVALIDATION</TaintFlags>
<FunctionIdentifier>
…
<FunctionName>
<Pattern>encodeForHTML</Pattern>
</FunctionName>
<ApplyTo implements="true" overrides="true" extends="true"/>
</FunctionIdentifier>
<InArguments>0</InArguments>
<OutArguments>return</OutArguments>
</DataflowPassthroughRule>
The VALIDATED_* taints remove the findings that move through the encoding function from the Reflected and Persisted XSS findings. The +POORVALIDATION will move all of the findings that were going through the custom encoding method to a new category called XSS: Poor Validation. The findings in XSS: Poor Validation are the dataflows which should be quickly skimmed to make sure that the correct encoding is being applied in the correct context. The purpose of this is to allow you to quickly segregate the XSS findings with no encoding from the XSS findings with some encoding. But this leads to another question, “Why can’t we identify the context that untrusted data is being output to more intelligently identify exploitable vulnerabilities?”
Why SCA Doesn’t Understand the Context in which Untrusted Data is Output
This is another question I often get and again the answer is that it is difficult to do without explicit control of where the data is being written to and the encoding which is applied to the output at that location.
Lets take a look at an example to better illustrate the difficulty of the problem:
<div style=’background-image: url(javascript:callFunc(“<%=untrusted_var%>”)’ …>
…
<script>
function callFunc(input) {
document.write(input);
}
</script>
What context do you think untrusted_var is in? Well when you look at where the entrusted data is output you might guess that because untrusted data is output in a “style” attribute it is in a CSS context. Wrong.
How about the URL context because of the call to the CSS url() function. Wrong.
How about JavaScript context because of the “javascript:”? At first glance, you would be technically correct but does JavaScript encoding mitigate this XSS? JavaScript encoding does stop the attacker from escaping out of the quotes (injecting up) but when the data is passed to the callFunc() and output using document.write() the XSS pops. As you can see, trying to figure out the output context is a non-trivial task.
Conclusion
I hope you now understand why HTML encoding does not mitigate XSS in every context and why we move those findings to XSS: Poor Validation, why SCA does not automatically try to identify encoding methods, and why we don’t try to determine the output context. As technologies change and improvements in the underlying platform occur, we will revisit these issues to hopefully come up with improved solutions. Until then, keep the faith and keep plugging away.







