基於約束的SQL攻擊
前言
值得慶幸的是如今開發者在構建網站時,已經開始注重安全問題了。絕大部分開發者都意識到SQL注入漏洞的存在,在本文我想與讀者共同去探討另一種與SQL資料庫相關的漏洞,其危害與SQL注入不相上下,但卻不太常見。
接下來,我將為讀者詳細展示這種攻擊手法,以及相應的防禦策略。
注意:本文不是講述SQL注入攻擊
背景介紹
最近,我遇到了一個有趣的代碼片段,開發者嘗試各種方法來確保資料庫的安全訪問。當新用戶嘗試註冊時,將運行以下代碼:
0) { // User exists, exit gracefully
.
.
} else { // If not, only then insert a new entry
$query = "INSERT INTO users(username, password)
VALUES ("$username","$password")";
.
.
}
}
使用以下代碼驗證登錄信息:
0){
$row = mysql_fetch_assoc($res); return $row["username"];
}
}return Null;
安全考慮:
過濾用戶輸入參數了嗎? — 完成檢查
使用單引號(』)來增加安全性了嗎? — 完成檢查
按理說應該不會出錯了啊?
然而,攻擊者依然能夠以任意用戶身份進行登錄!
攻擊手法
在談論這種攻擊手法之前,首先我們需要了解幾個關鍵知識點。
在SQL中執行字元串處理時,字元串末尾的空格符將會被刪除。
換句話說「vampire」等同於「vampire 」,對於絕大多數情況來說都是成立的(諸如WHERE子句中的字元串或INSERT語句中的字元串)例如以下語句的查詢結果,與使用用戶名「vampire」進行查詢時的結果是一樣的。
SELECT * FROM users WHERE username="vampire ";
但也存在異常情況,最好的例子就是LIKE子句了。
注意,對尾部空白符的這種修剪操作,主要是在「字元串比較」期間進行的。這是因為,SQL會在
內部
使用空格來填充字元串,以便在比較之前使其它們的長度保持一致。
在所有的INSERT查詢中,SQL都會根據varchar(n)來限制字元串的最大長度。也就是說,如果字元串
的長度大於「n」個字元的話,那麼僅使用字元串的前「n」個字元。
比如特定列的長度約束為「5」個字元,那麼在插入字元串「vampire」時,實際上只能插入字元串的前5個字元,即「vampi」。
現在,讓我們建立一個測試資料庫來演示具體攻擊過程。
vampire@linux:~$ mysql -u root -p
mysql> CREATE DATABASE testing;Query OK, 1 row affected (0.03 sec)mysql> USE testing;Database changed
接著創建一個數據表users,其包含username和password列,並且欄位的最大長度限制為25個字元。然後,我將向username欄位插入「vampire」,向password欄位插入「my_password」。
mysql> CREATE TABLE users (
-> username varchar(25),
-> password varchar(25)
-> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO users
-> VALUES("vampire", "my_password");
Query OK, 1 row affected (0.11 sec)
mysql> SELECT * FROM users;
+----------+-------------+
| username | password |
+----------+-------------+
| vampire | my_password |
+----------+-------------+1 row in set (0.00 sec)
為了展示尾部空白字元的修剪情況,我們可以鍵入下列命令:
mysql> SELECT * FROM users
-> WHERE username="vampire ";+----------+-------------+| username | password |+----------+-------------+| vampire | my_password |+----------+-------------+1 row in set (0.00 sec)
現在我們假設一個存在漏洞的網站使用了前面提到的PHP代碼來處理用戶的註冊及登錄過程。為了侵入任意用戶的帳戶(在本例中為「vampire」),只需要使用用戶名「vampire[許多空白符]1」和一個隨機密碼進行註冊即可。
對於選擇的用戶名,前25個字元應該只包含vampire和空白字元,這樣做將有助於繞過檢查特定用戶名是否已存在的查詢。
mysql> SELECT * FROM users
-> WHERE username="vampire 1";
Empty set (0.00 sec)
需要注意的是,在執行SELECT查詢語句時,SQL是不會將字元串縮短為25個字元的。因此,這裡將使用完整的字元串進行搜索,所以不會找到匹配的結果。接下來,當執行INSERT查詢語句時,它只會插入前25個字元。
mysql> INSERT INTO users(username, password)
-> VALUES ("vampire 1", "random_pass");
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql> SELECT * FROM users
-> WHERE username="vampire";
+---------------------------+-------------+
| username | password |
+---------------------------+-------------+
| vampire | my_password |
| vampire | random_pass |
+---------------------------+-------------+2 rows in set (0.00 sec)
很好,現在我們檢索「vampire」的,將返回兩個獨立用戶。注意,第二個用戶名實際上是「vampire」加上尾部的18個空格。
現在,如果使用用戶名「vampire」和密碼「random_pass」登錄的話,則所有搜索該用戶名的SELECT查詢都將返回第一個數據記錄,也就是原始的數據記錄。這樣的話,攻擊者就能夠以原始用戶身份登錄。
這個攻擊已經在MySQL和SQLite上成功通過測試。我相信在其他情況下依舊適用。
防禦手段
毫無疑問,在進行軟體開發時,需要對此類安全漏洞引起注意。我們可採取以下幾項措施進行防禦:
將要求或者預期具有唯一性的那些列加上UNIQUE約束。實際上這是一個涉及軟體開發的重要規則,即使你的代碼有維持其完整性的功能,也應該恰當的定義數據。
由於』username』列具有UNIQUE約束,所以不能插入另一條記錄。將會檢測到兩個相同的字元串,並且INSERT查詢將失敗。
最好使用』id』作為資料庫表的主鍵。並且數據應該通過程序中的id進行跟蹤
為了更加安全,還可以用手動調整輸入參數的限制長度(依照資料庫設置)
*參考來源:
dhavalkapil
,FB小編鳶尾編譯,轉載請註明來自FreeBuf(FreeBuf.COM)
※國際航空訂票系統存在漏洞,可輕易取消、修改航班預約
※揭秘:Signal通訊加密APP究竟是如何避開審查的
TAG:FreeBuf |
※法官裁決 GNU GPL 是有約束力的合同
※當均值-CVaR模型遇上現實約束
※完善強化學習安全性:UC Berkeley提出約束型策略優化新演算法
※工信部:將統一Android消息推送標準 約束流氓App
※歐盟擬通過立法來約束蘋果和Google的壟斷
※高速PCB設計軟體allegro16.6版本約束管理界面講解
※Oracle外鍵約束之在創建表時設置外鍵約束
※約束理論TOC在生產管理中的應用
※EXO中國成員現狀:鹿晗最成功?亦梵谷冷不討好,Wuli韜韜潛力股,小綿羊合約束縛常潛水
※EAST首次獲得百秒量級穩態高約束模等離子體
※P.A.WORKS發表全新劇場版動畫《さよならの朝に約束の花をかざろう》製作消息,著名腳本家「岡田麿里」首次執導作品!
※Chloé 2017 早秋系列,打造不受約束的女孩。
※走進聚變反應堆的內部:GIF圖演示利用磁場約束等離子體
※資料庫的三大範式以及五大約束
※行業發展關鍵,VR是否需要道德規範來約束?
※口語對話:約束ね
※來自紐約布朗區的時尚走咖 隨性不約束
※尹天照喜好自由不愛合約束縛 否認與Tvb簽約
※798:一塊生於約束的廢鐵