如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 DevTech Ascendancy Hub
像是 su
、sudo
這種個指令允許我們切換使用者,而 login
這個系統元件負責控制使用者存取… 這些會涉及核心如何切換使用者
更改使用者 ID 一般可以透過以下兩種方式(setuid
的行為由核心負責完成切換)
檔案為 setuid
權限
有些可執行檔的執行位元是
s
(一般為x
),表示在執行時會以 檔案擁有者的身份去執行,而非當前的用戶去執行
像是 passwd
命令就有 setuid
權限
請看下圖左邊
-rwsr-xr-x
中的s
,這表示了passwd
命令有setuid
權限
setuid
檔案呼叫系統設定 setuid()
函數
可用 setuid()
函數來處理與程序相關連的所有使用者 ID(之後在詳細介紹)
setuid()
規範
setuid()
規範由核心定義,大多以 root
使用者身份才能呼叫 setuid()
;如果不已 root
身份呼叫 setuid()
,那會有部份限制
大多數情況下都只接受
root
使用者呼叫
setuid
這個系統呼叫(System call)調整的是 euid
(所有者)
Linux 核心透過 setuid
程序核相關系統呼叫來處理使用者切換(還有相關檔案的存取權限),如果沒有注意,可能會導致安全性問題,常出現的問題如下
檔案如果有 s
顯示,那該檔案將會有 setuid
的權限,會幫普通使用者提權
如果你建立了一個 shell 並且
setuid
權限為 root,那普通使用者執行時就可以執行它來獲得整個系統的控制權
程式功能面問題
如果你的程式需要 setuid
為 root
才可以啟動(使用 sudo
),如果程式出現 Bug 那很可能會導致系統損壞
大多數時候提及的使用者 ID 都是「簡化過」的,實際上每個程序都有 超過一個 UID,(或是應該說,UID 其實是有多種不同含義的) UID 有分為以下幾種,如下表…
UID 種類 | 說明 | 補充 |
---|---|---|
Effective UID (euid ) |
Effective UID 是用於權限檢查的用戶身份。當程序執行時,Effective UID 獲得了 Real UID 的權限,並可能根據需要被臨時修改(例如使用 setuid) | 執行者,也就是一般情況下我們所說的 UID |
Real UID (ruid ) |
Real UID 是程序「執行」的實際用戶身份 | 所有者,可以用來對程序發送訊號(像是中止) |
Saved UID (suid ) |
已保存 UID | - |
File system UID (fsuid ) |
fsuid 是Linux特有的使用者ID,用於檔案系統權限檢查 | 通常情況下,進程的檔案系統使用者ID(fsuid)與其有效使用者ID(euid)相同 |
從這裡我們可以看到 Unix 將應用的各個不同功能做了權限的區分,像是「設定」、「執行」… 等等權限分離
這麽多 UID 要幹麻?
簡單來說為了 方邊控制,想想如果沒有 UID 的改變,那我們在啟動程式後需要中止(或是資源修改),就會需要不斷的使用 sudo
切換
詳細可看
man 2 setuid
手冊
如果我們是切換使用者執行程式(使用到 setuid
)時,Linux 會將當前用戶的 Effective UID
設定為檔案的 Effective UID
(ruid 不會改變)
root 用戶使用執行應用,而應用中使用到
setuid
函數會將實際用戶 ID(ruid
)、有效用戶 ID(euid
)、保存用戶 ID(suid
)設定為 root 用戶 ID
一般用戶使用執行應用,而應用中使用到 setuid
一般用戶執行 setuid
只會將有效用戶 ID(euid
)設定為當前用戶 ID
一般情況下 euid
, ruid
會被設定為相同,可用以下命令查看
「使用者標示、認證」通常是指在使用者空間中的應用程序或程式庫使用的功能,用於識別和驗證使用者的身份
多使用者系統必須支援 使用者標識、使用者認證,像 Ubuntu 就是可以擁有多個使用者一起使用的系統,所以需要 驗證不同的使用者
支援功能 | 說明 |
---|---|
使用者「標識」(identification ) |
判斷是哪位使用者(Linux 核心透過使用者 EUID 來管理程序、檔案權限),並可透過 setuid 來切換 |
使用者「認證」(authentication ) |
驗證是否是宣稱的使用者 |
核心並不關心使用者空間有關認證的事項(eg. 使用者名稱、密碼);核心只保存資料,而驗證是應用端的規範、應用
傳統的 Unix 會經過以下步驟(概略)來獲取使用者名稱(不包括密碼比對)
程序透過 系統呼叫 geteuid()
,取得核心返回的 euid
開啟、讀取 /etc/passwd
檔案
解析欄位,並使用切割的第三個項目來作為使用者 ID(EUID)
匹配成功後獲取第一個項目作為使用者名稱
由於使用者名稱的獲取是有固定步驟,所以 Unix 有提供一個標準函數庫供我們使用,簡化步驟如下
程序透過 系統呼叫 geteuid()
,取得核心返回的 euid
程序可以使用函數庫的 getpwuid
函數來獲取與該使用者 ID 相關聯的使用者記錄,其中包括使用者名稱
這裡說明的函數並「不包括密碼」的驗證 (/etc/passwd
);傳統的密碼驗證有以下 侷限
密碼協定、權限
加密協定並 沒有系統等級的標準
比對密碼的前提是 你需要對加密密碼有存取權限
傳統驗證會假定
假定每當使用者需要存取資源時都需輸入使用者名稱、密碼驗證
假定是使用輸入密碼,無法接受指紋識別、人臉驗證(也就是生物識別技術),如果需要則須自己使用插件做功能支援
為了提高使用者驗證的靈活性,Sun 公司在 1995 年提出了一個 新標準 PAM (Pluggable Authentiation Module
)
PAM可以被視為「使用者標示、認證」方面的一個應用… PAM 是一個用於管理系統身份驗證「框架」,在許多 Unix-like 系統中被廣泛使用
PAM 是共享的驗證函式庫,使用者被移交給 PAM 來決定使用者的驗證方式,這 方便於插入新的驗證方式(其靈活性很高),並且也提供一些驗證控制服務
驗證函式庫由
Open source software foundation
提出
PAM 的設定檔通常存放在 /etc/pam.d
目錄下(也可能在 /etc/pam.conf
檔案中)
我們來看 /etc/pam.d/chsh
的內容;在註解中我們可以看到:它只允許使用者使用 /etc/shells
中的 Shell
設置欄位(左到右) | chsh 設置 | 說明 |
---|---|---|
功能類型 | auth |
某個使用者應用程式請求 PAM 執行的「驗證」任務;以當前來說是 auth 驗證任務 |
控制參數 | required |
任務失敗時的操作;required 表示如果這個模組的執行失敗,則整個認證過程將被視為失敗(也就是 驗證是必須的操作) |
模組 | pam_shells.so |
可插拔的驗證模組;以當前來說 pam_shells.so 模組檢查使用者 Shell 是否在 /etc/shells 中 |
man 5 pam.conf
手冊查看我們在更近一步認識每一個欄位可以設定的數值
功能類型:主要有以下幾類
通常我們會結合 功能類型、模組 來確定該行的功能
功能類型 | 說明 | 補充 |
---|---|---|
auth |
驗證使用者身份 | - |
account |
檢查使用者帳號狀態 | eg. 使用者是否有操作的權限 |
session |
僅在使用者目前程序內執行 | eg. 顯示當日訊息 |
password |
用來更改使用者密碼、其他驗證資訊 | - |
控制參數者:有分為 簡單語法、高級語法,簡單語法有如下幾種
控制參數 | 成功後操作 | 失敗後操作 |
---|---|---|
sufficient |
驗證就成功,PAM 會忽略其他規則 | PAM 繼續執行其他規則 |
requisite |
PAM 會繼續執行其他規則 | 驗證失敗,忽略其他 PAM 規則 |
required |
PAM 繼續執行其他規則 | PAM 繼續執行其他規則,但最終仍會驗證失敗! |
高級語法是使用方括號 []
表示,它可以根據模組的回傳值手動定義相應的操作
可查看
man -5 pam.conf
手冊
PAM 的驗證說可堆疊的規則,範例如下
堆疊規則後的驗證順序如下圖所示
模組參數:PAM 模組就是運行的函數,使用時也可以帶入參數
模組查詢:可使用以下指令查看 PAM 相關使用模組的文檔
/etc/pam.d/other
檔案:沒有設定檔的程式會套用 other
的規則
@include
語法用來載入整個設定檔(以可以使用控制參數來載入某個特定功能的設定檔)首先提及 /etc/shadow
檔案:
檔案 /etc/login.defs
它是 /etc/shadow
檔的設定值,其中包含了用於 shadow 密碼檔案加密算法的資訊
login.defs
的功能?
login.defs
的功能 已經漸漸被 PAM 取代,不過仍有作用,如果在系統不支援 PAM 時,就會去使用 login.defs
的功能
PAM 如何獲得密碼加密資訊?
PAM 處理密碼是透過,功能類型的 auth
& password
兩個功能去驗證;如果要查看密碼設定可以使用以下命令
解釋如下
功能參數:password
這表示這個設定行用於密碼驗證步驟
控制參數:[success=1 default=ignore]
這是一個控制指令,用於指定驗證模組的執行流程
success=1
:表示如果這個模組成功驗證了密碼,則跳過下一個成功的模組
default=ignore
:表示如果這個模組不符合執行條件,則忽略它,並繼續執行下一個模組
模組:pam_unix.so
這是實際執行密碼驗證的 PAM 模組的名稱,並帶入以下參數
obscure
:這是 pam_unix.so
模組的一個參數,用於指定密碼的複雜性要求
yescrypt
:這是 pam_unix.so
模組的另一個參數,用於指定密碼的加密方法
目前看起來,PAM 並不知道要使用哪個算法驗證,猜測是按照一訂的規則去一次嘗試解開,這也是它「框架」給予的部分自由度