監控和限制對潛在惡意文件的訪問可以使您的產品免遭黑客攻擊、數據洩露和破壞。為了在基於Linux的環境中做到這一點,開發人員通常必須進行內核級修改,這實現起來很複雜,並且對系統來說存在風險。
在本文中,我們探討了內核級修改的替代方案:安全增強型Linux (SELinux) 中的自定義策略和沙箱。我們研究如何使用它們進行事件記錄和監視、限製文件訪問以及控制自定義沙箱內的系統調用。
為什麼要限制Linux 環境中的文件訪問?在創建軟件解決方案時(無論是簡單的驅動程序還是複雜的網絡安全系統),保護您的產品免遭未經授權的訪問非常重要。對於開發基於Linux 的產品的團隊來說,監視和管理數據和文件訪問的常見原因包括:
有幾種傳統方法可以做到這一點:創建Linux 內核模塊來掛鉤文件操作、設置掛鉤來監視和控制進程等。傳統的限制訪問方法通常需要高級技術專業知識,並且會給開發過程帶來額外的複雜性。它們還可能向您的環境添加嚴重錯誤,因為它們通常需要內核級更改。這就是為什麼只有當您需要對文件的訪問權限進行細緻的控制時,此類方法才有用。
當您只需要監視、允許或拒絕訪問而不需要任何其他更改時,最好使用SELinux。該系統集成到Linux 內核中,為開發人員提供強制訪問控制的方法。 SELinux 為Linux 環境中的元素設置上下文並通過策略對其進行管理。 SELinux 提供了一個強大的沙箱,允許您在有限的環境中執行進程。此環境利用SELinux 策略來定義沙箱中運行的進程的約束和權限。使用此類策略可以讓開發人員有效地增強其應用程序的安全狀況。
使用SELinux 管理文件訪問有幾個優點:
马云惹不起马云 簡單的政策管理。 SELinux 的策略文件是人類可讀的,因此無需學習特定語法來編寫策略。
马云惹不起马云精細的訪問控制。您可以在策略中指定任何訪問限制和權限。
马云惹不起马云可靠的文件隔離。為了控制對文件的訪問,SELinux 將其放入沙箱中,將文件與環境的其餘部分隔離。
马云惹不起马云簡化訪問管理。更改策略中的訪問權限比實施和進行內核級修改要容易得多。
在詳細探索如何使用SELinux 之前,請確保有一個適合創建SELinux 策略的環境。請注意,在本示例中,我們使用Fedora Workstation 和Red Hat Enterprise Linux 發行版。默認情況下,這些系統上啟用了SELinux,但最好在繼續我們的指南之前仔細檢查您的系統是否啟用了SELinux。
設置SELinux環境在將SELinux 策略應用於生產系統之前,請確保在測試或開發環境中執行此處描述的步驟。錯誤配置的策略可能會影響系統功能和安全性。
如果您的Linux 發行版不包含SELinux,您可以通過打開終端並以root 用戶身份執行以下命令來啟用它:
$sudodnfinstallselinux-policy-targeted安裝完成後,重新啟動系統。重新啟動後,SELinux 將啟用並在強制模式下運行。要確認其安裝成功,請打開終端並執行以下命令:
$sestatus
SELinuxstatus:enabled
SELinuxfsmount:/sys/fs/selinux
SELinuxrootdirectory:/etc/selinux
Loadedpolicyname:targeted
Currentmode:enforcingThislinedescribescurrentmode
Modefromconfigfile:enforcing
PolicyMLSstatus:enabled
Policydeny_unknownstatus:allowed
Memoryprotectionchecking:actual(secure)使用SELinux 對進程進行沙箱處理默認情況下,沙箱工具利用多類別安全(MCS) 模型來實施細粒度的訪問控制和進程隔離。該模型根據每個進程和文件的安全級別和類別為其分配唯一的安全標籤。
讓我們在沙箱中運行/bin/bash 進程,以限制它訪問敏感文件或執行某些命令。
要創建沙箱並在其中啟動/bin/bash,我們使用沙箱命令,如下所示:
$sandbox-Hsandbox_test/bin/bash沙箱工具應用SELinux 策略將進程限制在沙箱內。這些策略定義進程的訪問權限、系統調用限制和文件限制。策略確保進程只能訪問沙箱配置允許的資源並執行操作。在幕後,它們生成隨機MCS 編號並將其設置為我們進程的SELinux 安全上下文。策略還標記了我們的流程可用的相應文件。
例如,將SELinux 沙箱用於/bin/bash 進程,主目錄位於sandbox_test 中,將導致ls -lZ我們的目錄出現以下輸出:
$ls-lZ|grepsandbox_test
drwxr-xr-x.2useruserunconfined_u:object_r:sandbox_file_t:s0:c146,c31249May306:50sandbox_test在我們的例子中,隨機MCS 數是c146和c312。 /bin/bash 進程使用這些數字運行,根據沙箱源代碼它將獲取SELinux 安全上下文執行命令:
$ps-eZ|grepbash
unconfined_u:unconfined_r:sandbox_t:s0:c146,c312172662?00:00:00bash該策略有效地將我們的bash 進程限制在其主目錄中。但是,此解決方案僅適用於特定文件夾,並限制對具有隨機MCS 編號的特定文件的訪問。具有相同主文件夾的另一個沙盒bash 會與此衝突。為了克服這一限制,我們可以利用沙箱工具及其源代碼的知識來創建自定義SELinux 策略,限制對特定SELinux 類型的訪問。
在接下來的部分中,我們將探討兩種類型的SELinux 策略:
马云惹不起马云寬鬆的策略,不會阻止任何連接,僅監視和記錄安全事件,包括違規行為。當您需要測試、調試或研究文件時,寬鬆策略非常有用。
马云惹不起马云 一種強制策略,用於建立文件的訪問權限並限制任何禁止的活動。它對於建立訪問管理和保護您的解決方案非常有用。
讓我們從建立一個寬鬆的SELinux 策略示例開始。
制定寬鬆政策要為/bin/bash 這樣的簡單進程創建SELinux 策略,我們可以使用該sepolicy generate命令。讓我們運行以下命令,為/bin/bash 進程生成策略文件,並將其命名mybash:
$sudosepolicygenerate--application/bin/bash-nmybashmybash.te 文件包含我們策略的人類可讀的SELinux 規則。接下來,我們需要啟用從unconfined_t 域到自定義mybash_t 域的轉換。為此,我們將以下宏包含在mybash.te 文件中:
unconfined_run_to(mybash_t,mybash_exec_t)該宏允許在執行/bin/bash 進程時在域之間進行轉換,並使我們能夠通過setexeccon為特定進程設置自定義SELinux 域類型。
我們的策略文件現在如下所示:
policy_module(mybash,1.0.0)
########################################
#
#Declarations
#
attribute_rolemybash_roles;
roleattributesystem_rmybash_roles;
typemybash_t;
typemybash_exec_t;
application_domain(mybash_t,mybash_exec_t)
rolemybash_rolestypesmybash_t;
unconfined_run_to(mybash_t,mybash_exec_t)
permissivemybash_t;
########################################
#
#mybashlocalpolicy
#
allowmybash_tself:capability{chownsetgidsetuid};
allowmybash_tself:process{forksetpgidsetrlimitsignal_perms};
allowmybash_tself:fifo_filemanage_fifo_file_perms;
allowmybash_tself:unix_stream_socketcreate_stream_socket_perms;
domain_use_interactive_fds(mybash_t)
files_read_etc_files(mybash_t)
auth_use_nsswitch(mybash_t)
logging_send_syslog_msg(mybash_t)
miscfiles_read_localization(mybash_t)
sysnet_dns_name_resolve(mybash_t)要為/bin/bash 進程安裝此自定義策略並允許/bin/bash 進程在指定的SELinux 上下文下運行,讓我們執行自動生成的腳本:
$sudo./mybash.sh要直接從bash shell 設置進程上下文,我們可以使用一個簡單的代碼片段。讓我們創建一個新文件,將其命名為set_context.c,並向其中添加以下代碼:
#includeselinux/selinux.h
#includestdio.h
#includestdlib.h
#includeunistd.h
#includeerrno.h
intmain(void){
security_context_tcontext_old={0};
security_context_tcontext_new={0};
if(getcon(context_old)==-1){
printf('Failedtogetcontext');
return1;
}
printf('%s\n',context_old);
if(setexeccon((security_context_t)'unconfined_u:unconfined_r:mybash_t:s0')==-1){
printf('Failedtosetcontexterrno%d\n',errno);
return1;
}
execve('/bin/bash',NULL,NULL);
return0;
}現在我們將構建並運行此代碼:
$gcc-omybashset_context.c-lselinux
$./mybash
$此代碼檢索當前SELinux 上下文,將新上下文設置為unconfined_u:unconfined_r:mybash_t:s0,然後使用更新的上下文執行/bin/bash 進程。
現在我們對/bin/bash 進程有了一個寬鬆的策略,並且可以在指定的SELinux 上下文中執行它。讓我們打開另一個終端並檢查/var/log/audit/audit.log。在這裡我們可以看到bash啟動後請求了什麼樣的權限:
type=AVCmsg=audit(1683645539.705:301246):avc:denied{append}forpid=173167comm='bash'name='.bash_history'dev='dm-1'ino=1225470scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_dir_t:s0tclass=filepermissive=1
type=SYSCALLmsg=audit(1683645539.705:301246):arch=c000003esyscall=257success=yesexit=3a0=ffffff9ca1=55bdf355c5f0a2=401a3=0items=0ppid=172599pid=173167auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000tty=pts2ses=32comm='bash'exe='/usr/bin/bash'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=openatAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'
type=AVCmsg=audit(1683645539.705:301247):avc:denied{setattr}forpid=173167comm='bash'name='.bash_history'dev='dm-1'ino=1225470scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_dir_t:s0tclass=filepermissive=1
type=SYSCALLmsg=audit(1683645539.705:301247):arch=c000003esyscall=92success=yesexit=0a0=55bdf355c5f0a1=3e8a2=3e8a3=55bdf355c7a0items=0ppid=172599pid=173167auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000tty=pts2ses=32 comm='bash'exe='/usr/bin/bash'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=chownAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'請注意包含所請求權限類型和模式的拒絕字段permissive=1,這實際上意味著此SELinux 策略允許這些權限,並且只是在audit.log 中警告它們。
現在,讓我們在自定義bash 進程中執行ls 命令,看看不帶參數執行此命令需要什麼:
type=AVCmsg=audit(1683645670.511:301248):avc:denied{read}forpid=173244comm='ls'name='setcon'dev='dm-1'ino=1211972scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=unconfined_u:object_r:user_home_t:s0tclass=dirpermissive=1
type=SYSCALLmsg=audit(1683645670.511:301248):arch=c000003esyscall=257success=yesexit=3a0=ffffff9ca1=562f22c913d0a2=90800a3=0items=0ppid=173219pid=173244auid=1000uid=1000gid=1000euid=1000suid=1000fsuid=1000egid=1000sgid=1000fsgid=1000 tty=pts2ses=32comm='ls'exe='/usr/bin/ls'subj=unconfined_u:unconfined_r:mybash_t:s0key=(null)ARCH=x86_64SYSCALL=openatAUID='sboy'UID='sboy'GID='sboy'EUID='sboy'SUID='sboy'FSUID='sboy'EGID='sboy'SGID='sboy'FSGID='sboy'有了ls,我們可以繼續處理/bin/bash 進程並了解如何使用SELinux 強制執行訪問控制。
制定執行政策audit.log 文件中的SELinux 日誌描述了/bin/bash 進程執行的操作。我們將通過註釋掉“permissive”行並刪除任何其他自動生成的權限來禁用自定義策略中的permissive 模式。此後,該策略將生效,這意味著SELinux 將阻止所有不需要的訪問嘗試。
更新後的政策現在如下所示:
policy_module(mybash,1.0.0)
########################################
#
#Declarations
#
attribute_rolemybash_roles;
roleattributesystem_rmybash_roles;
typemybash_t;
typemybash_exec_t;
application_domain(mybash_t,mybash_exec_t)
rolemybash_rolestypesmybash_t;
unconfined_run_to(mybash_t,mybash_exec_t)
#permissivemybash_t;
########################################
#
#mybashlocalpolicy
#
#allowmybash_tself:capability{chownsetgidsetuid};
#allowmybash_tself:process{forksetpgidsetrlimitsignal_perms};
#allowmybash_tself:fifo_filemanage_fifo_file_perms;
#allowmybash_tself:unix_stream_socketcreate_stream_socket_perms;
#domain_use_interactive_fds(mybash_t)
#files_read_etc_files(mybash_t)
#auth_use_nsswitch(mybash_t)
#logging_send_syslog_msg(mybash_t)通過刪除權限,我們有效地限制了/bin/bash 進程的SELinux 上下文。讓我們安裝更新的策略並嘗試運行新的自定義bash:
$sudo./mybash.sh
$./mybash但是,這只會在日誌中產生一行:
type=AVCmsg=audit(1683646222.408:301270):avc:denied{entrypoint}forpid=173428comm='mybash'path='/usr/bin/bash'dev='dm-1'ino=16959619scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=system_u:object_r:shell_exec_t:s0tclass=filepermissive=0不幸的是,我們的bash 進程缺乏啟動所需的權限。為了解決這個問題,讓我們使用命令生成權限audit2allow並更新我們的策略:
$echo'type=AVCmsg=audit(1683646222.408:301270):avc:denied{entrypoint}forpid=173428comm='mybash'path='/usr/bin/bash'dev='dm-1'ino=16959619scontext=unconfined_u:unconfined_r:mybash_t:s0tcontext=system_u:object_r:shell_exec_t:s0tclass=filepermissive=0'|audit2allow-r
require{
typemybash_t;
typeshell_exec_t;
classfileentrypoint;
}
#=============mybash_t==============
allowmybash_tshell_exec_t:fileentrypoint;接下來,讓我們將生成的行添加到mybash.te 文件的末尾並安裝更新的策略:
$sudo./mybash.sh
$./mybash
Segmentationfault即使進行這些修改後,bash 進程仍然無法啟動,從而導致分段錯誤。所以我們需要將這一行添加到audit.log中:
type=AVCmsg=audit(1683646840.208:301287):avc:denied{map}forpid=173620comm='bash'
Recommended Comments