2014-07-19 184 views
3

以下查詢返回表tbl_user中的所有密碼,但我無法理解爲什麼會發生這種情況。'admin'的含義是什麼OR 1 = 1 - '

SELECT password FROM tbl_users WHERE name = 'admin' OR 1=1 -- ' 

請幫助我理解查詢的這個部分: '管理員' OR 1 = 1 - '

你能介紹其他威脅這樣的(網站,書籍等)?

+3

也就是說一個經典的SQL注入。它返回名稱爲'admin' * OR *的用戶,其中1 = 1(因爲1確實每個記錄匹配1)。'--'只是在將它看作是註釋之後才確認eveyrthing – PeeHaa

+0

您可以刪除1 = 1,因爲它什麼也不做。 – Gadgetster

+0

@Gadgetster你是什麼意思? – PeeHaa

回答

6

這是一個經典的SQL注入。 SQLfiddle

在這個例子中,有5個用戶被添加到表:

聽我的解釋是看到這個小提琴。然後您的查詢運行。預期結果將僅返回admin用戶的密碼值。

但是,通過添加1=1(這是一個真實的語句),將返回所有密碼。

幫助可視化的另一種方法是添加括號,以便您可以看到如何評估所有內容。

SELECT pass FROM users WHERE (user_name = 'admin')    OR (1=1) -- ' 
           ^Pulls only the admin user  ^Pulls everything because 1=1 

所以,我們選擇在這裏用戶名是admin表中的密碼。我們也從1 = 1的表格中提取密碼 - 這總是正確的。每行評估爲true,因此所有密碼都會返回。

最後的-- '用於註釋掉其餘的查詢。

SELECT pass from users WHERE user_name = 'admin' or (1=1) -- 'and permission='superadmin' 

通常情況下,(如果1=1沒有被注入),你會拉密碼與管理員和超級管理員權限USER_NAME用戶。你現在已經發表了評論,並沒有被執行。這就是整個密碼錶可以被返回的方式。

+0

非常好,不僅邏輯部分 - 我認爲我做得很好 - 但是這種利用如何改變查詢的意圖以及如何擴展。 – VMai

-2

我認爲你正在尋找「和」而不是「或」

「OR」表示的條件之一(其中name =「管理員」 OR 1 = 1)必須是真實的,並在此情況下,它返回具有名稱等於「管理員」的一切,或具有1等於1

嘗試使用此來代替:

SELECT password FROM tbl_users WHERE name = 'admin' AND 1=1 
+4

該查詢確實不是原作者的意圖 - 它是一種流行的破解語法,旨在利用SQL注入漏洞在所有情況下返回行。在這種情況下,「OR」形式就是黑客想要的。 – halfer

+0

噢好吧,對不起,我對這個東西很陌生,只是試圖從我認識的小孩身上得到幫助。謝謝你告訴我。 – Duane

+0

不用擔心。如果'1 = 1'_preceded_'WHERE'子句的其餘部分 - 如果查詢構建器庫具有一個包含多個可選子句的永久子句,那麼您會很對。這是因爲它簡化了附加語法 - 所有新的子句都是以「AND(clause)」的形式出現的。 – halfer

4

的邏輯OR的結果如下:

a  | b  | a OR b 
----------------------- 
false | false | false 
false | true | true 
true | false | true 
true | true | true 

如果其中一個操作數爲真,則OR b的結果爲真。

1 = 1 evaluates to true 

=>

(any expression) OR 1 = 1 evaluates to true 

=>

name = 'admin' OR 1 = 1 

計算結果爲真爲你的表的每一行

結果:

SELECT password FROM tbl_users WHERE name = 'admin' OR 1=1 -- ' 

將返回密碼,所有用戶,不僅是管理,因爲PeeHaa

作爲陳述
-- 

是開始SQL註釋的。

2

有兩種可能的混淆,我可以想象你在這裏遇到。第一個是,正如其他人所提到的,只要或者expr1expr2爲真,則返回true。由於1=1始終爲真,因此您的WHERE語句對於表中的每個記錄均爲真。

您可能會困惑的第二件事是查詢中的最後一個-- '--是PHP中的//的SQL等效項;它表示該行的其餘部分是註釋,應該忽略。所以SQL解釋器只讀SELECT password FROM tbl_users WHERE name = 'admin' OR 1=1而忽略了其餘部分,這就是爲什麼尾部單引號不會導致語法錯誤的原因。

這裏唯一的安全風險是如果您將未轉義的用戶輸入傳遞給SQL。在SQL查詢中使用它之前,請始終使用mysqli_real_escape_string或等效函數轉義任何用戶輸入。

編輯:正如在註釋中指出的,參數化查詢通常比手動轉義每個輸入元素更好。 PHP的PDO擴展是以這種方式開始的好地方。

+1

IMO,最好使用參數化而不是轉義和串聯 - 後者應該只用於不能被參數化的東西,比如列名。 – halfer

+1

@halfer我同意,參數化優於轉義+串聯作爲編碼實踐,因爲錯誤更難。我將編輯它的參考到答案中。 –

0

最後部分-- '是註釋,所以MySQL不關心。所以我們沒有留下

SELECT password FROM tbl_users WHERE name = 'admin' OR 1=1 

在此查詢1=1是真實的,因爲1是同樣是1這可能是這裏當然另一個真實的表達,例如2=2'a'='a' - 結果將是始終不變的。

所以您的查詢看起來是這樣的:

SELECT password FROM tbl_users WHERE name = 'admin' OR true 

操作OR以這種方式工作,如果有任何的條件是事實,就意味着整個表達式爲true。在表達name = 'admin' OR true一個表達式爲true(真實不虛),所以這整個表達式是true

所以查詢現在可能是

SELECT password FROM tbl_users WHERE true 

現在,如果我們看看那裏的一部分,我們有WHERE true。這意味着事實上沒有條件,所以我們可以改變查詢到:正如你在表格中看到您的查詢簡單的獲得列password每個記錄

SELECT password FROM tbl_users 

所以(可能爲所有用戶)

+0

不好意思,你能幫我理解爲什麼下面的查詢不起作用嗎? 'SELECT name FROM list WHERE name = true - '' – Daniyal

+0

@Daniyal,如果你有問題,請隨時解釋發生了什麼(錯誤?沒有?崩潰?等)。在這種情況下,您可能會比較字符串列和布爾常量。 – halfer

+0

@halfer非常感謝MR @Marrcin,對不起,你能幫我理解爲什麼下面的查詢返回一個空的結果集? 'SELECT name FROM list WHERE name = true - '' – Daniyal