在获得classic ASP protection against SQL injection的SQL注入安全性方面得到了很大帮助之后,我遇到了一个主要问题,无法使用参数化查询解决。
name = Trim(Request.QueryString("name"))
flds = Trim(Request.QueryString("flds"))
sql = "set rowcount 0 select " & flds & " from [TABLE] where Name = '" & name & "'"
据我所知,参数化查询将防止WHERE子句中的SQL注入(在本例中为name
字段。
flds
是用户想要返回的以逗号分隔的参数列表。很明显,非常容易受到SQL注入攻击。
我必须保护代码的一个想法是使用静态生成的有效字段的dict,将flds
字符串拆分为“,”,根据dict验证每个值,并构造SQL查询它将包含字典中存在的所有字段。
在我看来,虽然这种方法可以用于安全性,但它需要我在数据库中的每次更改时修改静态列表(无论这种情况很少见)。
是否有更好/正确的方法来保护此代码免受SQL注入攻击?
答案 0 :(得分:2)
在SQL Server中创建一个拆分函数(对于较新的版本,有更好的版本,但这是你在SQL Server 2000中得到的):
CREATE FUNCTION dbo.SplitStrings
(
@List NVARCHAR(4000),
@Delimiter CHAR(1)
)
RETURNS @Items TABLE
(
Item NVARCHAR(4000)
)
AS
BEGIN
DECLARE
@Item VARCHAR(12),
@Pos INT;
WHILE LEN(@List)>0
BEGIN
SET @Pos = CHARINDEX(@Delimiter, @List);
IF @Pos = 0
SET @Pos = LEN(@List)+1;
SET @Item = LEFT(@List, @Pos-1);
INSERT @Items SELECT LTRIM(RTRIM(@Item));
SET @List = SUBSTRING(@List, @Pos + LEN(@Delimiter), LEN(@List));
IF LEN(@List) = 0 BREAK;
END
RETURN;
END
GO
然后创建一个存储过程:
CREATE PROCEDURE dbo.RunScaryQuery
@columns NVARCHAR(4000),
@table NVARCHAR(255)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @collist NVARCHAR(4000), @sql NVARCHAR(4000);
SELECT @collist = COALESCE(@collist + ',', '') + c.name
FROM syscolumns AS c
INNER JOIN dbo.SplitStrings(@columns, ',') AS s
ON s.Item = c.name
WHERE c.id = OBJECT_ID(@table);
SELECT @sql = 'SELECT ' + @collist + ' FROM ' + @table
-- where ...
;
EXEC sp_executesql @sql;
END
GO
现在使用正确参数化的命令对象从ASP调用该存储过程。
这将确保仅使用表中实际存在的列名生成SQL查询。 (任何废话都会被忽略。)
这假设您将在列表中至少获得一个有效的列名称。
答案 1 :(得分:0)
我在家,没有数据库可以测试但是应该这样做 基本上,从db中获取适合where的所有字段,在数组中获取请求的字段并比较两个列表,仅输出所请求的字段。
name = Trim(Request.QueryString("name"))
flds = split(Trim(Request.QueryString("flds")),",")
sql = "set rowcount 0 select * from [TABLE] where Name = '" & name & "'"
set oRst = oConn.execute(sql)
on error resume next
do while not oRst.eof
result = ""
separator = ""
for each field in flds
for each requested_field in flds
if uCase(field.name) = uCase(trim(requested_field)) then
result = result & separator & field.value
separator = ","
end if
next
next
response.write result & "<br>"
oRst.movenext
loop
答案 2 :(得分:0)
嗯......所以我会选择其他解决方案。
我首先有一个返回所有有效字段的SQL查询
select
tcol.name
from
sysObjects tobj
join syscolumns tcol on tobj.id = tcol.id
where
tobj.xtype = 'U'
and tobj.name = '[TABLE]'
然后我按照@peter的建议验证每个元素。然后使用所有经过验证的参数构建查询字符串,并在第二个查询中将名称作为参数传递。
这似乎可以最大限度地减少数据库的开销和压力。
答案 3 :(得分:-1)