2012-06-20 43 views
7

我知道在sql語句中使用參數,但只是爲了好奇才安全地使用Format函數來防止sql注入而不是使用參數。格式函數與SQL注入場景中的參數?

這樣的樣本

sCustomer : string 
begin 
AdoSql.CommandText:=Format('Select SUM(value) result from invoices where customer=%s',[QuotedStr(sCustomer)]); 
end; 
+1

我認爲標題應該是'QuotedStr函數vs參數在sql注入場景?'但改變它,會在這裏打破一些答案。 * issue *這裏是關於'QuotedStr'而不是'Format'。 – kobik

回答

11

這將可能對抗SQL注入安全的,假設QuotedStr按預期工作,並且沒有邊緣的情況下,可以打破它。 (這並不是有保證的,正如Linas在評論中指出的那樣,MySql允許您使用\'來避免引號,其他DBMS可能具有相似的功能,對系統有足夠理論知識的攻擊者可以利用它們。

但是,即使QuotedStr足夠好,仍然可以使用不同的參數:性能。將參數與查詢分開時,最終可以使用不同的參數多次發送完全相同的查詢代碼。如果這樣做,數據庫可以緩存它在計算查詢時所做的大量工作,因此您的數據庫訪問速度會更快。當你將參數混合到查詢代碼本身時,這不起作用(或者至少不是那麼好)。

+6

+1對於「緩存」的評論,很多SQL Server可以重用sql語句的執行計劃。 – RRUZ

+3

這可能會在MySQL中不安全,因爲MySQL允許\'轉義報價,所以QuotedStr在這裏沒有幫助。 – Linas

+0

@Linas:好點。編輯考慮到這一點。 –

5

無論何時通過串聯字符串來構建SQL字符串,無論您認爲訪問這些字符串有多安全,都有可能發生注入式攻擊。對於您所知道的,有人可以在調試器中運行您的應用程序,在QuotedStr()的結果上放置斷點,並在允許Format()看到它之前修改其內容。

使用實際的SQL參數是最安全的方法。它不僅可以避免注入,而且還允許SQL引擎根據自己的需要決定如何最佳地設置參數的格式,因此您不必擔心在自己的代碼中格式化值,它對於強類型語言(如Delphi)。更不用說能夠提前在服務器端準備SQL語句,然後在您的代碼中執行它(甚至是多次)之前的性能優勢,從而大大減少了客戶端和服務器之間的流量並提高了整體性能。

var 
    sCustomer : string 
begin 
    AdoSql.CommandText := 'Select SUM(value) result from invoices where customer=:Customer'; 
    AdoSql.Prepared := True; 
    ... 
    AdoSql.Parameters['Customer'].Value := sCustomer; 
    AdoSql1.ExecSQL; 
    ... 
    AdoSql.Parameters['Customer'].Value := sCustomer; 
    AdoSql1.ExecSQL; 
    ... 
    AdoSql.Prepared := False; 
end; 
+3

那第一段有點傻。 SQL注入基本上是關於獲取對數據庫的未授權訪問。但是,如果某人對您的應用程序本身具有調試級訪問權限,則他們不需要* SQL注入攻擊來訪問數據庫;他們可以假定已經有權訪問它,與應用程序本身具有相同的權限級別。 –

+1

如果應用程序使用與數據庫的加密連接,或者攻擊者無法或不想確定正在使用哪種數據庫或如何直接訪問數據庫,則不適用。讓應用程序完成所有工作,只需更改執行的SQL即可。 –

+2

在這種情況下,然後使用參數也會變得不安全,因爲用戶可能會更改參數的值 - 有時在調試我自己的應用程序時會這樣做。 –

5

不,Format不提供SQL注入的安全性。這與普通的字符串連接沒有什麼不同。

問題中針對SQL注入進行任何操作的代碼部分是對QuotedStr的調用,您可以使用它或者使用Format。儘管如此,它並不像真正的參數化查詢那麼可靠。

Format在這種情況下唯一的好處是,整個字符串模板是在一個地方,這樣你就不太可能得到空格和標點錯誤比你會如果你要構建具有連續+操作字符串,其中的SQL撇號可能會在Delphi撇號中丟失。