Short and Sweaty
If you have stored procedures that do things like this:
IF @OwnerUserId IS NOT NULL SET @Filter = @Filter + N' AND p.OwnerUserId = ' + RTRIM(@OwnerUserId) + @nl; IF @CreationDate IS NOT NULL SET @Filter = @Filter + N' AND p.CreationDate >= ''' + RTRIM(@CreationDate) + '''' + @nl; IF @LastActivityDate IS NOT NULL SET @Filter = @Filter + N' AND p.LastActivityDate < ''' + RTRIM(@LastActivityDate) + '''' + @nl; IF @Title IS NOT NULL SET @Filter = @Filter + N' AND p.Title LIKE ''' + N'%' + @Title + N'%''' + @nl; IF @Body IS NOT NULL SET @Filter = @Filter + N' AND p.Body LIKE ''' + N'%' + @Body + N'%'';'; IF @Filter IS NOT NULL SET @SQLString += @Filter; PRINT @SQLString EXEC (@SQLString);
Or even application code that builds unparameterized strings, you’ve probably already had someone steal all your company data.
Way to go.
But Seriously
I was asked recently if the forced parameterization setting could prevent SQL injection attacks.
Let’s see what happens! I’m using code from my example here.
EXEC dbo.AwesomeSearchProcedure @OwnerUserId = 35004, @Title = NULL, @CreationDate = NULL, @LastActivityDate = NULL, @Body = N''' UNION ALL SELECT t.object_id, t.name, NULL, NULL, SCHEMA_NAME(t.schema_id) FROM sys.tables AS t; --';
If we look at the printed output from the procedure, we can see all of the literal values.
SELECT TOP (1000) p.OwnerUserId, p.Title, p.CreationDate, p.LastActivityDate, p.Body FROM dbo.Posts AS p WHERE 1 = 1 AND p.OwnerUserId = 35004 AND p.Body LIKE '%' UNION ALL SELECT t.object_id, t.name, NULL, NULL, SCHEMA_NAME(t.schema_id) FROM sys.tables AS t; --%';
But if we look at the query plan, we can see partial parameterization (formatted a little bit for readability)
where @0 = @1 and p . OwnerUserId = @2 and p . Body like '%' union all select t . object_id , t . name , null , null , SCHEMA_NAME ( t . schema_id ) from sys . tables as t
Slightly More Interesting
If we change the LIKE predicate on Body to an equality…
IF @Body IS NOT NULL SET @Filter = @Filter + N' AND p.Body = ''' + @Body + ';';
The parameterization will change a little bit, but still not fix the SQL injection attempts.
Instead of the ‘%’ literal value after the like, we get @3 — meaning this is the third literal that got parameterized.
where @0 = @1 and p . OwnerUserId = @2 and p . Body = @3 union all select t . object_id , t . name , null , null , SCHEMA_NAME ( t . schema_id ) from sys . tables as t
But the injecty part of the string is still there, and we get the full list of tables in the database back.
Double Down
If you’d like to learn how to fix tough problems like this, and make your queries stay fast, check out my advanced SQL Server training.
Thanks for reading!
Going Further
If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that and need to solve performance problems quickly.