SELinux 入門:理解 Linux 中的強制訪問控制與安全策略
一、概述
我們通常依靠傳統的安全措施,如強密碼、權限設置和防火墻來保護Linux系統。但有時,我們需要更精細的控制,比如管理進程可能執行的操作。這時候,SELinux(安全增強型Linux)就派上用場了。
SELinux最初由美國國家安全局(NSA)開發,后來發布給開源社區。它讓系統管理員能夠定義特定的訪問策略,以控制進程和用戶與系統資源的交互方式。
在本教程中,我們將探討SELinux是什么、它如何工作以及它的重要性。
二、SELinux到底是什么?
SELinux是一個內置于Linux內核的安全模塊,它在常規的Unix風格權限系統之外提供額外的訪問控制。它在防范權限提升、配置錯誤和零日漏洞攻擊方面發揮著關鍵作用。
在安全性至關重要的環境中,SELinux的作用尤為突出。無論是運行Web服務器、數據庫還是容器化應用,SELinux都可能決定威脅是被遏制還是導致整個系統淪陷。
要真正理解SELinux,了解它與標準Linux安全模型的區別是很有必要的。
1. 傳統權限(DAC)存在的問題
在Linux中,自主訪問控制(DAC)就是那些控制誰可以對文件執行何種操作的“讀-寫-執行”權限,它們構成了標準的安全層。簡單來說,文件或進程的所有者可以決定誰能獲得訪問權限。
雖然這種方式很靈活,但它也可能成為一個薄弱環節。如果惡意程序設法獲得了控制權,它或許能夠利用這些自主權限擴大破壞范圍。
例如,若一個用戶擁有某個腳本,該用戶可以決定誰能執行這個腳本。如果特權用戶(如root)或被入侵的進程獲得了控制權,它就有可能訪問或修改系統上的任何資源。傳統上,root用戶可以繞過DAC檢查。
2. 強制訪問控制(MAC)的解決方案
SELinux帶來的重大轉變在于它改變了訪問控制的工作方式。大多數管理員和用戶都非常熟悉DAC,在這種機制下,文件所有者有決定權。而SELinux則向內核中添加了MAC。
在MAC機制下,是操作系統(而非單個用戶)嚴格執行由管理員定義的系統級安全策略。每一個系統調用、每一次訪問嘗試,都會依據這一策略進行檢查。
更重要的是,即便是root用戶也必須遵守該策略。如果root用戶的操作超出了已定義的策略范圍,SELinux可以對其進行限制。換句話說,這是一種更為嚴格的安全機制。我們可以阻止對文件、進程和資源的未授權訪問或修改,即便是來自超級用戶賬戶的操作也不例外。
3. 默認拒絕原則
SELinux的MAC方法遵循默認拒絕原則。
簡而言之,如果SELinux規則沒有明確允許某項特定操作或訪問,那么該操作或訪問將被自動拒絕。這種“默認拒絕”的立場本身就通過減少攻擊面提供了極大的安全優勢。
4. MAC與DAC如何相輔相成
SELinux并不會取代由chmod或chown管理的基本文件權限,相反,它以特定的順序與這些權限協同工作,提供更深入且強制性的控制。
當一個進程試圖訪問某個文件時,系統會首先檢查DAC策略規則。只有當這些基本權限允許訪問時,SELinux才會介入并評估其安全策略(MAC)。
這一順序意味著SELinux扮演著第二個檢查點的角色。這為那些DAC級別可能過于寬松,或者被入侵的進程設法繞過DAC的場景提供了額外保護。
三、SELinux核心
啟用SELinux的系統依靠關鍵的安全概念來指導訪問決策。讓我們看看這些原則如何增強Linux系統的安全性。
1. 安全上下文(標簽)
SELinux會為系統上的每個文件、用戶和進程分配一個安全上下文(也稱為安全標簽)。這個上下文或標簽是一組屬性,SELinux用它來確定訪問權限。簡單來說,這些標簽就像是“名稱標簽”,表明哪些操作是允許的,哪些是不允許的。
安全上下文由四個部分組成(用戶:角色:類型:級別)。下面我們來看看每個部分的作用:
- 用戶:映射到一個或多個Linux用戶,并定義用戶可以承擔哪些角色,例如user_u或unconfined_u(與操作系統用戶不同)
- 角色:限制特定用戶或類型可以執行的操作,定義被分配到某個角色的用戶可以訪問哪些類型(SELinux分配的角色名稱帶有_r后綴,如system_r)
- 類型:進程的域和文件的類型,它定義了進程和文件之間如何交互(所有文件和運行中的進程都被分配一個以_t結尾的類型,例如,Web服務器進程的類型是httpd_t,/var目錄中文件的類型是var_t)
- 級別(可選):多級安全(MLS)系統中的 clearance 級別范圍,用于設置敏感級別,如s0或s1
現在,我們在包含文件的目錄上運行ls -Z命令,看看安全上下文的一些示例:
$ ls -Z
-rw-------. root root system_u:object_r:httpd_sys_content_t:s0 index.html
drwxrwxrwx. root root unconfined_u:object_r:admin_home_t:s0 backup
在這里,該命令列出了文件的所有者(root)以及其讀寫執行權限。此外,-Z選項還包含了每個條目的安全上下文的四個部分(用戶、角色、類型和安全級別),例如system_u:object_r:httpd_sys_content_t:s0。
2. 策略規則
SELinux使用策略模塊來定義每個進程可以執行的操作。每一個可能的操作(例如X類型的進程讀取Y類型的文件)都需要有明確的規則允許,否則SELinux會拒絕該操作。正如我們前面提到的,SELinux默認禁止所有操作,除非明確允許。
例如,一條策略規則可能會規定“允許httpd_t進程讀取httpd_sys_content_t文件”。如果我們嘗試執行規則中未涵蓋的操作,SELinux會阻止該操作并記錄拒絕信息。
設置策略規則時,我們需要遵循基本語法:
<規則類型> <主體> <對象>:<對象類別> <權限>;
下面我們來分解每個部分的含義:
- 規則類型:SELinux應采取的操作,通常是allow(允許)、dontaudit(不審計)或neverallow(從不允許)
- 主體:請求訪問的進程的域或類型
- 對象:被訪問資源的類型
- 對象類別:對象的類別,如file(文件)、dir(目錄)、tcp_socket(TCP套接字)
- 權限:被允許的操作,如read(讀?。?、write(寫入)、open(打開)
例如,我們可以看一個簡單的策略規則示例:
ALLOW apache_process apache_log:FILE READ;
這條規則簡單地允許標有apache_process標簽的進程讀取標有apache_log標簽的日志文件。
3. 布爾值
如果我們想在不編輯安全策略的情況下關閉一條規則,該怎么辦呢?
SELinux布爾值是一個開關,它允許在不重寫整個SELinux策略的情況下改變規則的行為。例如,一個常見的布爾值是httpd_can_network_connect。默認情況下,它可能是關閉的,因此Web服務器(httpd_t)不能建立出站網絡連接。
讓我們看看如何使用setsebool命令將其開啟:
$ setsebool -P httpd_can_network_connect on
通過將上述布爾值設置為on,SELinux允許相應的訪問,而無需修改策略文件。此外,我們可以使用等效的數值0-1來代替on-off選項。
實際上,SELinux自帶了許多這樣的布爾值,用于控制諸如允許FTP寫入訪問、使用NFS等操作,以便在運行時調整規則。我們可以使用getsebool -a命令列出所有規則:
$ getsebool -a | less
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
auditadm_exec_content --> on
authlogin_nsswitch_use_ldap --> off
authlogin_radius --> off
authlogin_yubikey --> off
awstats_purge_apache_log_files --> off
:
這里,輸出內容可能很長,所以最好將其通過管道傳輸到less命令,以便逐頁滾動查看。
4. 模式
SELinux可以在三種模式下運行,每種模式提供不同級別的安全控制:
- enforcing(強制模式)(0):主動阻止違規行為
- permissive(寬容模式)(1):記錄違規行為但不阻止
- disabled(禁用模式):完全關閉SELinux,系統退回到正常的DAC權限
我們可以使用getenforce命令檢查當前的SELinux模式:
$ getenforce
Enforcing
在這種情況下,SELinux處于強制模式。
現在,我們使用setenforce命令將其切換到寬容模式:
$ setenforce 0
這里的0是寬容模式的模式ID。相反,1是強制模式的ID。
值得注意的是,setenforce命令的設置在重啟后不會保留。不過,我們可以直接編輯SELinux配置文件(/etc/selinux/config)來使更改持久化。此外,編輯該配置文件也是切換到禁用模式的方法。
四、為什么SELinux很重要?
看起來Linux的文件權限(讀、寫、執行)和用戶所有權應該足以保證系統的安全。當然,對于簡單的設置來說,通常確實如此。但是,一旦我們運行復雜的面向互聯網的服務,標準的訪問權限就無法覆蓋所有場景了。
SELinux的一個主要優勢是它能夠在安全漏洞出現時限制損害范圍。
假設Web服務器(Apache httpd)被黑客攻擊。在傳統權限機制下,攻擊者可能會讀取/etc目錄中的敏感文件、修改/var/www目錄中的腳本,以及訪問用戶數據。
下面我們來看一個簡單的例子,了解SELinux如何基于文件標簽阻止即使是root用戶的訪問。
首先,我們在root用戶的主目錄中創建一個測試文件:
$ echo "secret" > /root/zfile
現在,我們使用chcon命令更改該文件的SELinux標簽:
$ chcon -t admin_home_t /root/zfile
在這里,我們為/root/zfile分配了admin_home_t類型,這并不是供Web服務器訪問的類型。
最后,我們檢查Apache是否能夠訪問該文件:
$ runcon -t httpd_t -- cat /root/testfile
cat: /root/zfile: Permission denied
我們使用runcon -t命令在不同的SELinux上下文(httpd_t,即Apache運行的域)下運行cat /root/zfile命令。即便cat命令是以root身份運行的,SELinux也會介入并阻止它。