2015-12-21 74 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