我有问题,我无法使用存储过程查看用户信息。该过程接受三个参数:table
,column
和searchBySomething
。每次我想使用其他列搜索用户时,column变量都会接收ID的列,而searchBySomething
变量会接收特定的ID,此过程是可行的,但是当我发送另一列时,我会得到错误消息
无效的列名(数据)
该过程如下:
ALTER PROCEDURE [dbo].[userDetailsDisplay]
@table NVARCHAR(30),
@column NVARCHAR(30),
@searchBySomething NVARCHAR(30)
DECLARE @sql NVARCHAR(100)
SET @sql = 'SELECT * FROM ' + @table + ' WHERE ' + @column + ' = ' + @searchBySomething
EXECUTE sp_executesql @sql
答案 0 :(得分:3)
因此,您得到的特定错误是因为您没有检查输入以查看传递到@column
的字符串是否确实存在。您可以按照以下步骤对照元数据目录视图sys.columns
检查它的存在:
if not exists
(
select 1
from sys.columns
where object_id = object_id(@table)
and name = @column
)
begin
raiserror('Column %s does not exist in table %t', 16, 1, @column, @table)
return
end
但是,如果我不指出两件事,我将被解雇。
首先,这种动态表动态where子句模式是非常不好的做法。如果是针对已经具有数据库访问权限的人员,则他们只需查询自己的表即可。而且,如果是针对外部用户的,那么您基本上可以通过此过程为他们提供完整的数据库读取访问权限。当然,在某些稀有场合中需要这种模式,因此,如果您对使用动态sql感到无所适从,那将引出我的下一个观点。
您编写的代码容易受到SQL注入攻击。任何时候使用动态SQL时,都必须非常小心其构造方式。假设我传入了列名; drop database [admin]--
,假设您拥有这样一个数据库,我将很乐意被执行,而您的数据库将消失。
如何确保动态SQL的安全是一个复杂的主题,但是如果您认真了解更多有关它的知识,那么这可能是您可以找到的最佳文章之一。 http://www.sommarskog.se/dynamic_sql.html
通过参数化查询并在表和列上使用quotename()
,我将其修改为如下所示。如果有人尝试进行注入攻击,这仍然会引发奇怪的错误,但至少不会真正执行其代码。
create procedure [dbo].[userDetailsDisplay]
@table nvarchar(30),
@column nvarchar(30),
@searchBySomething nvarchar(30)
as
begin
declare
@sql nvarchar(max),
@params nvarchar(1000)
if not exists
(
select 1
from sys.columns
where object_id = object_id(@table)
and name = @column
)
begin
raiserror('Column %s does not exist in table %t', 16, 1, @column, @table)
return
end
select @sql = '
select *
from ' + quotename(@table) + ' WHERE ' + quotename(@column) + ' = @searchBySomething'
execute sp_executesql
@stmt = @sql,
@params = '@searchBySomething nvarchar(30)',
@searchBySomething = @searchBySomething
end
答案 1 :(得分:0)
只需检查以确保表中存在该列。
对于每个调用的@table
,请检查@column
变量是否在该表中。
答案 2 :(得分:0)
SET @sql = 'SELECT * FROM ' + @table + ' WHERE ' + @column + ' = ' +''' @searchBySomething +''''
例如:select * from table where column ='value'