# Linux Auth ## 在 Windows 中模擬 Linux 環境進行練習 * 使用 Docker 搭建 Linux 容器環境 * 安裝 Docker Desktop(支援 Windows 10 以上) * 使用指令快速啟動 Ubuntu 容器:`docker run -it --rm ubuntu` * 容器內可自由操作 Linux 指令,離開即清除環境 * 適合安全地練習權限變更、不怕破壞系統 ![image](https://hackmd.io/_uploads/HySfccfQel.png) ## Linux 權限教學文章大綱 ### 一、前言 一直以來在使用 Linux 時,只有熟悉那些常常用到的指令,例如 `cp` `mv` `rm` `ll` 這些,知道 `ll` 最前面有一串奇怪的字串是權限,但是從來沒有了解他到底在做什麼 直到最近專案上線,很多鬼故事發生,在某些環境中,原本可以使用的指令,都突然出現 `permission denied` Damn,到底是誰動了我的東西,怎麼以前可以的指令現在不行了。 一切都是權限在搞事,要想辦法弄回來。 所以...還是好好了解一下吧... #### 為什麼權限管理在 Linux 中很重要? Linux 是一個多使用者、多工的作業系統,權限管理是其核心安全機制。良好的權限管理能夠: - **保護系統安全**:防止惡意或意外的檔案修改、刪除 - **確保資料隱私**:控制哪些使用者可以存取敏感資訊 - **維護系統穩定**:避免不當操作導致系統崩潰 - **符合法規要求**:企業環境中的資料保護與稽核需求 #### 常見場景 1. **多人共享伺服器環境** - 開發團隊共用開發機器 - 不同專案需要隔離檔案存取權限 - 防止誤刪他人檔案 2. **Web 服務器權限控制** - Web 應用程式檔案的存取權限 - 資料庫檔案保護 - 設定檔安全性 3. **系統管理與維運** - 系統設定檔保護 - 服務帳號權限最小化 - 日誌檔案的讀寫控制 ### 二、基本概念 #### 使用者(User)與群組(Group) **使用者(User)**: - 每個檔案都有一個擁有者(owner) - 使用者 ID(UID)是系統內部識別碼 - root 使用者的 UID 為 0,擁有最高權限 - 一般使用者 UID 通常從 1000 開始 ![image](https://hackmd.io/_uploads/H1HQ59MQgg.png) **群組(Group)**: - 使用者可以屬於一個或多個群組 - 群組 ID(GID)是系統內部識別碼 - 主要群組:使用者的預設群組 - 附加群組:使用者額外加入的群組 ![image](https://hackmd.io/_uploads/ryaQq5fQgx.png) ```bash # 查看目前使用者資訊,包含 uid,gid,groups whoami id # 查看使用者所屬群組 groups groups username # 查看系統所有使用者 cat /etc/passwd # 查看系統所有群組 cat /etc/group ``` #### 檔案與目錄的屬性 每個檔案和目錄都有三種存取對象: - **Owner(擁有者)**:檔案的擁有者 - **Group(群組)**:檔案所屬群組的成員 - **Others(其他人)**:系統上所有其他使用者 #### 權限種類 **基本權限**: - **read (r)**:讀取權限 - 檔案:可以查看檔案內容 - 目錄:可以列出目錄內容(需搭配 execute 權限) - **write (w)**:寫入權限 - 檔案:可以修改檔案內容 - 目錄:可以在目錄中建立、刪除、重命名檔案 - **execute (x)**:執行權限 - 檔案:可以執行檔案(如程式、腳本) - 目錄:可以進入目錄(cd 指令) ### 三、權限表示法 #### 字母表示法 使用 `ls -l` 指令可以查看詳細權限資訊: > 或是也可以使用縮寫 `ll` ```bash $ ls -l -rwxr-xr-- 1 user group 1024 Jun 7 10:30 example.txt drwxr-xr-x 2 user group 4096 Jun 7 10:31 folder ``` 權限字串解析: ``` -rwxr-xr-- │└┬┘└┬┘└┬┘ │ │ │ └── Others 權限 (r--):只能讀取 │ │ └───── Group 權限 (r-x):可讀取和執行 │ └──────── Owner 權限 (rwx):可讀、寫、執行 └─────────── 檔案類型 (-:一般檔案, d:目錄 dictionary, l:符號連結 link) ``` **權限符號對照**: - `r` = read(讀取) - `w` = write(寫入) - `x` = execute(執行) - `-` = 沒有該權限 #### 數字表示法(八進位) 每個權限對應一個數字: - `r` = 4 - `w` = 2 - `x` = 1 三個數字分別代表 Owner、Group、Others 的權限: | 數字 | 二進位 | 權限 | 說明 | |------|--------|------|------| | 0 | 000 | --- | 無任何權限 | | 1 | 001 | --x | 只有執行權限 | | 2 | 010 | -w- | 只有寫入權限 | | 3 | 011 | -wx | 寫入 + 執行 | | 4 | 100 | r-- | 只有讀取權限 | | 5 | 101 | r-x | 讀取 + 執行 | | 6 | 110 | rw- | 讀取 + 寫入 | | 7 | 111 | rwx | 完全權限 | **常見權限組合**: - `755`:擁有者完全權限,群組和其他人可讀取和執行 - `644`:擁有者可讀寫,群組和其他人只能讀取 - `700`:只有擁有者有完全權限 - `600`:只有擁有者可讀寫 #### 特殊權限 **SetUID (SUID)**: - 符號:`s` 在 owner 的 execute 位置 - 數字:在權限前加 `4`(如 4755) - 功能:執行檔案時,暫時獲得檔案擁有者的權限 - 例子:`/usr/bin/passwd` 指令 **SetGID (SGID)**: - 符號:`s` 在 group 的 execute 位置 - 數字:在權限前加 `2`(如 2755) - 功能: - 檔案:執行時獲得檔案群組權限 - 目錄:新建檔案自動繼承目錄的群組 - 也就是說,無論誰執行它,都會以「檔案擁有者(這裡是 root)」的身份來執行 - 例子:`/usr/bin/passwd` **Sticky Bit**: - 符號:`t` 在 others 的 execute 位置 - 數字:在權限前加 `1`(如 1755) - 功能: - 所有人都可以寫入該目錄(777) - 但只能刪除自己建立的檔案 - 其他人(即使有寫入權限)不能刪除或改動你建立的檔案 - 例子:`/tmp` 目錄 ```bash # 查看特殊權限範例 ls -l /usr/bin/passwd # SUID ls -ld /tmp # Sticky bit ``` ### 四、常用指令教學 #### `ls -l`:檢視檔案權限 ```bash # 查看目前目錄的詳細權限資訊 ls -l # 等同 ll,以下的指令以 ls -l 開頭的,都可以改成 ll,例如 ls -la = ll -a ll # 查看特定檔案權限 ls -l filename.txt # 查看目錄本身的權限(而非目錄內容) ls -ld dirname # 查看隱藏檔案權限 ls -la # 以人類可讀格式顯示檔案大小 ls -lh ``` 輸出解析: ``` -rw-r--r-- 1 user group 1024 Jun 7 10:30 file.txt │ │ │ │ │ │ │ └── 檔案名稱 │ │ │ │ │ │ └─────────── 修改時間 │ │ │ │ │ └──────────────── 檔案大小 │ │ │ │ └────────────────────── 群組名稱 │ │ │ └─────────────────────────── 使用者名稱 │ │ └────────────────────────────── 硬連結數量 │ └──────────────────────────────────── 檔案權限(前三為 owner、中三為 group、後三維 others) └───────────────────────────────────────── 檔案類型 ``` > 硬連結 > 數量表示有多少個連結指向這個檔案,對於目錄來說,這個數字會包含子目錄的連結數。 > 假設我用 `touch` 建立一個 txt 檔案,使用 `ll` 時看到的硬連結束自為 1 > 再用 `ln` 建立一個硬連結的另外一個檔案,再使用 `ll`,就會看到這兩個檔案的硬連結數字變成 2 > 修改其中一個檔案,另外一個也會被做一樣的修改。因為實際上這兩個檔案是同一個。 #### `chmod`:變更權限 **數字模式**: ```bash # 設定權限為 755 (rwxr-xr-x) chmod 755 filename # 設定權限為 644 (rw-r--r--) chmod 644 filename # 遞迴設定目錄及其內容權限 chmod -R 755 directory # 設定特殊權限 chmod 4755 filename # SUID + 755 chmod 2755 dirname # SGID + 755 chmod 1755 dirname # Sticky + 755 ``` **符號模式**: ```bash # 語法:chmod [who][operator][permission] filename # who: u(user), g(group), o(others), a(all) # operator: +(加入), -(移除), =(設定) # permission: r(read), w(write), x(execute) # 給予 owner 執行權限 chmod u+x filename # 移除 group 寫入權限 chmod g-w filename # 設定 others 只有讀取權限 chmod o=r filename # 給所有人加入執行權限 chmod a+x filename chmod +x filename # 簡寫 # 組合使用 chmod u+rw,g+r,o-rwx filename ``` #### `chown`:變更檔案擁有者 ```bash # 語法:chown [owner][:group] filename # 變更檔案擁有者 chown newuser filename # 同時變更擁有者和群組 chown newuser:newgroup filename # 只變更群組(使用冒號開頭) chown :newgroup filename # 遞迴變更目錄及其內容 chown -R newuser:newgroup directory # 從參考檔案複製權限 chown --reference=ref_file target_file # 變更符號連結本身的擁有者(而非目標檔案) chown -h newuser symlink ``` #### `chgrp`:變更檔案群組 ```bash # 變更檔案群組 chgrp newgroup filename # 遞迴變更 chgrp -R newgroup directory # 從參考檔案複製群組 chgrp --reference=ref_file target_file # 顯示變更過程 chgrp -v newgroup filename ``` #### `umask`:預設權限設定 umask 決定新建檔案和目錄的預設權限: ```bash # 查看目前 umask 值 umask # 查看 umask 的符號表示 umask -S # 設定 umask(數字模式) umask 022 # 新檔案權限 = 666-022 = 644 # 新目錄權限 = 777-022 = 755 # 設定 umask(符號模式) umask u=rwx,g=rx,o=rx # 臨時設定 umask umask 077 # 只有擁有者有權限 # 永久設定 umask(寫入 ~/.bashrc) echo "umask 027" >> ~/.bashrc ``` **umask 計算範例**: - 檔案預設最大權限:666 (rw-rw-rw-) - 目錄預設最大權限:777 (rwxrwxrwx) - umask 022:表示移除 group 和 others 的 write 權限 - 結果:檔案 644 (rw-r--r--),目錄 755 (rwxr-xr-x) ### 五、進階權限管理 #### ACL(Access Control List)介紹與設定 傳統的 Linux 權限系統只能為檔案設定一個擁有者、一個群組和其他人的權限。ACL 提供更細緻的權限控制,可以為特定使用者或群組設定個別權限。 **ACL 的優勢**: - 可以為多個不同使用者設定不同權限 - 不需要建立大量群組 - 更靈活的權限組合 **檢查 ACL 支援**: ```bash # 檢查檔案系統是否支援 ACL mount | grep acl # 查看檔案是否有 ACL(ls -l 會顯示 + 號) ls -l filename -rw-rw-r--+ 1 user group 1024 Jun 7 10:30 filename ``` **ACL 基本指令**: ```bash # 安裝 ACL 工具(Ubuntu/Debian) sudo apt-get install acl # 查看檔案的 ACL 設定 getfacl filename getfacl directory # 設定使用者權限 setfacl -m u:username:rwx filename # 給予特定使用者 rwx 權限 setfacl -m u:alice:r-- filename # 給予 alice 只讀權限 # 設定群組權限 setfacl -m g:groupname:rw- filename # 給予特定群組 rw 權限 # 設定預設 ACL(針對目錄,新檔案會繼承) setfacl -d -m u:username:rwx directory # 移除特定 ACL setfacl -x u:username filename # 移除特定使用者的 ACL setfacl -x g:groupname filename # 移除特定群組的 ACL # 移除所有 ACL setfacl -b filename # 遞迴設定 ACL setfacl -R -m u:username:rwx directory # 從檔案讀取 ACL 設定 setfacl --set-file=acl_rules.txt filename ``` **ACL 實用範例**: ```bash # 情境:讓 alice 可以讀寫專案目錄,bob 只能讀取 setfacl -m u:alice:rwx project_dir setfacl -m u:bob:r-x project_dir setfacl -d -m u:alice:rwx project_dir # 預設權限 setfacl -d -m u:bob:r-x project_dir # 備份和還原 ACL getfacl -R directory > acl_backup.txt setfacl --restore=acl_backup.txt ``` ### 六、實作範例 #### 建立使用者與群組並設計權限實例 **情境**:建立一個專案開發環境,有三種角色: - 專案經理(project_manager):完全存取權限 - 開發人員(developers):可讀寫程式碼,不能修改設定 - 測試人員(testers):只能讀取和執行,不能修改 ```bash # 1. 建立群組 groupadd project_managers groupadd developers groupadd testers # 2. 建立使用者並加入群組 ## -m:就是 --create-home 的縮寫,預設建立 /home/使用者名稱 的路徑,沒有加 -m 的話,有些系統四射不會幫你建立 home 目錄 ## -G:就是 --groups 的縮寫,把使用者加入指定的附加群組,一次可以多個 group,用逗號隔開就好 useradd -m -G project_managers alice useradd -m -G developers bob useradd -m -G developers charlie useradd -m -G testers david # 3. 設定密碼 passwd alice passwd bob passwd charlie passwd david # 4. 建立專案目錄結構 ## -p:即 parant,遞迴建立資料夾 ## {xxx,xxxx}:只建立多個子目錄 mkdir -p /project/{src,config,docs,bin} chown -R alice:project_managers /project # 5. 設定目錄權限 # 專案根目錄:專案經理完全權限,其他群組可進入 chmod 755 /project # 原始碼目錄:開發人員可讀寫,測試人員只讀 chgrp developers /project/src chmod 775 /project/src setfacl -m g:testers:r-x /project/src # 設定目錄:只有專案經理可修改 chmod 750 /project/config setfacl -m g:developers:r-x /project/config setfacl -m g:testers:r-x /project/config # 文件目錄:所有人可讀,開發人員和專案經理可寫 chgrp developers /project/docs chmod 775 /project/docs setfacl -m g:testers:r-x /project/docs # 執行檔目錄:所有人可執行,專案經理可修改 chmod 755 /project/bin setfacl -m g:developers:r-x /project/bin setfacl -m g:testers:r-x /project/bin # 6. 設定預設 ACL(新檔案自動繼承權限) setfacl -d -m g:developers:rw- /project/src setfacl -d -m g:testers:r-- /project/src ``` #### 權限錯誤排除範例 **常見問題 1:無法進入目錄** ```bash # 錯誤:Permission denied when trying to cd into directory cd: permission denied: /some/directory # 診斷步驟: ls -ld /some/directory # 檢查目錄權限 ls -ld /some # 檢查上層目錄權限 getfacl /some/directory # 檢查 ACL # 解決方案:確保目錄有 execute 權限 sudo chmod +x /some/directory ``` **常見問題 2:無法建立檔案** ```bash # 錯誤:無法在目錄中建立檔案 touch: cannot touch 'newfile': Permission denied # 診斷步驟: ls -ld . # 檢查目錄權限 id # 檢查使用者和群組 df -h . # 檢查磁碟空間 # 解決方案:確保目錄有 write 權限 sudo chmod g+w . ``` **常見問題 3:無法執行檔案** ```bash # 錯誤:程式無法執行 bash: ./script.sh: Permission denied # 診斷步驟: ls -l script.sh # 檢查檔案權限 file script.sh # 檢查檔案類型 # 解決方案:加入執行權限 chmod +x script.sh ``` **常見問題 4:權限看起來正確但仍無法存取** ```bash # 可能原因:SELinux 或 AppArmor 限制 # 診斷: getenforce # 檢查 SELinux 狀態 ausearch -m AVC -ts recent # 查看 SELinux 拒絕日誌 sudo apparmor_status # 檢查 AppArmor 狀態 # 暫時解決: sudo setenforce 0 # 暫時停用 SELinux sudo aa-complain /path/to/program # AppArmor 警告模式 ``` #### 使用 `find` 搭配權限查找異常檔案 ```bash # 尋找權限過於寬鬆的檔案 # 1. 找出所有人都可寫入的檔案(潛在安全風險) find /home -type f -perm -o+w 2>/dev/null # 2. 找出 SUID 檔案(需要特別注意) find /usr -type f -perm -4000 2>/dev/null # 3. 找出 SGID 檔案 find /usr -type f -perm -2000 2>/dev/null # 4. 找出沒有擁有者的檔案 find /home -nouser 2>/dev/null # 5. 找出沒有群組的檔案 find /home -nogroup 2>/dev/null # 尋找特定權限的檔案 # 6. 找出權限為 777 的檔案(完全開放) find /home -type f -perm 777 2>/dev/null # 7. 找出權限為 666 的檔案(所有人可讀寫) find /home -type f -perm 666 2>/dev/null # 8. 找出擁有者可執行的檔案 find /home -type f -perm -u+x 2>/dev/null # 尋找最近修改的檔案並檢查權限 # 9. 找出最近 7 天修改且權限異常的檔案 find /var/log -type f -mtime -7 -perm -o+w 2>/dev/null # 10. 找出大於 100MB 且所有人可讀的檔案 find /home -type f -size +100M -perm -o+r 2>/dev/null # 批次修復權限問題 # 11. 將所有 .txt 檔案設為 644 權限 find /home/user -name "*.txt" -type f -exec chmod 644 {} \; # 12. 將所有目錄設為 755 權限 find /home/user -type d -exec chmod 755 {} \; # 13. 移除所有人的寫入權限(除了擁有者) find /home/user -type f -exec chmod o-w {} \; # 生成權限報告 # 14. 生成目錄權限報告 find /project -exec ls -ld {} \; > permissions_report.txt # 15. 找出可能的安全問題並記錄 { echo "=== SUID Files ===" find /usr -type f -perm -4000 2>/dev/null echo "=== World Writable Files ===" find /home -type f -perm -o+w 2>/dev/null echo "=== No Owner Files ===" find /home -nouser 2>/dev/null } > security_audit.txt ``` ### 七、最佳實踐與建議 #### 最小權限原則(Principle of Least Privilege) **核心概念**:只給予使用者完成工作所需的最少權限,降低安全風險。 **實踐方法**: 1. **使用者權限設計**: ```bash # 不好的做法:直接給予 777 權限 chmod 777 /shared/data # 所有人完全權限 # 好的做法:針對需求設計權限 chmod 750 /shared/data # 擁有者和群組權限 setfacl -m u:alice:rw- /shared/data # 給特定使用者讀寫權限 setfacl -m u:bob:r-- /shared/data # 給特定使用者只讀權限 ``` 2. **服務帳號管理**: ```bash # 為服務建立專用使用者(無法登入) useradd -r -s /bin/false webapp_user useradd -r -s /bin/false database_user # 設定服務檔案權限 chown webapp_user:webapp_user /var/www/app chmod 750 /var/www/app ``` 3. **目錄權限規劃**: ```bash # 分層權限設計 /project/ # 755 - 專案根目錄 ├── src/ # 770 - 開發人員讀寫 ├── config/ # 750 - 管理員專用 ├── public/ # 755 - 公開讀取 └── logs/ # 750 - 管理員和服務讀寫 ``` #### 避免使用 root 身份操作 **為什麼要避免**: - root 權限過大,誤操作可能損壞系統 - 安全審計困難 - 不符合最小權限原則 **替代方案**: 1. **使用 sudo 進行特權操作**: ```bash # 設定 sudo 權限(編輯 /etc/sudoers) sudo visudo # 給予特定使用者特定指令權限 alice ALL=(ALL) /bin/systemctl restart apache2 bob ALL=(ALL) NOPASSWD: /usr/bin/tail -f /var/log/apache2/* # 給予群組權限 %developers ALL=(ALL) /usr/bin/docker ``` 2. **使用 su 切換使用者**: ```bash # 切換到特定使用者 su - webapp_user # 執行特定指令後返回 su -c "systemctl status apache2" root ``` 3. **使用服務帳號執行應用程式**: ```bash # 以特定使用者身份執行服務 sudo -u webapp_user /usr/bin/python3 /var/www/app/app.py # 設定 systemd 服務使用非 root 使用者 # /etc/systemd/system/myapp.service [Service] User=webapp_user Group=webapp_user ExecStart=/usr/bin/python3 /var/www/app/app.py ``` ###### Tags: `Linux`, `Permissions`, `Security`, `ACL`, `Best Practices` `Uncategorized`