Validating user input is really not complex at all. If you need to build and execute ad hoc queries you just need to remember two things.

With strings, always replace ticks/single-quotes (') with two ticks/single-quotes ('') <- notice there are two characters there and not a double-quote ("). If you do this then the user entry for that field will be accepted in its entirety and any SQL commands in the string, including comment markers.

The resulting SQL statement is this:select userid from users where userid = 'bogus' and password = '''; delete from users'

One other thing with strings. This is not so much a protection from SQL injection but will help keep errors from cropping up that could expose connection information in the form of an error response. Make sure you are limiting the size of strings in the UI to prevent people from entering text too large for the database to handle. If you are developing n-tier applications, you business layer should not trust the UI and double check the data.

For all non-string data you should use the appropriate means to determine if the input is valid for the data type that is to receive the input. If the field is an integer, check to see that the user entered an integer; same with dates, etc. Also don't assume that client-side form validation in web applications will catch this. Always check on the server-side because there is no guarantee that the user is using the form you created!

In my own defense, I did say "If you need to build and execute ad hoc queries" but maybe I did not stress the need enough. There are occasions where an application needs to throw together a query based on user input.

Stored procedures are the obvious choice for security and performance and should be used whenever possible. If you look around there are some tricks for handling situations where the obvious option is to use ad hoc queries (Particularly with WHERE clauses) but you really can use stored procedures with a little thought. If you want to get fancier, look into code generation (http://www.codegeneration.net/ and my favorite http://www.ericjsmith.com/codesmith). If you find yourself using the same patterns repeatedly, write a script or other tool to reproduce the code that results from the pattern and save yourself time down the road.

No harm, no foul. The comment was not really directed at anyone, I just wanted to introduce the concept of using stored procedures to short circuit injection attacks.

IMHO there is never a good reason to use dynamic sql, either as a command or wrapped in a stored procedure. Just create as many stored procedures as you need to handle the different scenarios, and call them appropriately.

Whenever I bring this approach up, development time up front seems to be the biggest pushback. But using this approach not only provides the security and performance benefits you mentioned, but also abstracts the internals of the db layer from the application/business layer. It also makes modifying application code as easy as calling a new sproc, instead of the nightmare of trying to maintain 300 lines of stored procedure code.

No harm, no foul. The comment was not really directed at anyone, I just wanted to introduce the concept of using stored procedures to short circuit injection attacks.

IMHO there is never a good reason to use dynamic sql, either as a command or wrapped in a stored procedure. Just create as many stored procedures as you need to handle the different scenarios, and call them appropriately.

Whenever I bring this approach up, development time up front seems to be the biggest pushback. But using this approach not only provides the security and performance benefits you mentioned, but also abstracts the internals of the db layer from the application/business layer. It also makes modifying application code as easy as calling a new sproc, instead of the nightmare of trying to maintain 300 lines of stored procedure code.

good comments and a great article. One other thing that I think should be mentioned first is that the user account should not be SA, but rather a limited rights account. To me that's the first step before attempting to limit injection attacks.