Please, please, please, learn about injection attacks!
SqlCommand cmd = new SqlCommand(
"SELECT ID, FullName FROM User WHERE Login='"
+ Login.Text
+ "' AND Password='"
+ Password.Text
+ "'");
"SELECT FullName FROM User WHERE ID=" + Identity.Text
SqlCommand cmd = new SqlCommand("SELECT ID, FullName FROM User WHERE Login=@Login
AND Password=@Password");
cmd.Parameters.Add("@Login", SqlDbType.NVarChar, 50).Value = Login.Text;
cmd.Parameters.Add("@Password", SqlDbType.NVarChar, 50).Value = Password.Text;
SqlCommand cmd = new SqlCommand("SELECT FullName FROM User WHERE ID=@ID");
cmd.Parameters.Add("@ID", SqlDbType.Int).Value = int.Parse(Identity.Text);
SqlCommand cmd = new SqlCommand("SELECT FullName FROM User WHERE ID
IN(@IdArray)");
cmd.Parameters.Add("@IdArray", SqlDbType.IntArray).Value = Convert.ChangeType(Request.Form["Identities"], typeof(int[]));
string idList = Request.Form["Identities"];
if (IntListValidate(idList)) {
SqlCommand cmd = new SqlCommand("SELECT FullName FROM User WHERE ID IN(" + idList + ")");
}
else {
throw new InvalidDataException("The posted data contains illegal characters.");
}
...
private bool IntListValidate(string input) {
for (int i = 0; i < input.Length; i++) {
if (!Char.IsDigit(input, i) && input[i] != ',') return false;
}
return true;
}
Of course, here, you have to use a white list, digits and comma in this case. Not even space is allowed. That's pretty safe, but I wish you could do that with parameters.
Update 8/19/2004:
Kyle Heon just pointed me to
this great Sql article that explains just how to do that with a parameter.
Thanks for the link, Kyle! So now, there's one less reason
not to use parameters everywhere.
http://msdn.microsoft.com/en-us/library/aa496058.aspx
The second common type of injection attack is Cross-Site Scripting, or X-Site Scripting. Consider this simple piece of asp page:
Bonjour, <%= Request.Form("Name") %>.
What if the user enters <script>alert("5tUp1dH4k3R ownz you");</script> in the Name form field? Well, he successfully displayed an alert on his browser using your page. Nothing to be afraid about for the moment, as he'll be the only one to see it. But what if instead of directly displaying the user input we store it in a database for other users to see, in a forum application, for example? What if the parameter is passed in the querystring parameters of a hyperlink in a mail that seems to come from your bank?
Well, then a lot of nasty things can happen (by the way, these are real scenarios, stuff that happened and continues to happen every day). For example, the attacker can inject script that will post all your cookies or some confidential information that's displayed on the page to some remote site that he owns. This can include your social security number, your authentication cookies, your credit card number, or any sensitive information that may be displayed on the page.
It is usually relatively harmless for many sites because they just don't have any information that's confidential or that could allow for other, more dangerous attacks.
Once again, ASP.NET gives a first line of defense out of the box. Since v1.1, all form and querystring data is validated on the server before the page is executed. So the above example does not work on ASP.NET 1.1, it will just throw an exception. Now, this feature is sometimes deactivated by controls such as rich text editors.
The second thing we're doing, which is what you should do in your own pages and controls, is to HtmlEncode any property that comes from user input. That includes the value of an input tag that's rendered from a TextBox. It protects this particular textbox from script injections and also makes it robust against legitimate characters in the contents, such as quotes.
Rule #5: Encode all rendered properties that come from user input when rendering them.
The above example would then become:
Bonjour, <%= Server.HtmlEncode(Request.Form("Name")) %>.
There's another often overlooked rule:
Rule #6: Don't display any secrets in error messages.
ASP.NET limits by default the complete error messages to calls from the local machine. A complete error message sent to any machine can reveal table names or other secrets that could give clues for some attacker to use. And usually, an error message gives an indication as to how to make this application fail, which can be repeated and improved on the basis of all the information the error message contains.
And of course, probably the most important rule:
Rule #7: Encrypt any page that contains sensitive data.
Of course, these rules are all important and the order in which they are presented here is irrelevant. Did I forget something?
If you need more information, here's some more reading:
On Sql Injections: http://www.governmentsecurity.org/articles/SQLInjectionModesofAttackDefenceandWhyItMatters.php
On Cross-Site Scripting: http://www.net-security.org/dl/articles/xss_anatomy.pdf
And of course, Google is your friend.
UPDATE: I've used the word "quote" in this article for both the apostrophe (or single quote) and double quote. Todd pointed out in the comments that was somehow ambiguous. The point is that anything that can be used as a string delimiter, or as a delimiter in general, should be considered suspicious. Double-quotes are more frequent, but some languages such as JavaScript use both single and double quotes. SQL uses single quotes. Bottom line: beware of delimiters, and remember you may not even know the list of possible delimiters.
UPDATE: we just released new tools that
aim at helping developers scan their code for potential
injection attacks.
http://www.microsoft.com/technet/security/advisory/954462.mspx