天天看點

MySQL中另類輸入是什麼_MySQL解決SQL注入的另類方法詳解

本文執行個體講述了MySQL解決SQL注入的另類方法。分享給大家供大家參考,具體如下:

問題解讀

我覺得,這個問題每年帶來的成本可以高達數十億美元了。本文就來談談,假定我們有如下 SQL 模闆語句: select * from T where f1 = '{value1}' and f2 = {value2}

現在我們需要根據使用者輸入值填充該語句: value1=hello

value2=5

我們得到了下面的 SQL 語句,我們再送出給資料庫: select * from T where f1='hello' and f2=5

問題在于,攻擊者可以構造如下的使用者輸入值: value1=anything' or 1=1 or f1='whatever

value2=5

拼接好的最終語句就變成了: select * from T where f1='anything' or 1=1 or f1='whatever' and f2=5

攻擊者成功地改變了模闆語句的語義。這種問題不單單發生在 SQL 上,還出現在通常使用模闆的任何語言上,比如 HTML 和 shell 腳本。

正常解決方案的說明

SQL 是具備任意性和一緻性的公理,token 和派生規則構成其公理化基礎。要注意的一個詞語是「任意性」。與 SQL 等價的公理化數不勝數。對于這種任意等價的表示,每一條合法的語句都能被準确地映射到 SQL 裡的合法語句,其它語言亦然。在這種任意等價表示中,如果某語句是不合法的,那麼它在 SQL 裡也是不合法的。攻擊者不可能構造出可以滿足任何可能的、任意與 SQL 等價的規則。

政策1:根據不同的派生規則,用另一種文法擴充模闆語句

例子1:字首語言

SQL 使用中綴表示法注1。中綴表示法等價于 lisp 風格的字首表示法注2。中綴與字首: a OP1 b OP2 c <=> (OP1 a (OP2 b c))

a、b、c 是辨別符或值,OP1、OP2 是操作符或功能。

字首表示法的示例語句: (select * T (and (= f1 '{value1}') (= f2 {value2})))

該語句是等價的。它們在語義上屬于外延。自動把 SQL 的中綴表示法轉換成字首表示法或其它表示法,都不算問題了。然而,攻擊者的注入在字首文法方面就是不合法的:

複制代碼 代碼如下:(select * T (and (= f1 'anything' or 1=1 or a='whatever') (= f2 5)))

文法錯誤。攻擊者想要的是:

複制代碼 代碼如下:(select * T (or (= f1 'anything') (or (=1 1) (and (= a 'whatever') (= f2 5)))))

這是不同的。攻擊者的注入不能輸出合法的字首語言。

例子2:歐拉表示法

另一個替代方法将數得着歐拉表示法了。從中綴表示法到歐拉: a OP1 b OP2 c <=> OP1(a,OP2(b,c))

例子中的語句: select( *,T,and(=(f1,'{value1}'),=(f2,{value2})))

而注入的語句将出現文法錯誤:

複制代碼 代碼如下:select( *,T,and(=(f1,'anything' or 1=1 or a='whatever'),=(f2,5)))

攻擊者本來是想寫成:

複制代碼 代碼如下:select( *,T,or(=(f1,'anything',or(=(1,1),and(=(a,'whatever'),=(f2,5))))))

攻擊者正在做錯誤的事情。他的注入根本就沒有注意到所選的任意标記法。

例子3:對象标記法(object notation)

還有一種替代方法,對象标記法。從字首表示法到對象: a OP1 b OP2 c <=> a.OP1(b).OP2(c)

