0

I have the below stored procedure that we've identified as being vulnerable to SQL injection, but I'm not sure how to achieve the same kind of thing without injection. Any ideas appreciated

CREATE PROCEDURE [dbo].[usp_Trun_Tab]
    (@TrunTableSchema VARCHAR(100),
     @TrunTableName VARCHAR(254))
WITH EXECUTE AS OWNER
AS
BEGIN  
    DECLARE @SQL NVARCHAR(400)

    SET @SQL = 'TRUNCATE TABLE '+ @TrunTableSchema +'.'+@TrunTableName 

    EXEC sp_EXECUTESQL @SQL
END
2
  • 4
    Easiest is to not craft procedures like what you have. I doubt it gives any benefit over just running the truncate statement non-dynamically where it's needed. Commented Mar 23, 2021 at 19:26
  • Agree with TT. I see no purpose in this procedure. What does it provide you that just running TRUNCATE TABLE does not? Commented Mar 23, 2021 at 19:37

3 Answers 3

4

You are looking for the QUOTENAME function which ensures the entered names are escaped:

And for neatness you could define your input parameters as sysname since thats what they are.

CREATE PROCEDURE [dbo].[usp_Trun_Tab]
(
    @TrunTableSchema sysname
    , @TrunTableName sysname
)
WITH EXECUTE AS OWNER
AS
BEGIN  
    SET NOCOUNT, XACT_ABORT ON;

    DECLARE @SQL nvarchar(max);

    SET @SQL = 'TRUNCATE TABLE ' + QUOTENAME(@TrunTableSchema) + '.' + QUOTENAME(@TrunTableName);

    EXEC sp_EXECUTESQL @SQL;

    RETURN 0;
END;
Sign up to request clarification or add additional context in comments.

Comments

1

The way I prefer is to do the easiest validation: check against the metadata. You will get only existing objects.

Like this:

create procedure sp_trunc(
  @TrunTableSchema VARCHAR(100),
  @TrunTableName VARCHAR(254)
)
as
begin

  declare @sql nvarchar(1000);

  select
    @sql = 'truncate table '
    + quotename(table_schema) + '.'
    + quotename(table_name) + ''
  from information_schema.tables
  where table_type = 'BASE TABLE'
    and table_schema = @TrunTableSchema
    and table_name = @TrunTableName
  ;

  if @sql is null
    return; --handle not exist
  else
    EXEC sp_EXECUTESQL @sql;

end;

db<>fiddle here

3 Comments

@DaleK Thank you, you are absolutely right! Fixed
@DaleK But input should be valid existing identifier for the statement to return something. Can you please share the example of harmful input? And output still needs quotation, because for my first code it will do wrong with table like create table "t].[" (... )
@DaleK I've deleted my previous comment to recheck it again, but that was ok: such schema name will not pass where clause or if it really exists it will be quoted. Checked in this db<>fiddle. But thank you a lot, you made me think of really bad examples and possibilities.
0

I agree with previous comments, not sure benefit of the procedure. However, you could also check that the table and schema both exist...

declare @x int

select @x = count(*)
from INFORMATION_SCHEMA.TABLES
where table_schema =  @TrunTableSchema
and table_name = @TrunTableName

if @x = 1
begin 
  -- Do your truncation logic here
end

This way, you will only truncate if parameters are valid.

Quotename works as well, this is just an alternative solution, as I tend to validate parameters prior to executing commands

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.