其實是因為SQL語句在程式執行前已經進行了預編譯,在程式執行時第一次操作資料庫之前,SQL語句已經被資料庫分析,編譯和最佳化,對應的執行計劃也會快取下來並允許資料庫已引數化的形式進行查詢,當執行時動態地把引數傳給PreprareStatement時,即使引數裡有敏感字元如 or "1=1"也資料庫會作為一個引數一個欄位的屬性值來處理而不會作為一個SQL指令,如此,就起到了SQL注入的作用了!
具體像這樣。例如剛剛那條SQL:
SELECT * From table_name WHERE name="" and password="" and corporate="" or 1=1-"
要回答這個問題,我們要知道怎麼進行的SQL注入,所謂知己知彼,方能百戰百勝。
什麼是SQL注入??
所謂SQL注入,就是透過把SQL命令插入到Web表單提交或頁面請求url的查詢字串,最終達到欺騙伺服器執行惡意的SQL命令。具體來說,它是利用現有應用程式,將(惡意)的SQL命令注入到後臺資料庫引擎執行的能力,它可以透過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的資料庫,而不是按照設計者意圖去執行SQL語句。
實戰舉例有個登陸框如下:
可以看到除了賬號密碼之外,還有一個公司名的輸入框,根據輸入框的形式不難推出SQL的寫法如下:
SELECT * From table_name WHERE name="XX" and password="YY" and corporate="ZZ"
怎麼做呢,?
因為沒有校驗,因此,我們賬號密碼,都不填寫,直接在最後,新增 or 1=1 --
看看與上面SQL組合,成了如下:
SELECT * From table_name WHERE name="" and password="" and corporate="" or 1=1-"
從程式碼可以看出,前一半單引號被閉合,後一半單引號被 “--”給註釋掉,中間多了一個永遠成立的條件“1=1”,這就造成任何字元都能成功登入的結果。
重要提醒不要以為在輸入框做個檢查就夠了,不要忘記了,我們web提交表單,是可以模擬url直接訪問過去,繞開前段檢查。因此,必須是後端,或是資料來檢查才能有效防止。
(1)檢查使用者輸入的合法性;
(2)將使用者的登入名、密碼等資料加密儲存。
(3)預處理SQL。
(4)使用儲存過程實現查詢,雖然不推薦,但也是一個方法。
MySQL預處理是怎麼防止的呢?其實是因為SQL語句在程式執行前已經進行了預編譯,在程式執行時第一次操作資料庫之前,SQL語句已經被資料庫分析,編譯和最佳化,對應的執行計劃也會快取下來並允許資料庫已引數化的形式進行查詢,當執行時動態地把引數傳給PreprareStatement時,即使引數裡有敏感字元如 or "1=1"也資料庫會作為一個引數一個欄位的屬性值來處理而不會作為一個SQL指令,如此,就起到了SQL注入的作用了!
具體像這樣。例如剛剛那條SQL:
SELECT * From table_name WHERE name="" and password="" and corporate="" or 1=1-"
開啟預編譯執行SQL的時候,則不會這麼處理。會當成一個屬性值。什麼意思。隨便你怎麼加,都是一個值。也就是說,如果中間有產生歧義的,都將被處理掉,最後執行相當於是這樣:
SELECT * From table_name WHERE name="" and password="" and corporate=""or 1=1--"
這個大家應該看的懂吧,輸入的一串,都被揉在一起,作一個引數,而不是SQL。
這樣就無法進行SQL注入了。是不是很巧妙。
好了,回答完畢,你學到了嗎?