Do stored procedures prevent SQL injection?

No, stored procedures do not prevent SQL injection. Here's an actual example (from an in-house app someone created where I work) of a stored procedure that unfortunately permits SQL injection:

This sql server code:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

roughly equivalent to postgres:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

The developer's idea was to create a versatile search procedure, but the result is that the WHERE clause can contain anything the user wants, allowing a visit from little Bobby Tables.

Whether you use SQL statements or stored procedure doesn't matter. What matters is whether your SQL uses parameters or concatenated strings. Parameters prevent SQL injection; concatenated strings allow SQL injection.


SQL-Injection attacks are those where untrusted input is directly appended queries, allowing the user to effectively execute arbitrary code, as illustrated in this canonical XKCD comic.

Thus, we get the situation:

userInput = getFromHTML # "Robert ') Drop table students; --"

Query = "Select * from students where studentName = " + userInput

Stored Procedures are, in general, good defenses against SQL injection attacks because the incoming parameters are never parsed.

In a stored procedure, in most DBs (and programs, don't forget that precompiled queries count as stored procedures) look like the following:

 

create Stored procdure foo (
select * from students where studentName = :1
);

Then, when the program desires access, it calls foo(userInput) and happily retrieves the result.

A stored procedure is not a magical defense against SQL-Injection, as people are quite able to write bad stored procedures. However, pre-compiled queries, be they stored in the database or in the program, are much more difficult to open security holes in if you understand how SQL-Injection works.

You can read more about SQL-Injection:

  • In this discussion by Jeff Atwood
  • Prevention cheat sheet
  • How to attack your own code (Make sure your QA includes security testing. If it doesn't, your site will be security tested by the outside. This is a Bad Thing.)

Yes, to some extent.
Stored Procedures alone will not prevent SQL Injection.

Let me first quote about SQL Injection from OWASP

A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data (Insert/Update/Delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some cases issue commands to the operating system. SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to effect the execution of predefined SQL commands.

You have to sanitize user inputs and do not concatenate SQL statements, even if you are using stored procedure.

Jeff Attwood explained consequences of concatenating sql in "Give me parameterized SQL, or give me death"

Following is the interesting cartoon which comes to my mind whenever I hear SQL Injection alt text I think you got the point :-)

Have a look at SQL Injection Prevention Cheat Sheet, prevention methods are neatly explained...