8

Is it sufficient to convert ' to &#039; , > to &gt; and < to &lt; to avoid XSS when inserting untrusted data into a JavaScript string as below?

<script>
param='payload';
</script>

Are there any examples of situations where the above conversion is not sufficient to avoid XSS?

  • 3
    Why would filtering a single character fix XSS? What about param='</script><script>alert(1)//' – rook Nov 27 '14 at 15:47
  • Or, if more than one field is filled out, a simple backslash in the first and ;alert(1)// in the second. – Polynomial Nov 27 '14 at 16:19
9

Don't rely on using your own "conversion" rules, OWASP recommends using a security-focused encoding library to make sure the necessary rules are properly implemented:

Escape the following characters with HTML entity encoding to prevent switching into any execution context, such as script, style, or event handlers. In addition to the 5 characters significant in XML (&, <, >, ", '), the forward slash is included as it helps to end an HTML entity.

HTML entity encoding is okay for untrusted data that you put in the body of the HTML document, such as inside a <div> tag. However, it would not be sufficient in a number of cases, such as "nested contexts":

<script>...param used directly here...</script>
<!--...param used inside an HTML comment...-->
<div ...param used in an attribute name=test />
<param as a tag name href="/test" />
<style>...param used directly in CSS...</style>

In general, never use param inside any of these nested entities, even if HTML entity encoded.

  • i agree that we should use security focused libary but i was looking for a specific example for the mentioned context. any ideas?? – Sanchit Sharma Nov 27 '14 at 15:44
  • 3
    @Milen Your posts need to contain citation. Link to the OWASP XSS filter evasion cheat sheet, or XSS prevention cheat sheet. – rook Nov 27 '14 at 15:50
  • @Rook sorry, you're absolutely correct, I should've added the source. – Milen Nov 27 '14 at 19:23
5

It isn’t sufficient, no. Contrived backslash example:

<script>
var param1 = '{{ param1 }}'; var param2 = '{{ param2 }}';
</script>
param1=\&param2=;alert(1)//
<script>
var param1 = '\'; var param2 = ';alert(1)//';
</script>

Not to mention that your data won’t survive intact:

<script>
var param1 = '&lt;';
alert(param1); // Shows up as &lt;, not <
</script>

Newlines (\r, \n, \u2028, \u2029) can also break a JavaScript string, though it’s probably rare for that to create a vulnerability, since it’s invariably a syntax error. If you absolutely need to put user input in a variable in an inline <script> inline, I would recommend JSON-encoding followed by a replacement of </ with <\/ and <! with <\!. The best way, though, is to use reliable HTML encoding outside of the script:

<div id="my-information" data-something="{{ param1 }}"></div>

<script>
var param1 = document.getElementById('my-information').getAttribute('data-something');
</script>

Not having dynamic scripts lets you implement strong CSPs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.