In the bits that I've searched about this, I've seen a few people declare as word-of-god that you should only sanitize outputs and not inputs. Why? Would it not be safer to cover both ends?
When you sanitize input, you risk altering the data in ways that might make it unusable. So input sanitization is avoided in cases where the nature of the data is unknown. For instance, perhaps some special characters hold significance in the data and stripping them means destroying that significance.
A scenario like this may be that your system stores data that may later be pulled out into a third party system, and in that system those characters hold meaning. By stripping them you've altered the data in a significant way. For instance, perhaps the string is used as a key to look up a record in the third party system and by stripping the symbol you alter the key such that the record cannot be found.
Input sanitization can be used when that nature of the data is known and sanitization would not adversely affect the data in anyway.
Your decision to sanitize input data is in part a business decision. Will third party system depend on input exactly as it is provided? If so, it's probably not a good idea. However, you may be able to shape expectations such that the third parties understand that you will be sanitizing input data based on a specified criteria that you share with them.
By the way "You can never in retrospect go through the database and see how many of the posts were malicious." is simply not true. There are scrubbers available to go through a database and "scrub it" of malicious code. I know, I did it last year for a major financial services company.
You don't know how to sanitise data until you output it, or more precisely use it.
In many cases it might seem obvious; in your blogging engine you want to filter out script-tags; always and ever so you simply delete them from the input and never think of them again.
In other cases it might not be so easy; if the same data is used in different contexts. "<" needs to be escaped to "<"in html and is completely harmless if exported as text.
But even if it is simple, by removing <script> from your input you lose important data. You can never in retrospect go through the database and see how many of the posts were malicious.
Then comes the possibility of moving goal posts: someone finds a new exploit that your filter doesn't deal with. Suddenly you must reapply a fixed filter on your entire database. What if there is a false positive bug in your fix?
But even if you are absolutely certain that the posted data is completely free of xss, viruses et cetera, it is completely safe to show in a browser; you cant just shove it in your database willy nilly. That's how SQL-injections are born.
The bottom line is that until you use the data, you cannot know what "bad" data looks like, and every time you use the data you must sanitize it.
Trying to fix the data in advance is like darning socks before there is a hole in them.
It is a risk to have XSS content in your database. Databases are meant to be shared by applications, and are long-lived compared to web front-ends.
Example: The new intern starts working on a new web app for the db, shows his boss, and bam, his login cookie is in St. Petersburg.
You don't want to alter user input, you want to validate user input and reject it if it contains possible XSS. This is pretty easy and fast with a proper HTML parser like JSoup. It's built-in to Hibernate Validator.
I'm not saying you shouldn't escape user input on output. With the number of XSS issues, it's obviously easy to miss a few though.
I would recomend validating the imput and sanitizing the output. That way you can ensure that valid data are being stored on the database and harmless data is consumed on the users' end.
If a field expects a date, make sure you are receiving a date. You can easily validate dates, numbers, emails, ZIP codes, phone numbers, and a lot of fields. So do it.
Sanitize before storing the data - you don't want to be hit by a SQL injection. Use prepared statements if possible, and escape every control char if not possible.
On the output side, encode the data as to be harmless on the backend format. If outputting HTML, escape all special HTML chars. If outputting json or XML, do the encoding accordingly.
As others said, filtering and encoding the data on the input size will destroy the data, and can delete part of data that would be harmless on some contexts, or keep hazardous data. Validating the input and encoding the output would be the best approach.