天天看點

MySQL的權限排序問題MySQL的權限排序問題

實驗:因權限表具有通配符,對權限進行排序後,比對時引來的問題。

授權表中的通配符

user表中user為空值表示比對任意user name,也表示匿名使用者。

user表中host部分使用者可以使用通配符”%”和”_”在host name或者ip位址中,這些具有和模式比對like相同的意義。

db表中,host、user與user表中表示方法一緻,同時db列也可以具有通配符。

tables_priv、columns_priv和procs_priv表中,隻有host列可以具有通配符。

由于具有通配符,這就會發生一個使用者連接配接server可以比對多個賬戶的事情發生。例如建立了賬戶’’@localhost和’yz’@’%’,當使用者’yz’@localhost登入時兩個賬戶都可以比對。這樣就面臨着選擇哪一個賬戶作為登入賬戶的問題。mysql為解決這個問題,對user表中的記錄做了排序。排序方法如下:

先按最具體的(most-specific)host值排序。原義的host_name和ip位址算是最具體的(ip位址的具體級别specificity是不受子網路遮罩影響的,192.168.1.13和192.168.1.0/255.255.255.0被認為是同一具體級别)。比對符’%’算是最不具體的級别。空字元’’也表明任意host,但排在’%’後面。有相同host值的行首先以最具體的user值排序(空user值意味着“任何使用者”并且是最不具體的)。對于具有相同具體級别的host和user值,排序是不确定。

采用上述方法,當’yz’@localhost登入時,比對的就是賬号’’@localhost。如果用用賬戶’yz’@’%’的密碼試圖登入,可能會被告知access denied for user 'yz'@'localhost',因為mysql選取的登入賬戶是’’@localhost。

不過mysql也比較奇怪,登入後使用select user()發現

| user()       |

| yz@localhost |

使用show grants;可以看到下面結果,賬戶是’’@localhost。

| grants for @localhost            |

| grant usage on *.* to ''@'localhost'  |

| grant create on `privtest`.* to ''@'localhost' |

賬戶行為還好,不會引起太大的坑。db中的排序不注意可能就會導緻mysql結果不一緻,使用者權限可能‘丢失’,導緻使用者無法正常工作,服務故障。

db表在host、db和user範圍列上排序,也是按照具體到不具體排序,而且比對到第一條符合的記錄後,就傳回。首先其排序是不穩定排序,這會導緻插入一條不相關的記錄,導緻其他記錄排序變化,權限表現變化,部分原有權限‘丢失’。即使是穩定排序,也會導緻邏輯上應該有的權限沒有,例如

grant select on aaa.* to yz@localhost;

grant create on `aa%` to yz@localhost;

grant insert on `aaa%` to yz@localhost;

       mysql在做權限檢查時,隻會傳回比對到的第一條記錄,即使用者yz@localhost對aaa資料庫隻有select權限,不會有create和insert權限。從這個角度講即使排序穩定,插入新的權限資訊也可能會導緻之前的權限‘丢失’。

相關知識:

1、mysql的權限驗證有global,db,table,column多個緯度。

2、在global和db緯度中,mysql按内部權重,從大到小讀取所有授權,擷取第一個比對(權重最大的)的作為内部授權驗證。

3、db緯度的權重計算方法如下:

    3.1 分别按照hostname,dbname,username計算。

    3.2 單個字元串若不存在通配符權重為0x80,若存在通配符,則權重為第一個通配符出現的位置,最大為0x7f

    3.3 舉例 grant create on `tt_`.* to 'tt'@‘%’ 這條授權的權重為0x010380,其中’%’為0x01 ’tt_’為0x03 ’tt’為0x80

4、目前mysql内部大部分排序采用快速排序,這是一種不穩定的排序算法。

實驗:mysql在db層驗證權限時,是否會對db中所有賬戶權限資訊都做逐一比對。

結論:從效果上mysql會逐一比對db表中的資訊,遇到能比對的就傳回,導緻擁護show grants的權限資訊可能與實際權限不一緻。(table層也是這樣)

mysql排序先後為host、db、user,前面user表在比對時會發生比對多條記錄,那麼在db層比對時,同時可比對的賬戶是否也會在db層發生比對。實驗:

同時建立

’yz’@’%’和’yz’@localhost賬号。

對’yz’@’%’賦予權限:

grant create on yzdb to 'yz'@'%';

登入yz@localhost,執行下面語句,可以看到權限資訊僅usage。這個時候試着建立database yzdb,會發現其具有建立yzdb的權限。

mysql> show grants;

| grants for yz@localhost                |

| grant usage on *.* to 'yz'@'localhost' |

mysql> create database yzdb;

query ok, 1 row affected (0.02 sec)

當撤銷'yz'@'%'的建立yzdb權限,'yz'@'localhost'也會失去該權限。

在測試中,’’@localhost賬戶不會擁有'yz'@'%'的上述權限。在這裡比對時,’yz’不等同于’’。

上述情況也會産生權限‘丢失’問題,show grants中有的權限可能因為其他賬戶授權資訊引發‘丢失’。

繼續閱讀