Subscribe to Windows IT Pro

 

Get Newsletters

  • Get the Latest News
  • Product Updates
  • Helpful Tricks
  • Productivity Tips

Subscribe Now!

April 06, 2004 12:00 AM

Protecting Against SQL Injection

SQL Server Pro
InstantDoc ID #42216
Rating: (1)

Congratulations to Zsolt Peter, a developer for Cosys Ltd. in St. George, Romania, and Kristofer Andersson, a senior software developer for RR Technologies in Fort Lauderdale, Florida. Zsolt won first prize of $100 for the best solution to the April Reader Challenge, "Protecting Against SQL Injection." Kristofer won second prize of $50. Here’s a recap of the problem and the solution to the April Reader Challenge.

Problem:
Jeff is a database architect, responsible for designing and developing database solutions using SQL Server 2000. Jeff's main concern when performing code reviews is the use of dynamic SQL in stored procedures that his Web application uses for search purposes. He's worried that the dynamic SQL will put his system at risk for SQL injection attacks, in which an attacker compromises the system's security by executing unauthorized code.

The following example uses the sample Northwind database objects to show how a user exploits the dynamic SQL in a stored procedure. The Web page in this example lets the user specify searches for customers or suppliers based on relationship, city, company, or contact name. The Web page executes the following stored procedure, SearchCustomersAndSuppliers:

CREATE PROCEDURE SearchCustomersAndSuppliers
(@Relationship varchar(9) = NULL
,@City nvarchar(30) = NULL
,@CompanyName nvarchar(80) = NULL
,@ContactName nvarchar(60) = NULL
,@Debug bit = 0)
AS
BEGIN
  DECLARE @SQL nvarchar(4000), @WhereClause nvarchar(500)
  SET @SQL = N'SELECT City, CompanyName, ContactName, 
    Relationship FROM "Customer AND Suppliers BY City"'
  SET @WhereClause = N' WHERE 1=1'
  IF @Relationship IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND Relationship = 
      ''' + @Relationship + ''''
  IF @City IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND City LIKE N''' 
      + @City + ''''
  IF @CompanyName IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND CompanyName LIKE N''' 
      + @CompanyName + ''''
  IF @ContactName IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND ContactName LIKE N''' 
      + @ContactName + ''''
  IF @Debug = 1
    PRINT @SQL
  IF @Debug = 1
    PRINT @WhereClause
  EXEC(@SQL + @WhereClause)
END
GO

The parameters for city, company, and contact name let users conduct wildcard searches by using LIKE patterns, meaning they can search for words "like" cty and still get city. The @Relationship parameter limits the search to a specific value.

Using the SearchCustomersAndSuppliers stored procedure, Jeff issues the following command to return the generated queries and a list of customers from the Customers table, which demonstrates the security danger of forming dynamic SQL without specific checks:

  EXEC SearchCustomersAndSuppliers
    @CompanyName = N'%'';SELECT * FROM customers;PRINT ''',
    @Debug = 1

By injecting SQL code into the search parameters, an attacker can potentially perform unauthorized actions depending on the permissions of the user account, the Web page, or application executing the stored procedure.

Help Jeff write the dynamic SQL to prevent SQL injection attacks. Ultimately, he wants to suggest to the developers a more secure dynamic SQL approach as a standard technique for stored procedures that require dynamic SQL.

Solution:
To execute the dynamically generated SQL statement in the SearchCustomersandSuppliers stored procedure, Jeff uses the sp_executesql system stored procedure, which modifies the original stored procedure, but retains the dynamic SQL and search capabilities. Sp_executesql is more powerful than the EXEC statement that dynamically executes an arbitrary string that can be reused multiple times or have embedded parameters. Additionally, the parameter values that Jeff uses with sp_executesql can be either variables or literal values. With the sp_executesql stored procedure, Jeff stops the parameter values from being used to directly form the SQL statement. Here is the new stored procedure, SearchCustomersAndSuppliers_1:

