當前位置:
首頁 > 新聞 > 基於約束的SQL攻擊

基於約束的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)



您的贊是小編持續努力的最大動力,動動手指贊一下吧!


本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊下面的「搶先收到最新資訊」瀏覽吧!



請您繼續閱讀更多來自 FreeBuf 的精彩文章:

國際航空訂票系統存在漏洞,可輕易取消、修改航班預約
揭秘: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:一塊生於約束的廢鐵