4

Would it not be possible to use such a method to wrap areas where user input/output is expected (eg. comment boxes), so that even if a script is successfully injected through regex evasion, the script will not run since it falls within a certain HTML wrapper set up to disable all scripts within it?

4

Problems with your approach

No, this wouldn't work. The problems are:

  • An attacker can still inject tags. They can inject </disablescripts> to inject scripts and thus gain XSS.
  • It affects usability. What if I want to leave a comment that is: You can use </disablescripts> to exit the new HTML6 feature. After that, anything in <script>alert(1)</script> will be executed. That comment would not display correctly.
  • XSS is dangerous, but you shouldn't underestimate HTML injection, which would still be possible with your approach and allows to change the look and functionality of a website, which may be used for phishing attacks, defacement, and possibly even privilege escalation.

And that's not even considering the practicality of it. The problem with XSS is that developers often don't know where user input is expected. If they knew, they would HTML encode it already. But for some reason, they lost sight of what is user input and what isn't.

The same problem exists with your proposed idea: How does a developer know what areas likely contain JavaScript? Even if it was working, your approach would at best be a second line of defense, in addition to the proper solutions to XSS.

Better approaches to XSS

Better approaches are:

  • HTML encoding in HTML contexts, escaping in JavaScript contexts
  • Using something like HTMLPurifier if a limited subset of HTML is required
  • Use some templating engine or other mechanism that allows the automatic encoding of all variables (to ensure that none are forgot).
  • If you do not have inline JavaScript, use a content security policy such as script-src self https://cdn1.com. Only modern browsers will follow it, but they will not execute any injected inline scripts, and will only load external scripts from allowed sites.
0

There is a perfectly good way to stop cross site scripting attacks. Content-sensitive escaping; e.g., if user-generated content is inserted as content in an HTML document then HTML-escape &<>"'/ (potentially allow a a small-whitelist of allowed tags like <b> or escape everything and use a safe markdown-like language to allow a few tags), if user-generated content is inserted into javascript, then javascript escape it, etc. (See OWASP for more details.)

This attack would badly fail when someone attempts to use it to prevent attacks on dynamically generated webpages.

Imagine you have a webpage that reads your comment from a database and puts that comment into an HTML page that is served to the user.

You write your HTML page as such:

<disablescripts>
   {{ untrusted_user_content_read_from_db }}
</disablescripts>

Well when {{untrusted_user_content_read_from_db}} is set to the value:

</disablescripts><script>alert("XSS -- gotcha!");</script><disablescripts>

then this prevention method fails as the webserver just sent over the html webpage to your browser as:

<disablescripts>
</disablescripts><script>alert("XSS -- gotcha!");</script><disablescripts>
</disablescripts>
3
  • Would one be able to get around this vulnerability if they were to add single character tag? eg <☢></☢>, would a filter not be able to remove all "☢" characters from a user's input, rendering any </☢> inserted by a user as useless?
    – Jay
    Feb 25 '16 at 7:19
  • @Jay - Sure could work. But then you have to deal with potential unicode encoding issues (UTF8 vs UCS2 vs UTF7) of ☢ (again these should be sorted out, but its not guaranteed) at the user-input filtering level and browser level (in every browser some with users changing encoding manually). It's simpler to keep to the status quo of HTML-escaping <, >, etc. to &lt; and &gt;. Furthermore, introducing a new tag method won't be backward compatible. If HTML6 came out with this tag, anyone using an old browser that doesn't recognize <☢></☢> would be vulnerable to XSS in the transition.
    – dr jimbob
    Feb 25 '16 at 20:49
  • Similarly if you only disallowed <script> tags and javascript functions (e.g., onclick attribute), there's still plenty of potential malicious things you could do within the <disablescripts>. E.g., introduce a </body></html><!-- that prevents the rest of the page from rendering. Introduce an <iframe> with style set to cover the content of the rest of the page to replace it with one the attacker controls, etc. If you can introduce content on a page with secrets in the URL, insert a hidden image to domain you control to see the secret in the URL in the HTTP Referer header, etc.
    – dr jimbob
    Feb 25 '16 at 20:58
0

This is pretty much what a content security policy does.

Via an HTTP header, the website author can disable inline scripts from being executed, and "lock down" the remote domains that script tag can load their source from (<script src="").

e.g.

Content-Security-Policy: script-src 'self' https://apis.google.com

The advantage of this over your suggested method is that it is set in an HTTP header where it can't be unset by subsequent page content. In your example an attacker could simply include </disablescripts> at the start of their payload to get round it.

-1

Some website owners have tried to prevent XSS with the <noscript> HTML tag. The problem is, if you don't properly output encode, you can just break out of the <noscript> tag and get XSS anyway. The right thing to do is to a) validate input (eg a number is a number) and b) output encode.

10
  • 2
    <noscript> displays special content when javascript (or scripting language inside instead of usual text/javascript in <script type="text/javascript">) is turned off or not supported by the browser. It has nothing to do with stopping XSS. Maybe there was a draft proposal for <noscript> to work differently at some point, but the html element that exists works in this way: developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript
    – dr jimbob
    Feb 25 '16 at 6:48
  • Fair enough. What I intended to say was that some website authors have tried to use it to prevent XSS by wrapping user output in <noscript>. And sadly I've seen more than one well-known website do this. I've hopefully clarified by editing my answer.
    – h4ckNinja
    Feb 25 '16 at 6:51
  • @Micheal However, that is expected not to work, since that is not what the <noscript> tag is intended for. So would an actual script disabling wrapper be a good solution to eliminate scripts that manage to get injected by evading sanitation? The way I see things, both sanitation and outputting encoded characters is something that can be evaded. See: owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet as well as shawarkhan.com/bypassing-htmlspecialchars-and-executing-xss
    – Jay
    Feb 25 '16 at 7:00
  • @Jay Okay, let's see if I can answer this in 500 characters. Some websites, contrary to the right way, attempted to use <noscript>. The <noscript> tag does not execute JavaScript inside of it. However, If you have the following <noscript>[user input]</noscript>, an attack can input </noscript><script>...</script> and execute JavaScript anyway. And I have done this against sites that used the <noscript> tag, again, against the advice of proper output encoding.
    – h4ckNinja
    Feb 25 '16 at 7:04
  • 1
    @Jay Filtering is a bad idea. Here's why. You have UTF8, UTF16, and overlong encodings. And that's just off the top of my head. The right way is output encoding.
    – h4ckNinja
    Feb 25 '16 at 7:24

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.