如何防止SQL注入

Nao*_*aor 4 t-sql stored-procedures sql-injection

我正在使用存储过程.为了节省时间,我做了一些使用动态sqlin顺序更新的通用程序.这种通用程序是:

CREATE PROCEDURE [dbo].[SetField]
 @company_id uniqueidentifier,
 @id bigint,
 @field_code nvarchar(50),
 @value nvarchar(50)
AS
BEGIN
 DECLARE @field_name nvarchar(50)
 SET @field_name = NULL
 SELECT @field_name=field_name
 FROM dbo.FIELD_DEFINITION
 WHERE field_code=@field_code

 IF @field_name IS NOT NULL
 BEGIN

  IF @value IS NULL OR @value=''
  BEGIN
   SET @value='NULL'
  END
  ELSE
  BEGIN
   IF @field_code='START_DATE' OR @field_code='END_DATE'
   BEGIN
    SET @value = CONVERT(datetime, @value ,103)
   END
   SET @value=''''+@value+''''
  END

  DECLARE @sql nvarchar(1000)
  SET @sql = 'UPDATE dbo.TABLE '+
     'SET '+@field_name+'='+@value+' '+
     'WHERE company_id=''' + CAST(@company_id as nvarchar(36)) + ''' AND '+
     'id='+CAST(@id as nvarchar)
  EXEC(@sql)
 END
END
Run Code Online (Sandbox Code Playgroud)

如何使用此代码阻止sql注入?

gbn*_*gbn 6

你说:

为了节省时间,我制作了一些使用动态sql进行更新的通用程序

如果您先询问,我们可以节省时间并建议这样做......

UPDATE
    dbo.TABLE
SET
    Field1 = CASE WHEN @field_name = 'Field1' THEN @value ELSE Field1 END,
    Field2 = CASE WHEN @field_name = 'Field2' THEN @value ELSE Field2 END,
    Field3 = CASE WHEN @field_name = 'Field3' THEN @value ELSE Field3 END,
    ...
    Fieldn = CASE WHEN @field_name = 'Fieldn' THEN @value ELSE Fieldn END
WHERE
    company_id = @company_id AND id = @id
Run Code Online (Sandbox Code Playgroud)


Ada*_*son 5

关于 SQL 注入要记住的一个重要方面是,如果可能的话,您永远不应该将用户提供的值直接嵌入到您的 SQL 中。这并不意味着你不能使用动态SQL(尽管它绝对会让事情变得更容易,如果你没有),但它确实成为时代更加危险。

在您的具体示例中,您可以保留除@field_name. 不幸的是,这必须直接嵌入到 SQL 中;其他所有内容都可以再次作为参数传递,因此无需担心它们的内容。

在此特定示例中,您可以做的最安全的事情如下:

if(exists (select 1 from INFORMATION_SCHEMA.Columns where TABLE_NAME = 'Table' and TABLE_SCHEMA = 'dbo' and COLUMN_NAME = @fieldName))
begin
    DECLARE @sql nvarchar(1000)
    SET @sql = 'UPDATE dbo.TABLE '+
       'SET ' + QUOTENAME(@field_name) + '=@value ' + 
       'WHERE company_id=@company_id AND '+
       'id=@id'

    exec sp_executesql @sql,N'@id bigint, @company_id uniqueidentifier, @value nvarchar(50)',@id,@company_id,@value
end
Run Code Online (Sandbox Code Playgroud)

这有两件事:

  1. 它验证表中是否确实存在具有该名称的列。如果用户将任何其他 SQL 语句嵌入到该字段中,则此检查将失败并且不会执行该语句。你也可以打电话raiseerror报告错误,但我会把这个练习留给你。
  2. 它将字段名称括在方括号中,以便包含空格或保留字的字段名称不会破坏语句。这对您来说可能不是问题,但如果您自己生成 SQL,这总是很好的做法。