2015-12-21 72 views
0

我在数据库中有一个存储过程,它接受直接插入到查询中的字符串参数。我有客户端代码来逃避输入,但是这并不会阻止任何有权以错误参数执行该过程并注入SQL的人。服务器端的转义字符串

当前实现是这样的:

CREATE PROCEDURE grantPermissionSuffix (perm VARCHAR(30), target VARCHAR(30), id VARCHAR(8), host VARCHAR(45), suffix VARCHAR(45)) 
BEGIN 
    SET @setPermissionCmd = CONCAT('GRANT ', perm, ' ON ', target, ' TO ''', id, '''@''', host, ''' ', suffix, ';'); 
    PREPARE setPermissionStmt FROM @setPermissionCmd; 
    EXECUTE setPermissionStmt; 
    DEALLOCATE PREPARE setPermissionStmt; 
    FLUSH PRIVILEGES; 
END 

显然,这是一个灾难。我怎样才能防止注射机会?是否有标准的SQL函数来转义输入?有没有一个用于MySQL?有没有额外的客户端代码获得相同结果的另一种方法?

我的担心是唯一的解决方案将是客户端准备好的语句,目前这不是一个选项。我需要在服务器上处理所有的逻辑,要求客户端只调用这个过程(我不想授予用户直接修改表/权限的权限,只能用允许执行的过程来处理它)。

+0

为您的用户提供mySQL客户端和相应的权限。 –

回答

0

您可以使用?占位符为变量准备报表,然后使用EXECUTE USING变量,就像在客户端准备的语句中一样,至少根据manual。但我不确定在替换表名时效果如何,但这受到prepare规则的限制,所以如果它在服务器端不起作用,它在客户端也不起作用。

UPDATE:

显然,MySQL不承认准备GRANT查询?占位符。在这种情况下,您必须手动处理。一些技巧在that answer - 即使用`(反向)转义标识符和使用关键字白名单 - 这样,你也可以在你的程序中允许的细粒度控制。

我想补充说,为了您的特定目的,最好从information_schemamysql表中选择,以控制传递给您的db和table实际存在的数据。您可以使用带有占位符的预准备语句,因此它很安全。像这样的东西会检查数据库和表:

PREPARE mystat FROM 'SELECT count(*) into @res FROM INFORMATION_SCHEMA.TABLES WHERE upper(TABLE_SCHEMA)=UPPER(?) and UPPER(TABLE_NAME)=UPPER(?)'; 

set @db = 'mydb'; --these two are params to your procedure 
set @table = 'mytable'; 
set @res = 0; 
execute mystat using @db, @table; 
select @res; --if it's still 0, then no db/table exists, possibly an attack is happening. 

检查用户和主机可以做到这样,也使用mysql.users表代替。对于其余的参数,你必须建立一个白名单。

我看到的另一种方法是使用正则表达式检查允许的字符 - 这里有REGEXP命令。例如,您可以控制您的过程参数只有字母大写if @var REGEXP '^[A-z]+$'。据我所知,仅使用A-z执行SQL注入是不可能的。

+0

我在我的问题中描述的过程实际上从不直接由客户端调用。你认为我应该用'?'占位符来准备一个声明,最终调用这个“私有”过程吗? – 2mac

+0

@ 2mac不,我的意思是'GRANT?上 ?至 ?@? ';',但显然这是不可能的。我会在几分钟内修改我的答案,还有一些方法。 – Timekiller