2008-06-11

MySQL 權限問題的雷

MySQL 的權限判斷我想大家應該都有概念, 稍微提一下:

  1. 判斷 mysql.user(也是控制 ID/PW, 另外一些系統操作權限也在這理, 還有相關權限設定後就可以控制整個 mysql 的所有DB...)
  2. 判斷 mysql.db, 這裡可以控制哪個 host -> db -> user(判斷順序) 可以有哪些權限
  3. 判斷 mysql.host, 大多搭配 2. 使(我目前沒用到)
  4. 判斷 mysql.table_priv, 再細一步劃分哪個 host -> user -> table 可以做什麼操作
  5. mysql.column_priv, (我目前沒用到)
其實這次的雷簡單來說就是兩個點
  1. MySQL 權限判斷的順序
  2. 排序比對應先判斷最特定值,最後判斷不特定值(但是我測試出來結果似乎不是這樣)
可以確定的就是"在判斷權限時,前面如果有比對的到的資料就會直接忽略後面的權限設定"

但是我很不解的地方在於,Document 說會先根據最"實體", 再根據最不實體, 所以理論上像是 192.168.1.1 應該比 192.168.1.0/255.255.255.0 實體, 但事實上似乎不是

我先節錄一些參考資料(MySQL doc)給大家看看:

db和host表在伺服器啟動時被讀取和排序(同時它讀user表)。db表在Host、Db和User範圍字段上排序,並且host表在Host和Db 範圍字段上排序。對於user表,排序首先放置最特定的值然後最後最不特定的值,並且當伺服器尋找匹配入條目時,它使用它找到的第一個匹配。

user 、db 及 host 資料表在伺服器啟動時就會被讀入及排序
User資料表依Host、User 排序
db 資料表依 Host、Db及 User 排序
host 資料表會依 Host 及 Db 排序

dbhost表授予數據庫特定的權限。在這 些表中的範圍列的值可以採用以下方式:

  • 通配符字符%_可 用於兩個表的HostDb列。它們與用LIKE操作符執行的模式匹配 操作具有相同的含義。如果授權時你想使用某個字符,必須使用反斜現引用。例如,要想在數據庫名中包括下劃線(_), 在GRANT語句中用\_來指定
  • db表的'%'Host值意味著「任 何主機」,在db表中空Host值意味著「對進一步的信息諮詢host表」 (本節後面將描述的一個過程)。
  • host表的'%'或空Host值 意味著「任何主機」。
  • 在兩個表中的'%'或空Db值意味著 「任何數據庫」。
  • 在兩個表中的空User值 匹配匿名用戶。

dbhost表在服務器啟動時被讀取並排序(同 時它讀user)db表在HostDbUser範 圍列上排序,並且host表在HostDb範圍列上排序。對於user表, 首先根據最具體的值最後根據最不具體的值排序,並且當服務器尋找匹配條目時,它使用它找到的第一匹配。

參考網站如下:
(中文)
http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html#request-access
http://www.sy3es.tnc.edu.tw/teaching/php_mysql/mysql.htm

底下可能有點混亂,是我測試的例子:

假設原本的 mysql.db 內容如下(cvs type):

"192.168.1.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"192.168.2.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"192.168.1.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"192.168.2.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"192.168.3.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"192.168.4.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"

前面兩個 IP 是 指定 Server 的 IP, 後面是我們針對我們各個 ISP 的網段(也就是自家機器都至少開給 SELECT table 的權限)

當我新增兩筆資料在 mysql.db 後, 它的資料排序會像底下的樣子

"168.95.1.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.2.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.3.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.1.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.2.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.3.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.4.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.4.100";"my_db";"myaccount";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"

一切看起來都正確, 然後下指令更新 DB: Flush PRIVILEGES

問題來了, 在 168.95.4.100 上就會出現
mysql> UPDATE your_table SET seq='10' WHERE id=6;
ERROR 1142 (42000): UPDATE command denied to user 'my_account'@'168.95.4.100' for table 'your_table'

這個問題我嘗試了一整天,懷疑該不會是真的有順序問題, 然後請小白幫我看,小白研究一下將168.95.1.100直接 update 成 168.95.4.100那筆, 然後再新增一筆168.95.1.100的權限資料,
結果 168.95.4.100就可以 update, 但是後來再加的168.95.1.100變成 不能 update table 了!!

後來用同樣的手法再把 168.95.1.100 改回去, 讓它恢復正常, 於是確定了的確會有順序判比對上的問題, 接著就以手動加一筆改一筆的方式讓 mysql.db 變成底下的排序

"168.95.1.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.2.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.3.100";"my_db";"my_account";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.4.100";"my_db";"myaccount";"Y";"Y";"Y";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.1.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.2.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.3.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"
"168.95.4.0/255.255.255.0";"my_db";"my_account";"Y";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N";"N"

目前兩邊都可以正常 update,

這個排序目前沒摸透的就是它的邏輯,似乎是 insert 時就決定好的(通常會在最後面,但是也有發現不會到最後面的, 像168.95.3.100那筆就會跑到前面,168.95.4.100就一直在最後,不管砍掉重現幾次都一樣)

沒有留言: