这可以很容易地在这里注入,因为@ID param通过输入它几乎可以在这个SQL语句中的任何内容,但是,你如何防止这种利用?
我更愿意在此级别而不是应用程序级别,任何建议中专门防止此漏洞利用?
CREATE PROCEDURE [dbo].[GetDataByID]
@ID bigint,
@Table varchar(150)
AS
BEGIN
Declare @SQL Varchar(1000)
SELECT @SQL = 'SELECT * FROM ' + @Table + ' WHERE ID = ' + CONVERT(varchar,@ID)
SET NOCOUNT ON;
EXEC(@sql)
END
答案 0 :(得分:9)
检查this page,它有一个很棒的动态sql指南,以及安全执行它们的选项
在你的情况下它应该是这样的:
SELECT @SQL = N'SELECT * FROM ' + quotename(@Table) + N' WHERE ID = @xid'
EXEC sp_executesql @SQL, N'@xid bigint', @ID
答案 1 :(得分:1)
1)创建一个具有标识PK并包含字符串表名称的新表 2)在您的程序中插入所有/仅有效的表格 3)使用此int identity PK作为存储过程的输入参数值(TableID) 4)在过程中,只需从给定的身份PK中查找字符串值(表名),您就可以安全地连接查询中的查找字符串。 5)你的WHERE子句没有问题,因为你传入了一个int
答案 2 :(得分:0)
我建议完全避免使用动态sql。问题如下:
注意 QUOTENAME不会保证您注射安全。截断注射仍然是可能的。使用前请先阅读http://msdn.microsoft.com/en-us/library/ms161953.aspx。
答案 3 :(得分:0)
虽然我一般会建议动态sql,但在这种情况下,我认为你可以通过检查@Table变量是否包含有效的表名来逃避它。
只是在@table周围放置QuoteName()不会保护你免受一切。虽然功能很强,但它还远非完美。恕我直言,你最好的办法是解析@Table变量,检查其内容是否有效,然后根据获得的部分创建动态sql。 我开始做上面的大部分工作,令人惊讶的是它需要很多检查看起来像这样简单的东西=)
CREATE PROCEDURE [dbo].[GetDataByID] (
@ID bigint,
@Table nvarchar(300)
)
AS
DECLARE @sql nvarchar(max)
DECLARE @server_name sysname,
@db_name sysname,
@schema_name sysname,
@object_name sysname,
@schema_id int
SELECT @server_name = ParseName(@Table, 4),
@db_name = ParseName(@Table, 3),
@schema_name = ParseName(@Table, 2),
@object_name = ParseName(@Table, 1)
IF ISNULL(@server_name, @@SERVERNAME) <> @@SERVERNAME
BEGIN
RaisError('Queries are restricted to this server only.', 16, 1)
Return(-1)
END
IF ISNULL(@db_name, DB_Name()) <> DB_Name()
BEGIN
RaisError('Queries are restricted to this database only.', 16, 1)
Return(-1)
END
IF @schema_name IS NULL
BEGIN
IF NOT EXISTS ( SELECT *
FROM sys.objects
WHERE name = @object_name
AND type IN ('U', 'V') )
BEGIN
RaisError('Requested @Table not found. [%s]', 16, 1, @object_name)
Return(-1)
END
SELECT @sql = 'SELECT * FROM ' + QuoteName(@object_name) + ' WHERE ID = @ID'
END
ELSE
BEGIN
SELECT @schema_id = Schema_id(@schema_name)
IF @schema_id IS NULL
BEGIN
RaisError('Unrecognized schema requested [%s].', 16, 1, @schema_name)
Return(-1)
END
IF NOT EXISTS ( SELECT *
FROM sys.objects
WHERE name = @object_name
AND schema_id = @schema_id
AND type IN ('U', 'V') )
BEGIN
RaisError('Requested @Table not found. [%s].[%s]', 16, 1, @schema_name, @object_name)
Return(-1)
END
SELECT @sql = 'SELECT * FROM ' + QuoteName(@schema_name) + '.' + QuoteName(@object_name) + ' WHERE ID = @ID'
END
EXEC sp_executesql @stmt = @sql,
@params = N'@ID bigint',
@ID = @ID
Return(0)
Supra编译,但你可能需要解决一些错误,因为我没有完全检查所有代码路径。