CREATE PROCEDURE SearchCustomersAndSuppliers_1
(@Relationship varchar(9) = NULL
,@City nvarchar(30) = NULL
,@CompanyName nvarchar(80) = NULL
,@ContactName nvarchar(60) = NULL
,@Debug bit = 0)
AS
BEGIN
  DECLARE @SQL nvarchar(4000), @WhereClause nvarchar(500)
  SET @SQL = N'SELECT City, CompanyName, ContactName, 
    Relationship FROM "Customer AND Suppliers BY City"'
  SET @WhereClause = N' WHERE 1=1'
  IF @Relationship IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND RelationShip = 
      @Relationship$'
  IF @City IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND City LIKE @City$'
  IF @CompanyName IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND CompanyName LIKE 
      @CompanyName$'
  IF @ContactName IS NOT NULL
    SET @WhereClause = @WhereClause + ' AND ContactName LIKE 
      @ContactName$'
  SET @SQL = @SQL + @WhereClause
  IF @Debug = 1
    PRINT @SQL
  EXEC sp_executesql
    @SQL,
    N'@RelationShip$ varchar(9), @City$ nvarchar(30), 
      @CompanyName$ nvarchar(80), @ContactName$ nvarchar(60)',
    @RelationShip$ = @RelationShip,
    @City$ = @City,
    @CompanyName$ = @CompanyName,
    @ContactName$ = @ContactName
END
GO

Jeff retains most of the code that performs the checks for the input parameters, but the WHERE clause generation statement now uses placeholder variables instead of search values. SQL Server passes the variable values to the sp_exceutesql call. The dynamic SQL statement that searches only by company name looks like:

SELECT City, CompanyName, ContactName, Relationship
 FROM "Customer AND Suppliers BY City"
 WHERE 1=1 AND CompanyName LIKE @CompanyName_

The sp_executesql call passes the value for the @CompanyName variable (which is the stored procedure input parameter) at the time of execution. Now if Jeff executes the statement that lets him read the Customers table, the statement won’t return any results because the input value is considered as a CompanyName column value, which prevents the injection of SQL code by intruders. To see Jeff’s new dynamic SQL stored procedure in action, execute the following statement:

EXEC SearchCustomersAndSuppliers_1
  @CompanyName = N'%'';SELECT * FROM customers;PRINT ''',
  @Debug = 1

Note that because the search that contains the injected SQL statement is treated as a string value by the sq_executesql call, the new stored procedure doesn’t return the same rows as the original. If you run both the stored procedures with valid search strings, you’ll get the same results.

Related Content:

ARTICLE TOOLS

Comments
    There are no comments to display. Be the first one!
You must log on before posting a comment.

Are you a new visitor? Register Here

advertisement

advertisement

White Papers

Get your Windows 7 deployment off to the right start by implementing PC lockdown. A locked-down environment is easier and cheaper to support since users are less likely to make unnecessary changes to the core system configuration - read more here!

Essential Guides

Is your iSCSI "lossy"? The reality is that most off-the-shelf Ethernet hardware deployed for iSCSI can lose packets, resulting in slow performance or application downtime. Learn how to assess your current iSCSI infrastructure and engineer an advanced iSCSI SAN infrastructure.

Web Seminars

What's the best way to keep your network safe from malware? In this web seminar, security expert Greg Shields suggests an alternative method to the traditional blacklisting approach that is common with anti-virus and anti-malware solutions.

eLearning Series

We bring the experts direct to you to share their real-world perspective and expertise. During each event, three sessions stream in real time, so you can learn, ask questions, and get solutions.
Upcoming event: Getting the Most with Exchange 2010 with Paul Robichaux

Subscribe to Windows IT Pro!

Windows is a trademark of the Microsoft group of companies. Windows IT Pro is used by Penton Media Inc. under license from owner.