首先提及sql注入這個題目,也許大家會笑笑,覺得這是一件比較低級的攻擊方式,但事實上,正是這種不屑,就可能會導致我們網站數據庫服務器被攻擊,甚至服務器權限都被提走,這種例子,以不鮮見。以下是我在寫ORM時sql注入這塊,所研究的心得,分享給大家,有可能說的不對,還望大家指正。
先來看下這段sql
$query = 'SELECT * from user where name =" '.$name.' "';
這樣的sql是我們經常有寫的,
然后$name = ' ";delete from user where name="mini -- ";';
這里' 后面跟一個空格,其實沒有,是wile看的更清楚些
如此,這就是是一個sql注入,先截斷了我們定義好的"符號,自定義一個"使之於我們定義好的第一個"配對,這樣后面的輸入串,就非一個sql字符串了,就成功完成sql注入
這種截斷引號的注入方式非常常見,當然引號包括單引號於雙引號,注入者,必須要完成與sql語句的前一個引號,成功配對,才可能完成注入,這里所說的成功配置指的是,如果 我們這里
where name =" ' .$name. ' " 注入者,就必須只有用"號才能成功配對,截斷本該是字符串的參數,
如果這塊是 where name =' " .$name. " ' 單引號來標識的字符串,那么注入者,只可能用單引號來截斷,完成注入
注意上面提到的sql語句,變量拼接語法所涉及到的單引號或雙引號,這只是語法形式,拼接完成后,並不會保留
前面說到的是,截斷引號方式的注入方法,還有一種是根本不需要截斷引號就可以完成注入的方式,
比如說,如下sql
$query = 'SELECT * from '.$user.' where name ="zhangyan" ';
其中$user = 'user;delete from user where name="mini";--';
如此這個變量本來就不在一個字符串中,當然,注入時,不用引號配對來截斷,直接;結束上一個sql然后寫我們的注入sql語句就ok
所以,有效的避免sql注入,並不僅僅是在where條件后。
如何來有效的避免sql注入呢,
這里只說pdo,
1.首先pdo提供quote方法,來轉義所有的輸入的參數
但是使用quote方法需要注意的是,它認為所有輸入的參數都是字符串形式輸出,所以在拼接sql是,自定義的sql語句就不用在加上 字符串表示符了(單引號或者雙引號) 比如說where name ='.$name
直接如此就ok 。這里出現的單引號是為了拼接變量的語法形式,並不是字符串中的引號
2.第二種方式是使用prepare來於執行你的sql語句,之后再進行填充你的輸入參數,以此來保證不會出現截斷整體sql的行為,但並不是說sql語句就完全能夠防止sql注入,比如如下
$prepareSql = 'SELECT * from '.$user.' where name =:name';
$sth = $dbh->prepare($prepareSql);
$sth->execute(array(':name' => 'zhangsan'));
$sth = $dbh->prepare($prepareSql);
$sth->execute(array(':name' => 'zhangsan'));
這里的$user 還是和之前一樣 $user = 'user;delete from user where name="mini";--';
這樣在預執行的時候,sql注入就已經發生了,網上都說pdo能夠防止sql注入,這完全是不對的說法,
其實是否能完全防止sql語句,在於你是怎樣用 的,比如說,我們把所有的輸入參數,都經過轉義后,才拼接到sql語句中,如果是用prepare,我們把所有輸入參數都放在execute中,而不是拼接在prepare時,如此就能有效的防范sql注入,
其實關於網上說pdo能夠防止sql注入,這句話應該這樣說,pdo能夠提供給更好的方法來防止sql注入。
其他鏈接數據庫方式,只要做好輸入字段的轉義工作,也一樣能夠有效的防止sql的注入
其實所謂字段的轉義工作,在sql語句里面,可以參照於pdo的quote方法,吧所有輸入字段都當做字符串的輸出,並且對所有引號進行轉義,這樣就能有效的防止,sql語句的注入。
3.對整個sql語句進行直接轉義。
也許你回這樣想,直接對整個sql語句進行轉義,這樣就開發者就不用單獨提出所輸入的字段了,也許你沒這樣想過,但至少我這樣想過,但是這種方式是不對的,如下
這里就不以腳本的形式表現了,直接是sql語句形式
SELECT * from user where name = /"zh/"angyan/"
如果是對整個sql語句進行直接轉義,最終發送給mysql的就是這樣一句sql。
可以執行下,就知道,失敗。
因為第一次轉義和第二次轉義的",正好會完成引號的配對,這樣后面的字符就不是一種字符串方式了,在此之前,sql語句已經被截斷,也就是說這種方式,是不會解決sql注入的。
最后總結一句:想從根本上解決sql注入,其實在於開發者的個人意識,根本上說什么框架不能完美的解決這個問題,即使是從框架方法解決,開發者也必須要把輸入數據按照框架的約定放在我特定的規則里面,才能完美的解決sql注入隱患。