Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I have a text field that allows the user to type whatever he/she wants. After saving, the results are later displayed on the screen to potentially many people.

XSS seems a bit like black magic to me, so I am wondering what the current best practices are for handling this situation (from specific ways to sanitize input to specific ways to encode html to display)?

share|improve this question

4 Answers 4

up vote 6 down vote accepted

Escape quotes, filter out the word javascript, restrict the allowed letters, etc.

You might want to just read through the OWASP guidelines on XSS.

This additional page at OWASP should be useful to, it deals with the encoding issues in our discussions below.

share|improve this answer
    
The OWASP XSS Prevention cheat sheet and OWASP Abridged XSS prevention cheat sheet are probably worth mentioning: owasp.org/index.php/… owasp.org/index.php/Abridged_XSS_Prevention_Cheat_Sheet –  Erlend Sep 1 '12 at 6:36

Compose your HTML using an auto-escaping template language that, by default, escapes untrusted inputs for you.

For example, Django templates escape HTML special characters:

Clearly, user-submitted data shouldn't be trusted blindly and inserted directly into your Web pages, because a malicious user could use this kind of hole to do potentially bad things. This type of security exploit is called a Cross Site Scripting (XSS) attack.

To avoid this problem, you have two options:

  1. You can make sure to run each untrusted variable through the escape filter, which converts potentially harmful HTML characters to unharmful ones. This was the default solution in Django for its first few years, but the problem is that it puts the onus on you, the developer / template author, to ensure you're escaping everything. It's easy to forget to escape data.
  2. You can take advantage of Django's automatic HTML escaping. The remainder of this section describes how auto-escaping works. By default in Django, every template automatically escapes the output of every variable tag.

There are also a variety of contextual auto-escaped templates which are a bit smarter, and can prevent XSS even when your templates contain embedded JavaScript, CSS, and URLs.

Closure templates says:

Contextual autoescaping works by augmenting Closure Templates to properly encode each dynamic value based on the context in which it appears, thus defending against XSS vulnerabilities in values that are controlled by an attacker.

Go's template language uses contextual autoescaping:

HTML templates treat data values as plain text which should be encoded so they can be safely embedded in an HTML document. The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.

share|improve this answer
1  
Exactly, use appropriate encoding at the use site, when you know the context instead of trying to sanitize inputs. Automatic encoding is even nicer, though you need to be aware of the details of how their context detection works, so you know in which cases it'll misdetect the context. –  CodesInChaos Sep 1 '12 at 0:08
    
@CodesInChaos, I've spent the last year looking for context detection schemes that match template authors' expectations. Code injection isn't going to disappear overnight, but the next generation of tools will be much more robust. –  Mike Samuel Sep 1 '12 at 2:50

I have a text field that allows the user to type whatever he/she wants. After saving, the results are later displayed on the screen to potentially many people.

That's the problem. Do NOT trust user's input... To avoid XSS you must sanitize the user's input before storing it in the DB.

Some things you should check:

  • Do not allow HTML tags. Once you have all the tags forbidden, then you could allow some of them (like this site) like <hr> <b> etc. Or creating your own tag system, [img] [b]...

  • Do not allow " or ', replace them by their HTML code &quot; and &#39;

  • If you are planning to allow hyperlinks, be sure that the url are valid. In other words, they must start with http:// or https://

Probably, the language on which you are developping the application has functions to check most of the previous points (at least, checking quotes and HTML tags).

share|improve this answer
3  
I disagree. I see no reason to sanitize the input from a text field if there are no specific constraints (e.g. should be an email). The clean solution is to encode the output. And the encoding should happen when outputting, and not when storing. –  CodesInChaos Aug 31 '12 at 12:43
1  
Perhaps I am not interpreting your response correctly, but if you don't filter on the way in, you run the risk of an (SQL, XML, etc.) injection attack. I am not sure why you would ever have a input from a user that has no constraints. If you have a form asking for something, its usually something specific - it may be broad (e.g., tell me your life story), but it should not include scripts, injection, etc. Your comments also suggests its okay to echo the encoded attempted attack back to the screen, which would at the least look bad and confuse other visitors. –  Eric G Aug 31 '12 at 14:35
    
@EricG You're typing this on a programmers website. We discuss programs, and parts of programs. Which include SQL, XML, HTML, JS, whatever the "user" likes. And it's just as common for these discussions to take place on general purpose blogs, forums, email etc. As to how you decide whether something includes "injection" - ! –  sourcejedi Aug 31 '12 at 21:49
    
sourcejedi, I am not sure I understand your comment, CodeChaos was implying you do not need to filter on the way to storage. That is the exact reason a SQL injection attack will occur, if you don't filter input into storage. I belive this is actually a security site.. nonetheless, programmers need to abide by business requirements and if the business says i want a form for my end-users to submit "their life story" it should include "their life story" and not htmlencoded evidence that someone tried to do SQL injection or XSS, that would be poor presentation. –  Eric G Aug 31 '12 at 22:47
2  
What the user enters is only text. It only becomes something different when you treat it differently. For example when you insert it into html, you must html encode. When you send it to a raw sql query(I'd avoid that in the first place) then sql-escape it. But you only know what encodings when you know the context in which it will be used. For example in a forum software I wouldn't apply any sanitization to user posts, the only thing I'd do is a html encode directly before outputting it. And even then, I'd prefer a template language that takes care of that automatically. –  CodesInChaos Sep 1 '12 at 0:06

The single best practice: strictly control type and sanitize your data.

Always use proper method to output data according to type: never render what was entered as text in HTML (i.e. assign user-entered text data to text node's .data property in DOM, not to magical .innerHTML). Never use input in eval-like construction or as substring of database query - proper tools would be expression parser and placeholders respectively.

Reject or clean-up everything coming to your program from external sources (including your very own internal databases, that could be compromised too!) to strict set of allowed patterns.

Use established and proven protocols and serializers to transport data, preferably one that have native implementation on both sending and receiving end (JSON serializer, protobuf, Storable in Perl, etc.) instead of homemade quoting.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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