一直在用mysql數據庫報錯注入方法,但爲什麼會報錯?javascript
百度谷歌知乎了一番,發現你們都是把官網的結論發一下截圖,而後執行sql語句證實一下結論,可是沒有人去深刻研究爲何rand不能和order by一塊兒使用,也沒完全說明三者同時使用報錯的原理。java
select count(*),(floor(rand(0)*2))x from information_schema.tables group by x; 這是網上最多見的語句,目前位置看到的網上sql注入教程,floor 都是直接放count(*) 後面,爲了排除干擾,咱們直接對比了兩個報錯語句,以下圖mysql
由上面的圖片,能夠知道報錯跟位置無關。sql
是否是報錯語句有了floor(rand(0)*2)以及其餘幾個條件就必定報錯?其實並非如此,咱們先建建個表,新增一條記錄看看,以下圖:數據庫
確認表中只有一條記錄後,再執行報錯語句看看,以下圖:測試
屢次執行均未發現報錯。this
而後咱們新增一條記錄。3d
而後再測試下報錯語句orm
屢次執行並無報錯blog
OK 那咱們再增長一條
執行報錯語句
ok 成功報錯
由此可證實floor(rand(0)*2)報錯是有條件的,記錄必須3條以上,並且在3條以上一定報錯,到底爲什麼?請繼續往下看。
爲了更完全的說明報錯緣由,直接把隨機因子去掉,再來一遍看看,先看一條記錄的時候,以下圖:
一條記錄的話 不管執行多少次也不報錯
而後增長一條記錄。
兩條記錄的話 結果就變成不肯定性了
隨機出現報錯。
而後再插入一條
三條記錄以後,也和2條記錄同樣進行隨機報錯。
因而可知報錯和隨機因子是有關聯的,但有什麼關聯呢,爲何直接使用rand(),有兩條記錄的狀況下就會報錯,並且是有時候報錯,有時候不報錯,而rand(0)的時候在兩條的時候不報錯,在三條以上就絕對報錯?咱們繼續往下看。
前面說過,floor(rand(0)*2)報錯的原理是偏偏是因爲它的肯定性,這究竟是爲何呢?從0x03咱們大體能夠猜測到,由於floor(rand()*2)不加隨機因子的時候是隨機出錯的,而在3條記錄以上用floor(rand(0)*2)就必定報錯,由此可猜測floor(rand()*2)是比較隨機的,不具有肯定性因素,而floor(rand(0)*2)具有某方面的肯定性。
爲了證實咱們猜測,分別對floor(rand()*2)和floor(rand(0)*2)在多記錄表中執行屢次(記錄選擇10條以上),在有12條記錄表中執行結果以下圖:
連續3次查詢,毫無規則,接下來看看select floor(rand(0)*2) from `T-Safe`;,以下圖:
能夠看到floor(rand(0)*2)是有規律的,並且是固定的,這個就是上面提到的因爲是肯定性才致使的報錯,那爲什麼會報錯呢,咱們接着往下看。
使用select count(*) from `T-Safe` group by x;這種語句的時候咱們常常能夠看到下面相似的結果:
能夠看出 test12的記錄有5條
與count(*)的結果相符合,那麼mysql在遇到select count(*) from TSafe group by x;這語句的時候到底作了哪些操做呢,咱們果斷猜想mysql遇到該語句時會創建一個虛擬表(實際上就是會創建虛擬表),那整個工做流程就會以下圖所示:
2.開始查詢數據,取數據庫數據,而後查看虛擬表存在不,不存在則插入新記錄,存在則count(*)字段直接加1,以下圖:
由此看到 若是key存在的話就+1, 不存在的話就新建一個key。
那這個和報錯有啥內在聯繫,咱們直接往下來,其實到這裏,結合前面的內容你們也能猜個一二了。
其實mysql官方有給過提示,就是查詢的時候若是使用rand()的話,該值會被計算屢次,那這個「被計算屢次」究竟是什麼意思,就是在使用group by的時候,floor(rand(0)*2)會被執行一次,若是虛表不存在記錄,插入虛表的時候會再被執行一次,咱們來看下floor(rand(0)*2)報錯的過程就知道了,從0x04能夠看到在一次多記錄的查詢過程當中floor(rand(0)*2)的值是定性的,爲011011…(記住這個順序很重要),報錯實際上就是floor(rand(0)*2)被計算屢次致使的,具體看看select count(*) from TSafe group by floor(rand(0)*2);的查詢過程:
1.查詢前默認會創建空虛擬表以下圖:
2.取第一條記錄,執行floor(rand(0)*2),發現結果爲0(第一次計算),查詢虛擬表,發現0的鍵值不存在,則floor(rand(0)*2)會被再計算一次,結果爲1(第二次計算),插入虛表,這時第一條記錄查詢完畢,以下圖:
3.查詢第二條記錄,再次計算floor(rand(0)*2),發現結果爲1(第三次計算),查詢虛表,發現1的鍵值存在,因此floor(rand(0)*2)不會被計算第二次,直接count(*)加1,第二條記錄查詢完畢,結果以下:
4.查詢第三條記錄,再次計算floor(rand(0)*2),發現結果爲0(第4次計算),查詢虛表,發現鍵值沒有0,則數據庫嘗試插入一條新的數據,在插入數據時floor(rand(0)*2)被再次計算,做爲虛表的主鍵,其值爲1(第5次計算),然而1這個主鍵已經存在於虛擬表中,而新計算的值也爲1(主鍵鍵值必須惟一),因此插入的時候就直接報錯了。
5.整個查詢過程floor(rand(0)*2)被計算了5次,查詢原數據表3次,因此這就是爲何數據表中須要3條數據,使用該語句纔會報錯的緣由。
由0x05咱們能夠一樣推理出不加入隨機因子的狀況,因爲沒加入隨機因子,因此floor(rand()*2)是不可測的,所以在兩條數據的時候,只要出現下面狀況,便可報錯,以下圖:
最重要的是前面幾條記錄查詢後不能讓虛表存在0,1鍵值,若是存在了,那不管多少條記錄,也都沒辦法報錯,由於floor(rand()*2)不會再被計算作爲虛表的鍵值,這也就是爲何不加隨機因子有時候會報錯,有時候不會報錯的緣由。如圖:
當前面記錄讓虛表長成這樣子後,因爲無論查詢多少條記錄,floor(rand()*2)的值在虛表中都能找到,因此不會被再次計算,只是簡單的增長count(*)字段的數量,因此不會報錯,好比floor(rand(1)*2),如圖:
在前兩條記錄查詢後,虛擬表已經存在0和1兩個鍵值了,因此後面再怎麼弄仍是不會報錯。
總之報錯須要count(*),rand()、group by,三者缺一不可。
上一頁