例子的代碼: T.where(f1.=('{value1}').and(f2.=({value2})).select(*)

注入再一次折戟于文法: T.where(f1.=('anything' or 1=1 or a='whatever').and(f2.=5)).select(*)

我不再提供正确答案了,讀者可以當做練習,看看攻擊者應該寫成什麼樣子。

政策2:為 SQL 選擇其它任意 token

keyword 常常是一門語言裡的任意 token。重要的是它們在派生規則裡的位置、而非它們的任意展現。你總是可以用其它 keyword 替換現有 keyword,并且來回轉換。舉個例子,我們可以将下面 SQL 語句中的 keyword 轉換成我們姑且稱為「任意的 brainfuck」:

複制代碼 代碼如下:{"select":"iph0ohKi", "*":"ieZoh4xa", "from":"aeZi5uja", "where":"OoJ4aX4n", "=":"eeQu2Zad", "(":"eiD5aera",")":"Soo2uach", "or":"Ocaig5Es"}

為了論證起見,我們将把操作數映射為 半任意的結構化序列: T <=> @[email protected]@

hello <=> @[email protected]@

phai1Oa6 是任意選取的字元序列。對于目前情形,例子: select * from T where f1 = '{value1}' and f2 = {value2}

變成了:

iph0ohKi ieZoh4xa aeZi5uja @[email protected]@ OoJ4aX4n @[email protected]@ eeQu2Zad '{value1}' @[email protected]@ @[email protected]@ eeQu2Zad {value2}

這是合法的、任意的 brainfuck 語言。經過注入之後,我們得到了:

iph0ohKi ieZoh4xa aeZi5uja @[email protected]@ OoJ4aX4n @[email protected]@ eeQu2Zad 'anything' or 1=1 or a='whatever' @[email protected]@ @[email protected]@ eeQu2Zad 5

你可以看到,它包含的 token 有 'or' 和 '=',它們在任意的 brainfuck 語言中是不合法的。我們的文法說,你必須這樣使用: or <=> Ocaig5Es

= <=> eeQu2Zad

這些 token 也不是操作數,因為它們将隻能被視作: or <=> @[email protected]@

= <=> @[email protected][email protected]

換句話說,注入之後的語句就變得不合法、也不可用了。

政策3:驗證不變量

你數數下面模闆語句例子中的 token 有幾個?

[1] select [2] * [3] from [4] T [5] where [6] f1 [7] = [8] '{value1}' [9] and [10] f2 [11] = [12] {value2}

12 個。模闆填充之後,總數必須仍然為 12,但是我們卻看到了攻擊者所引發的結果:

[1] select [2] * [3] from [4] T [5] where [6] f1 [7] = [8] 'anything' [9] or [10] 1 [11] = [12] 1 [13] or [14] a [15] = [16] 'whatever' [17] and [18] f2 [19] = [20] 5

現在有 20 個 token 。違反這種不變量,就暴露了有問題的地方。同樣适用于相同語句的表示,除了任意的、brainfuck 語言。模闆的填充根本不可能導緻 token 數量的變化。

事實上,你可以試着使用其它不變量,并在填充之後進行驗證。攻擊者必須和它們保持一緻。

結論

有些人提倡,程式員在填充 SQL 模闆時,應該更加小心。應對 SQL 注入問題,隻是需要在程式設計方面多加小心。很明顯,這種方式算不上解決方案。人們仍然在校驗使用者輸入值方面出現錯誤,最終接受了帶有惡意的使用者輸入值。換句話說,單憑我們所有人更努力地工作,是無法根本解決這種問題的。

真正的解決方案在于,SQL 語句本身的任意性,并要求所有現存不變量都符合任意的等價結構的規則。無需程式員的幹預,就能自動完成。

攻擊者不得不符合一種未知的、任意的 brainfuck 文法的規則。想要符合一組未知的規則,将是難以解決的問題。是以,攻擊者通常無法得手。

更多關于MySQL相關内容感興趣的讀者可檢視本站專題:《MySQL日志操作技巧大全》、《MySQL事務操作技巧彙總》、《MySQL存儲過程技巧大全》、《MySQL資料庫鎖相關技巧彙總》及《MySQL常用函數大彙總》

希望本文所述對大家MySQL資料庫計有所幫助。