Getting Started with Adobe After Effects - Part 6: Motion Blur


Upload Image Close it
Select File

Nakul Vachhrajani is a Technical Specialist & Systems development professional with iGATE. He holds a MCTS (SQL Server 2008: Implementation & Maintenance)
Browse by Tags · View All
#SQLServer 232
SQL Server 231
Administration 198
DBA 187
Tips 176
Development 176
T-SQL 171
#TSQL 169
Guidance 113
Tools and Utilities 112

Archive · View All
April 2011 14
March 2012 11
December 2011 11
March 2011 11
December 2012 10
October 2011 10
January 2011 10
January 2013 9
November 2012 9
October 2012 9

#0202-SQL Server-Replacing EXECUTE with sp_executesql does not protect against SQL injection

Oct 8 2012 12:00AM by Nakul Vachhrajani   

There are many dangers that come from incomplete knowledge, or for that matter, from the lack of experimenting something on your own. Implementing a solution without proper understanding and testing is a sin that most of us developers have committed at some point (knowingly, or unknowingly).

One such point is ensuring that a system is protected from SQL injection. As the name suggests, SQL injection refers to the ability of an external attacker to inject a rogue SQL command to the database (e.g. dumping the contents of the database to the user) within a seemingly legitimate request. Allow me to demonstrate what I mean by this.

(Please note that the intention of this post is to bust a myth around protecting against SQL injection and is not intended to be a complete guide against SQL injection).

[EDIT: 2012-10-08, 23:10 IST: The examples in this post are intentially over simplified for a clear understanding of the concept. The situation described in this post does not generally mandate the use of dynamic queries. END EDIT]

SQL Injection – A demo

Assume that my application provides functionality to search for contacts stored in the system based on the last name. This requirement is realized in code, by the following stored procedure:

USE AdventureWorks2012
GO

--Safety check
IF OBJECT_ID('proc_SearchPersonByLastName') IS NOT NULL
    DROP PROCEDURE dbo.proc_SearchPersonByLastName
GO

--Create Test Procedure, prone to injection
CREATE PROCEDURE dbo.proc_SearchPersonByLastName
    @filterString NVARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @sqlstring NVARCHAR(200);
    SET @sqlstring = 'SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName, EmailPromotion
                      FROM Person.Person 
                      WHERE LastName = ''';

    SET @sqlstring = @sqlstring + @filterString + '''';

    BEGIN TRY
        EXEC (@sqlstring);
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE(),
               ERROR_NUMBER(),
               ERROR_SEVERITY(),
               ERROR_STATE();
        --THROW is SQL 2012 specific!
        --If you are running SQL 2008, please replace it with RAISERROR
        --http://beyondrelational.com/modules/2/blogs/77/posts/11287/sunset-for-raiserror-and-sunrise-for-throw-sql-11-denali.aspx
        THROW;
    END CATCH
END
GO

What the stored procedure does is to append the filter criteria to the query and then uses EXEC or EXECUTE to execute the query. Here’s what can go wrong. Imagine that an attacker uses the following call:

--SQL Injection!
EXEC proc_SearchPersonByLastName 'Hill'' OR 1=1 OR 1=''%'
GO

The result? All contents of the table Person.Person are dumped out to the user because 1 will always be equal to 1 – something which the system is not supposed to do! This is a simple demonstration of a SQL injection attack. For more such examples, refer the links in the References section of this post.

Image showing that all records from Person.Person have been dumped to the user

(One of the) Solutions – the myth

The above is a classic example of SQL injection and one of the most common myths that surrounds SQL Injection is that it is due to the use of EXEC or EXECUTE. Some say – “simply replace EXEC with calls to sp_executesql and the system becomes SQL injection-proof”. This has to be the biggest misconception of all times around this subject.

Let’s simply replace EXEC with a call to sp_executesql and we see that SQL injection is still possible.

USE AdventureWorks2012
GO
--Alter Test Procedure, still prone to injection
ALTER PROCEDURE dbo.proc_SearchPersonByLastName
    @filterString NVARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @sqlstring NVARCHAR(200);
    SET @sqlstring = 'SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName, EmailPromotion
                      FROM Person.Person 
                      WHERE LastName = ''';

    SET @sqlstring = @sqlstring + @filterString + '''';

    BEGIN TRY
        --Notice that we now use sp_executesql here
        EXEC sp_executesql @sqlstring;
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE(),
               ERROR_NUMBER(),
               ERROR_SEVERITY(),
               ERROR_STATE();
        --THROW is SQL 2012 specific!
        --If you are running SQL 2008, please replace it with RAISERROR
        --http://beyondrelational.com/modules/2/blogs/77/posts/11287/sunset-for-raiserror-and-sunrise-for-throw-sql-11-denali.aspx
        THROW;
    END CATCH
END
GO

--Proof that injection is possible
EXEC proc_SearchPersonByLastName 'Hill'' OR 1=1 OR 1=''%'
GO

