今天還是和往常一樣看着微信推的訂閱号文章
有一篇 select * from user where uersname=0引起了我的思考
其實這個問題是MySQL隐式轉化整理存在的安全問題
網上一搜比較多,我這裡就參考師傅們寫的文章進行總結和學校
官方給的解釋:
MySQL 的隐式類型轉換原則:
– 兩個參數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會傳回 1,這兩種情況都不需要做類型轉換
– 兩個參數都是字元串,會按照字元串來比較,不做類型轉換
– 兩個參數都是整數,按照整數來比較,不做類型轉換
– 十六進制的值和非數字做比較時,會被當做二進制串,和數字做比較時會按下面的規則處理
– 有一個參數是 TIMESTAMP 或 DATETIME,并且另外一個參數是常量,常量會被轉換為 timestamp
– 有一個參數是 decimal 類型,如果另外一個參數是 decimal 或者整數,會将整數轉換為 decimal 後進行比較,如果另外一個參數是浮點數,則會把 decimal 轉換為浮點數進行比較
– 所有其他情況下,兩個參數都會被轉換為浮點數再進行比較
注意一個安全問題:假如 password 類型為字元串,查詢條件為 int 0 則會比對上。
在這裡我就隻是總結用法,詳細的原理下面會給出師傅們連結。防止重複造輪子
在一般的網站登入的使用者名和密碼都是varchar類型
這樣就可能存在安全問題(下面讨論就是比較經典,師傅們可以自由發揮好)
select * from user where uersname=$_POST['username']
user表有
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin1 | 12345 |
| 2 | admin2 | 123 |
| 3 | admin3 | 321 |
+----+----------+----------+
我們就可以直接利用payload:
select * from user where uersname=0
進行查詢
MariaDB [test]> select * from user where username=0;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin1 | 12345 |
| 2 | admin2 | 123 |
| 3 | admin3 | 321 |
+----+----------+----------+
原因就是上面說的進行了隐式轉化 username是varchar類型,但是查詢的時候使用了0(int)類型
這樣username的值就進行了隐式轉化成0,剛剛好0=0,就查詢出來了全部
MariaDB [test]> select "admin"=0;
+-----------+
| "admin"=0 |
+-----------+
| 1 |
+-----------+
#這樣我們就可以嘗試新方法的萬能密碼
但是如果username字段裡面的值不能字母開頭的是數字開頭的那就不能進行萬能密碼
MariaDB [test]> select "1213admin"=0;
+---------------+
| "1213admin"=0 |
+---------------+
| 0 |
+---------------+
總結:
0. 從上面的例子可以看出,當把字元串轉為數字的時候,其實是從左邊開始處理的。
- 如果字元串的第一個字元就是非數字的字元,那麼轉換為數字就是0
-
如果字元串以數字開頭
2.1 如果字元串中都是數字,那麼轉換為數字就是整個字元串對應的數字
2.2 如果字元串中存在非數字,那麼轉換為的數字就是開頭的那些數字對應的值
參考
https://www.cnblogs.com/rollenholt/p/5442825.html