Contents
電腦安全近日再次成為管理者的熱門話題。互聯網上冒起了數十個網站,而每個都推薦自己的「完美」設置指南。它們的建議都擁有常見的鐘型分佈:好的建議、一般的建議、與及那些足以令到你的資料成為一堆廢物的建議。在這裡,我們要討論如何正確地加固一個 CentOS 5 系統。這個「正確」的方法建基於 NSA RHEL5 指南、Steve Grubb 的「加固 RHEL」簡報、及其它可靠的資料來源。
在這個 wiki 文章內,我們會假設正在安裝一台伺服器。筆記型電腦及工作台或許會有不同需求,例如加密的檔案系統,是不包含在這裡的。同樣地,它們或許會應用到 USB 儲存器或無線模塊,但在這份安全性指南內它們會被停用。
分割檔案系統
透過將檔案系統分配到不同分割區,你可以微調存取權及功能。這樣做能夠將存取權劃分得更細微,而且多加一層安全保障來阻嚇任何壞人。
Steve Grubb 頗正確地建議將用戶有權寫入的地方放在獨立的分割區內。這樣做令你能防止硬連結越權、新增設置、及其它不受歡迎的行為。
1. 更改 fstab
當你將分割區劃分好及設定大小後,你便可以盡量收窄個別掛載點的權限。只要情況容許,你便應該加入 nodev、nodexec 及 nosuid。下面是一個已經適切地收窄權限的 /etc/fstab 範例檔:
/dev/VG_OS/lv_root / ext3 defaults 1 1 /dev/VG_OS/lv_tmp /tmp ext3 defaults,nosuid,noexec,nodev 1 2 /dev/VG_OS/lv_vartmp /var/tmp ext3 defaults,nosuid,noexec,nodev 1 2 /dev/data_vol/lv_home /home ext3 defaults,nosuid,nodev 1 2 /dev/VG_OS/lv_var /var ext3 defaults,nosuid 1 2 /dev/data_vol/lv_web /var/www ext3 defaults,nosuid,nodev 1 2 /dev/sda1 /boot ext3 defaults,nosuid,noexec,nodev 1 2 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 /dev/_VG_OS/lv_swap swap swap defaults 0 0
明顯地,你需要修改這個範例來迎合你的系統。LVM、磁區名稱、標籤等都可以被更改。請不會隻字不漏地複製這個範例檔,並期望它適合你使用。
網頁伺服器的掛載亦可以被設定為 noexec,但這樣做會影響到 cgi 類應用程式,與及依賴 execute bit hack 的伺服器端包含檔。如果你不會應用 cgi 程式,我建議最低限度測試採用 noexec,並看看會否有副作用。
安裝套件
當你在系統上安裝套件時,請記得簡單就是美。你的系統上越多東西,就意味著越多東西需要追踪漏動及更新,及越多東西有機會妨礙你做想做的事情。由於伺服器的工種可以很不同,我甚至不會嘗試列出哪些套件應該或不應該安裝。反而,我會建議採用自訂套件清單及只選取基本套件這個簡單策略。當你這樣做之後,列出現時安裝了的套件,然後繼續清除你不需要的東西。
yum list installed >> ~/installed.txt
|
x86_64 用戶: 如果你不需要 i386/i686 套件來提供兼容性,你或許會想用 yum remove *.i?86 來移除它們,然後在 /etc/yum.conf 內加入 exclude = *.i?86 來防止它們再出現。 |
1. 定期更新
既然我們已經設定了最細的套件集,我們便須要定時更新它們。我不建議使用 yum-updatesd,因為它給我太多搶奪資源的壞經驗。你可以設立一個 cron 工作來進行更新或檢查更新,這亦是 NSA 指南的建議。你可以簡單地每週進行手動更新,或者赴力設置一個 spacewalk 伺服器進行跨系統的更新管理。不論你採用哪一種更新政策,它基本上是:適時地進行更新來避免問題發生。另外,訂閱 CentOS-Announce 這個郵件列表亦是一個不錯的主意。這樣,每次有更新時,你都會收到通知,而你便可以按所需加入重要的修正。
一旦你已經充份地修剪及更新你的套件清單,你好應該檢查你的服務清單及停用任何在伺服器上不需用的服務。再一次,由於每個環境都不同,我不會試圖告訴你甚麼應該或不應該被停用;然而,你應該自問伺服器是否真的需要 bluetooth 服務 :-P
基本加固
既然我們已經完成磁碟分割、收窄權限、及修剪套件清單,現在是時候進到核心部份。是時候將系統加固了。下列某些方法或許不適用於你的環境。你應該考慮每個方法,但你的處境或許需要用到別的方法。
1. 實體保護
- 只容許直接為伺服器負責任的人員接近它。
- 不要以可卸式媒體作為預設開機選項。
- 要求使用密碼來更改 BIOS 選項。操作系統上的保安對入侵者的自備操作系統是起不了作用的。
- 為 grub 設置密碼。保如有人在你的開機程式內輸入引數來停用保安設定,世上任何保安都沒有用。
- 在單一用戶模式下採用密碼。理由同上。
- 多數伺服器不需要 USB 儲存裝置。可能的話,停用 usb-storage 這個驅動程式。
關於如何保護 grub,請參閱 BIOS and Boot Loader Security。要令單一用戶模式詢問 root 的密碼,你可以用:
echo "# 啟動單一用戶模式時要求 root 密碼" >> /etc/inittab echo "~~:S:wait:/sbin/sulogin" >> /etc/inittab echo "避免人停止伺服器" perl -npe 's/ca::ctrlaltdel:\/sbin\/shutdown/#ca::ctrlaltdel:\/sbin\/shutdown/' -i /etc/inittab
假如你的環境中不會應用到 USB 儲存器,現在便停用它
echo "停用 USB 儲存器" echo "blacklist usb-storage" > /etc/modprobe.d/blacklist-usbstorage
2. 用戶權限
這算是最大的類別,包含了一些最重要的東西。由於每個機構都有所不同,它們未必全數適用於你,但請考慮它們。
在預設情況下,用戶被賦予不少自由度。你可以借著收窄這些寬限來加固系統。由於 root 擁有最多權力,我們就以限制 root 用戶作為一個開始。
2.1. 限制 root 用戶
一旦伺服器已經完成開機及在運行中,除非是緊急情況,否則 root 不應該直接登入。這些情況多數須要親身在控制台前,因此這應該是唯一容許 root 登入的地方。要這樣做,我們需要修改 /etc/securetty。此外,除了 root,其他人不應有權進入 root 的主目錄。預設值其實已很接近,但仍不夠嚴格。
echo "tty1" > /etc/securetty chmod 700 /root
因於我們基本上已經移除 root 從本地控制台以外登入的可能性,使用 su 及 sudo 已經成為必須的。這個做法在多管理員的環境下亦提供了一些次要的好處。
- sudo 容讓你更細緻地控制需要限權的動作。這樣的話,一個網頁管理者可以啟用、停用及管理網頁伺服器,而要會影響其它服務。
- 你的日誌能夠提供一幅更清析的圖畫,顯示誰人做了甚麼,因為何人在何時成為 root 不再是一個謎。
2.2. 密碼政策
我們大致上已經限制了 root,是時候處理其它用戶了。首先我們要為新建立的戶口設定一些基本原則。
- 採用強效的密碼。一個強效的密碼應該包含大小寫、特殊符號、數目字、及擁有最少 8 個字完。
- 對密碼的複雜情度有所要求,藉此實施採用強效密碼。
- 密碼應該定時更替。有些人爭議更改密碼的重要性,但你的密碼越用得久,其他人就越有時間來破解它。相對地,如果你經常更改密碼,你的用戶會偏向使用較弱的密碼,以便記憶。你應該為你的機構選擇一個合適的中間位。
- 密碼不應在一日內更改多過一次
echo "密碼每 180 日便失效" perl -npe 's/PASS_MAX_DAYS\s+99999/PASS_MAX_DAYS 180/' -i /etc/login.defs echo "密碼每日只可更改一次" perl -npe 's/PASS_MIN_DAYS\s+0/PASS_MIN_DAYS 1/g' -i /etc/login.defs
以下的指令會更新你的系統以 sha512 取代 md5 作密碼的保護。這個做法會緩解一些官僚方面有關以 md5 保護密碼的安全問題。這樣做亦能讓多疑的人安心。
authconfig --passalgo=sha512 --update
2.3. 限制 umask
更改預設的 umask 可以令事情變得有趣。我們建議用 077 作為一個安全的 umask,但它會對經常分享檔案的用戶構成很大不便。如果你決定實施這個方案,請聆聽你用戶的意見。
perl -npe 's/umask\s+0\d2/umask 077/g' -i /etc/bashrc perl -npe 's/umask\s+0\d2/umask 077/g' -i /etc/csh.cshrc
由這裡開始事情變得有點巧妙。假如一個用戶無法輸入正確的憑證,pam_tally2 將會拒絕存取直至 unlock_time 時間已過去。換句話說,假若你在 3 次內無法正確登入,你將要等候一段時間才能再次作出嘗試。
2.4. 修改 pam
現在我們需要更新 /etc/pam.d/system-auth
touch /var/log/tallylog cat << 'EOF' > /etc/pam.d/system-auth #%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth required pam_deny.so auth required pam_tally2.so deny=3 onerr=fail unlock_time=60 account required pam_unix.so account sufficient pam_succeed_if.so uid < 500 quiet account required pam_permit.so account required pam_tally2.so per_user password requisite pam_cracklib.so try_first_pass retry=3 minlen=9 lcredit=-2 ucredit=-2 dcredit=-2 ocredit=-2 password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=10 password required pam_deny.so session optional pam_keyinit.so revoke session required pam_limits.so session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid session required pam_unix.so EOF
/var/log/tallylog 是 pam 用來記錄失敗登入的二進制日誌。你可以利用沒有引數的 pam_tally2 指令來檢視失敗了的登入嘗試,或者用 pam_tally2 --reset -u <用戶名稱> 提早將戶口解封。
2.5. 移除閒置用戶
現在我們已經限制了伺服器的登入選項,讓我們移除閒雜人等。要這樣做,我們須要利用 /etc/profile 內的一個 bash 變數。當然有些簡單的方法可以避過它,但我們想要的是多重保安。
echo "閒置用戶在 15 分鐘後會被移除" echo "readonly TMOUT=900" >> /etc/profile.d/os-security.sh echo "readonly HISTFILE" >> /etc/profile.d/os-security.sh chmod +x /etc/profile.d/os-security.sh
2.6. 限制 cron 及 at
在某些情況下,管理員或許會想容讓 root 或其它受信任的用戶執行 cron 工作或 at 的腳本。要加固它們,你需要在 /etc 內建立含有所有被拒用戶名稱的 cron.deny 及 at.deny 檔案。達至這個目標的一個簡單方法就是剖析 /etc/passwd。以下的腳本可以為你服務。
echo "加固 Cron" touch /etc/cron.allow chmod 600 /etc/cron.allow awk -F: '{print $1}' /etc/passwd | grep -v root > /etc/cron.deny echo "加固 AT" touch /etc/at.allow chmod 600 /etc/at.allow awk -F: '{print $1}' /etc/passwd | grep -v root > /etc/at.deny
網絡安全
我們已經初步將保護給予操作系統,現在是時候檢視基本的網絡功能。在這裡我們不會太關注在服務上。我們只會從管理的角度看介面本身及 ssh。
1. 內核網絡安全
有數過方法只需透過簡單的改動,及將某些模塊放入黑名單,已經能夠改善網絡的安全性。
1.1. 停用無線上網
由於我們在討論伺服器的安全問題,無線上網其實不應在議題之內。如果你需要一個無線網絡,你可以略過這部份,因為我們將要停用所有無線驅動程式。你可以遂一檢視你的內核在 /lib/modules 裡的內容並移除所有無線驅動程式。這樣做的確可以停止無線上網,但不是一個永久性的解決辦法。每當你將內核升級,它們又會再出現,而你必需重複這個動作。反過來,我們可以用一個簡單的迴圈,透過 /etc/modprobe.d 內的黑名單檔案來停用它們。
for i in $(find /lib/modules/`uname -r`/kernel/drivers/net/wireless -name "*.ko" -type f) ; do echo blacklist $i >> /etc/modprobe.d/blacklist-wireless ; done
1.2. sysctl 保安
接下來我們需要看看 /etc/sysctl.conf 的內容並作出一些基本的改動。如果這些行已經存在,請更改它們至下面的模樣。假如它們不存在,你只需加入它們。如果你的伺服器有多個網絡介面,下面某些內容或許會構成問題。請在正式使用它們前進行測試。如果你想知道更多關於這些選項,安裝 kernel-doc 這個套件,並參閱 Documentation/networking/ip-sysctl.txt。
net.ipv4.ip_forward = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.tcp_max_syn_backlog = 1280 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.accept_source_route = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.tcp_timestamps = 0
1.3. 利用 TCP 包裝函式
TCP 包裝函式可以提供一個簡便、快捷的方法來控制相關應用程式的存取權。能配合 TCP 包裝函式的應用程式包括 sshd 及 portmap。下面是一個有限的範例。這個範例攔截所有不是 ssh 的流量。
echo "ALL:ALL" >> /etc/hosts.deny echo "sshd:ALL" >> /etc/hosts.allow
1.4. 強化 iptables
CentOS 預設的 iptables 規則集比較上是寬鬆了一些:預設的政策接納流量,有些連接埠被敞開,而流量基本上不必問責。我們可以做得更好。
在編輯器內開啟 /etc/sysconfig/iptables,並讓我們看看它。在首 3 行內已經有兩個問題。INPUT 及 FORWARD 這兩條規則鏈被設定為接納一切。接下來我們看見 50、51、5353、631 及 22 號埠被開啟。我對 22 號埠沒有太大問題。但其它連接埠不應在這裡,除非你想 mDNS、cups、及 ipsec 與外界溝通。我一般不喜歡陌生人使用我的打印機。
這裡亦未有將惡意掃描或其它不受歡迎的行為記錄下來。一個較強的規則集會是這個樣子:
#丟棄任何未經特別批准的東西。容許所有對外的流量 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :RH-Firewall-1-INPUT - [0:0] -A INPUT -j RH-Firewall-1-INPUT -A FORWARD -j RH-Firewall-1-INPUT -A RH-Firewall-1-INPUT -i lo -j ACCEPT -A RH-Firewall-1-INPUT -p icmp --icmp-type echo-reply -j ACCEPT -A RH-Firewall-1-INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT -A RH-Firewall-1-INPUT -p icmp --icmp-type time-exceeded -j ACCEPT # 接納 ping -A RH-Firewall-1-INPUT -p icmp --icmp-type echo-request -j ACCEPT # 記錄在 eth0 上所有聲稱來自本地或不須選路的網絡的東西 # 如果你使用下面其中一個本地網絡,請從以下清單中移除它 -A INPUT -i eth0 -s 10.0.0.0/8 -j LOG --log-prefix "IP DROP SPOOF A: " -A INPUT -i eth0 -s 172.16.0.0/12 -j LOG --log-prefix "IP DROP SPOOF B: " -A INPUT -i eth0 -s 192.168.0.0/16 -j LOG --log-prefix "IP DROP SPOOF C: " -A INPUT -i eth0 -s 224.0.0.0/4 -j LOG --log-prefix "IP DROP MULTICAST D: " -A INPUT -i eth0 -s 240.0.0.0/5 -j LOG --log-prefix "IP DROP SPOOF E: " -A INPUT -i eth0 -d 127.0.0.0/8 -j LOG --log-prefix "IP DROP LOOPBACK: " # 接納任何已設立的連線 -A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 接納 ssh 流量。可能的話,限制到已知的 IP 位址。 -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT # 記錄並丟棄餘下的封包 -A RH-Firewall-1-INPUT -j LOG -A RH-Firewall-1-INPUT -j DROP COMMIT
你可能會爭議我們既然回答 ping,丟棄流量而不拒絕它們實在騙不到誰。這只是個人喜好。如果你寧願拒絕流量,你可以將 COMMIT 前一行改為:
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
防止纂改
由於我們放上了不少時間來加固系統,及設置它按你的方式運作,一般來說,確保別人不會瞞著你纂改它是一個好主意。這一點對於擁有多位管理員的機構,與提防壞蛋來說都同樣適用。CentOS 內置了兩個非常好的工具來保護你的系統。第一個工具是 aide。aide 有些像 tripwire,它可以定期將你系統內主要的檔案與散列對比來找出改動。第二個工具是 auditd。CentOS 內的 audit 子系統會按照你所定的規則,即時監視你的系統。它會記錄你要求它所做的一切動作,與及格外的資訊。
如果可以的話,你應該考慮在一個非公開的網絡介面上設立一個中央的日誌收集服務。假若日誌被傳送到一個無法存取的遠端系統,惡意用戶便更難隱藏他們的踪蹟。
1. aide
為了免得我重覆別人已做的工夫,有關如何設置 aide 請參閱 http://www.server-world.info/en/note?os=CentOS_7&p=aide。然而我們建議你採用以下 crontab 項目取代該網站的版本。
00 01 * * * /usr/sbin/aide --check | mail -s 'Daily Check by AIDE' root
雖然該網站提及 CentOS 7,這些步驟同樣適用於舊的 CentOS 發行版本。
2. auditd
有待寫成
Translation of revision 32