Simply replacing EXEC with sp_executesql does not prevent SQL injection

(One of the) Solutions – Parameterization

Using sp_executesql instead of EXEC is a partial solution. Using sp_executesql with parameters is the complete solution. Allow me to demonstrate. I have modified the stored procedure from above to use parameters:

USE AdventureWorks2012
GO
--Now, alter the SP to protect from injection
ALTER PROCEDURE dbo.proc_SearchPersonByLastName
    @filterString NVARCHAR(100)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @sqlstring NVARCHAR(200);
    DECLARE @params NVARCHAR(100);
    SET @sqlstring = 'SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName, EmailPromotion
                      FROM Person.Person 
                      WHERE LastName = @personLastName';
    SET @params = '@personLastName NVARCHAR(100)';

    BEGIN TRY
        EXEC sp_executesql @sqlstring, 
                           @params, 
                           @personLastName = @filterString;
    END TRY
    BEGIN CATCH
        SELECT ERROR_MESSAGE(),
               ERROR_NUMBER(),
               ERROR_SEVERITY(),
               ERROR_STATE();
        THROW;
    END CATCH
END
GO

What I have done is that I have explicitly specified that the query should expect a single parameter with a specific type – anything more is considered invalid and should not be processed. So, let me try it out:

USE AdventureWorks2012
GO
--Try injecting SQL code again - Won't Work!
EXEC proc_SearchPersonByLastName 'Hill'' OR 1=1 OR 1=''%'
GO

sp_executesql with parameters protects agaisnt SQL injection

This call did not work because the statement expects just one parameter and is instead getting a complete condition – which is incorrect. The following correct call however, works:

--Proper call - success
EXEC proc_SearchPersonByLastName 'Hill'
GO

sp_executesql with parameters protects agaisnt SQL injection

The conclusion that we can derive from this exercise is that to protect from SQL injection, one of the first things that need to be done is to use sp_executesql with parameterization. Simply replacing EXEC or EXECUTE calls with sp_executesql is not the solution.

References:

Until we meet next time,

Be courteous. Drive responsibly.

Tags: #SQLServer, SQL Server, Development, Administration, DBA, T-SQL, #TSQL, Guidance, Best Practices


Nakul Vachhrajani
4 · 33% · 10564
12
 
0
Lifesaver
 
 
0
Learned
 
0
Incorrect



Submit

4  Comments  

  • An even better solution: Don't put your query into strings to be executed later. Instead do this:

    USE AdventureWorks2012
    GO
    --Now, alter the SP to protect from injection
    ALTER PROCEDURE dbo.proc_SearchPersonByLastName
        @filterString NVARCHAR(100)
    AS
    BEGIN
        SET NOCOUNT ON;
    
        BEGIN TRY
    
           SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName, EmailPromotion
                          FROM Person.Person 
                          WHERE LastName = @personLastName
    
        END TRY
        BEGIN CATCH
            SELECT ERROR_MESSAGE(),
                   ERROR_NUMBER(),
                   ERROR_SEVERITY(),
                   ERROR_STATE();
            THROW;
        END CATCH
    END
    GO
    
    commented on Oct 8 2012 12:19AM
    Marc Jellinek
    97 · 2% · 545
  • You beat me to it, Marc. I can unserstand that sometimes Dynamic SQL must be used, but this isn't one of them.

    Still, hats off to Nakul for demonstrating that just changing EXEC to EXEC sp_executesql is not sufficient to prevent SQL Injection. He did say that this is "one of the solutions".

    commented on Oct 8 2012 12:10PM
    Jeff Moden
    165 · 1% · 291
  • Thank-you, Marc & Jeff for your feedback. Yes, I tried to make the concept simple enough for all to understand, but perhaps I over-simplified things a bit. A comment has now been introduced warning readers about this.

    Thank-you, Jeff for the encouraging words in recognizing my efforts to bring some awareness around the methods to prevent SQL injection.

    Once again, thank-you very much for taking the time out, reading my posts and sharing your thoughts about them!

    commented on Oct 8 2012 12:39PM
    Nakul Vachhrajani
    4 · 33% · 10564
  • Parameterization helps, but not all dynamic code can be parameterized. I find it's also important to mention QUOTENAME() for when it can't be - especially if it's the table names that are dynamic.

    commented on Oct 11 2012 8:05AM
    Ryan
    2891 · 0% · 2

Your Comment


Sign Up or Login to post a comment.

"#0202-SQL Server-Replacing EXECUTE with sp_executesql does not protect against SQL injection" rated 5 out of 5 by 12 readers
#0202-SQL Server-Replacing EXECUTE with sp_executesql does not protect against SQL injection , 5.0 out of 5 based on 12 ratings
    Copyright © Rivera Informatic Private Ltd Contact us      Privacy Policy      Terms of use      Report Abuse      Advertising      [ZULU1097]