動手學 VPS 架站:使用 CentOS 7 + Nginx + PHP-FPM + MariaDB (5) - SSH 登入安全

LNMP

要讓系統安全有許多工作要做,第一件事就是確保登入安全。

3.1 準備動作

在 Linux 中,有一個最高權限的使用者帳號稱為 root,這個帳號能夠對系統做任何事,因此你必須確保它不被他人竊取。當有人想要嘗試登入你的電腦時,他第一個會做的就是以 root 的身份來嘗試登入,因為這個帳號大家都知道,他只要猜密碼就可以了。為了避免這個問題,首先要做的就是讓 root 無法登入,既然無法登入,那密碼怎麼猜也沒用,這也就是為什麼我們需要先建立一個一般使用者,然後永遠只以一般使用者的帳號來登入系統。

使用一般使用者帳號來登入系統還是有風險,因為你仍然要輸入密碼,只要有密碼就能猜,能猜就可能被猜中;一個更加安全的方法是使用加密金鑰,你 (本機) 一把、伺服器一把,傳輸資料加、解密都靠它。

因為 Vagrant 已經建立了一個以加密連線方式登入的帳號 vagrant,所以我們會用它來登入虛擬機器,但一般來說,你會以 root 登入一台初次安裝的伺服器。

首先,請先確認 Vagrant 的虛擬機器已經啟動並且登入:

vagrant up
vagrant ssh

這裡請你想像這台虛擬機器是遠在天邊的一台伺服器。

當你登入虛擬機器後,會是 vagrant 這個使用者帳號,我們要先把它切換成 root

[vagrant@localhost ~]$ su
# 接著輸入密碼 vagrant

# 確認目前身份
[root@localhost vagrant]# whoami

你會發現一般使用者和 root 的提示符號不同,一般使用者是 $ 錢字號,root 則是 # 井字號。指令 su 可以用來切換身份為 root

到此為止是使用 Vagrant 環境所必須做的動作,之後的內容請想像你真的在操作一台剛安裝好的伺服器。

3.2 建立使用者

我們將練習建立一個 tony 使用者,並且使用金鑰來登入。

# 建立名稱為 tony 的使用者
adduser tony

# 設定 tony 使用者的密碼
passwd tony

如果你不想要這個使用者,可以刪除它:

# 刪除名為 tony 的使用者(保留家目錄)
userdel tony

# 同上,但同時刪除家目錄
userdel -r tony 

使用者的家目錄在 /home 目錄底下,例如 tony 使用者的家目錄就是 /home/tony

註:請不要刪除 Vagrant 內建的 vagrant 使用者,因為 Vagrant 預設是使用該帳號登入。

3.3 使用金鑰登入伺服器

我們會使用終端機透過連線程式連到遠端的伺服器,早期是使用 telnet 來連線,但是它的缺點是以明碼傳輸資料,資料未經加密,會有被竊取的風險,因此後來都使用 SSH (Secure SHell) 來連線。SSH 是使用金鑰對來達成加密,金鑰由公鑰 (public key) 及私鑰 (private key) 配對使用。

當你第一次使用 SSH 連線到伺服器時,指令會像這樣:

ssh root@yourserver.com

伺服器會自行產生金鑰,並且傳送公鑰到你的電腦,你會收到是否要信任此公鑰的訊息,當你輸入 yes 後,就可以使用加密連線來通訊,接著輸入密碼來登入此伺服器,因為連線已經加密,所以不用擔心密碼被看見。

3.3.1 小心中間人攻擊

使用金鑰的連線方式仍是有風險的,由於公鑰是由伺服器送給你的,在這傳送的過程中,任何人都可能拿到這把公鑰。於是有心人就可以偷走這把公鑰,然後轉送它自己的公鑰給你,你會誤以為這是伺服器給你的公鑰而信任並使用它來傳送資料,這個有心人就可以在你和伺服器之間當成中間人,完全取得你和伺服器所傳送的資料,這就是中間人攻擊 (Man-in-the-middle attack, MITM)。中間人攻擊可以藉由身份驗證 (第三方的憑證認證機構來驗明正身) 和篡改檢測 (以連線時間過長來判斷是否被攻擊) 來防禦。

下圖為中間人攻擊的示意圖: 圖片來源:Miraceti - https://commons.wikimedia.org/w/index.php?curid=5672044

3.3.2 密碼驗證 vs 金鑰驗證

通常連線到伺服器的第一件事就是輸入帳號及密碼,但是每次登入都要做重複的事,久了就會覺得麻煩,二來如果帳號及密碼被猜到就完了,這就是密碼驗證的小缺點。相對來說,使用金鑰驗證就很方便,除了第一次使用需要設定以外,之後就可以直接登入,完全不用輸入密碼,當然也就不用擔心密碼被偷或被猜中的問題,唯一要注意的就是私鑰要保管好。

3.3.3 金鑰使用流程

首先,你在本機電腦中自行產生金鑰對,包含公鑰及私鑰,然後將公鑰以安全的方式上傳到遠端伺服器。當你在本機上透過 SSH 和遠端伺服器連線時,伺服器會以公鑰加密一段隨機文字,然後傳給本機;本機使用私鑰解開該加密的隨機文字,然後回傳結果給伺服器,伺服器確認正確後就會允許連線。

假設你有 5 台伺服器要管理,只要將公鑰分別存放到這 5 台伺服器上即可,擁有私鑰的本機就能成功連線,這也就是為什麼私鑰很重要,被偷了的話,任何人都可以使用該私鑰進行連線。

在產生金鑰對時也可以對私鑰設定密碼 (passphrase),假如私鑰被偷的話,就必須輸入對的密碼才能使用。但這樣在登入時就又會要求你輸入密碼,只不過這次不是伺服器上帳號的密碼,而是私鑰的密碼。

3.3.4 實戰 SSH 金鑰設定

步驟一:在本機上產生金鑰對

在 Mac/Linux 上使用 ssh-keygen 指令來產生金鑰:

ssh-keygen -t rsa

它會詢問你要將金鑰存放在哪裡,預設的位置在使用者家目錄下的 .ssh 隱藏目錄中,例如: (Mac) /Users/tony/.ssh/ ,其中的 id_rsa 是私鑰的檔案名稱,id_rsa.pub 則是公鑰的檔案名稱。你可以直接按 Enter 使用預設值即可。

接著它會問你密碼 (passphrase),也就是私鑰的密碼,你可以留空白直接按 Enter,這樣的好處是,之後遠端連線登入伺服器時可以不用輸入密碼,比較方便。

完成後可以到使用者家目錄下的 .ssh 目錄查看是否有出現 id_rsdid_rsa.pub 兩個檔案。這裡要注意,必須小心把私鑰保存好,例如備份,公鑰不見了可以由私鑰再次產生,但是私鑰沒了就沒了,只能再產生一個新的,而這個新的可無法登入你原本的伺服器,你得重新上傳這把和新私鑰配對的公鑰才行。如果私鑰被偷走,那個人就能透過私鑰連線到你的伺服器,請務必小心。

步驟二:上傳公鑰

現在你已經擁有金鑰對,接下來就是把公鑰放到遠端伺服器上。

首先使用一般使用者帳號透過 ssh 連線登入,記住!絕對不要使用 root 帳號來登入。當你登入伺服器後,進入家目錄底下的 .ssh 目錄,沒有此目錄的話請自行建立 mkdir .ssh,裡面應該會有 authorized_keys 這個檔案,沒有的話一樣自行建立 touch authorized_keys,這個檔案會儲存公鑰,所有的公鑰都存放在這裡。

你有兩種方式來上傳公鑰:

# 本機輸入
ssh-copy-id username@123.45.56.78
# 這個指令會去預設目錄 ~/.ssh/id_rsa.pub 取公鑰上傳
# 如果你的目錄不一樣,可以加上 -i 選項來指定位置
ssh-copy-id -i ~/.ssh/id_rsa.pub username@123.45.56.78
# 這個 username 是指遠端伺服器的帳號,例如 tony

# 或是本機輸入
cat ~/.ssh/id_rsa.pub | ssh username@123.45.56.78 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 將 id_rsa.pub 的內容輸出,透過 SSH 傳送到遠端伺服器帳號的 authorized_keys 檔案中

步驟三:權限設定

為了確保你的公鑰的安全,我們要設定這個目錄及檔案只有我本人可以讀取,假設帳號為 tony :

cd /home/tony
# 把 .ssh 目錄擁有者改為 tony
chown -R tony:tony .ssh

# 修改 .ssh 目錄的權限,只有 tony 能讀寫及進入
chmod 700 /home/tony/.ssh

# 修改 authorized_keys 檔案的權限,只有 tony 能讀寫
chmod 600 authorized_keys

# RedHat 系的 Fedora 及 CentOS 必須重新還原 SELinux 的類型
restorecon -Rv /home/tony/.ssh

# 最後記得重新啟動 sshd
systemctl restart sshd

這樣就完成了。現在 tony 這個使用者帳號已經可以使用 ssh 連線到伺服器了:

ssh tony@192.168.8.8 # 這個 ip 是前面的 Vagrant 設定檔指定的

來測試看看能否用 tony 登入吧。

要登出伺服器,有三種方式:

  • 快速鍵 ctrl + d (建議用這個)
  • 輸入 logout
  • 輸入 exit

如果以上操作都順利的話,你現在已經完成登入安全的一半工作了。

3.4 關於 root

3.4.1 sudo

因為 root 的權限太大,實務上我們不會使用 root 的身分來操作系統,而是在需要的時候才使用 sudo 指令暫時取得 root 的權限來執行操作。如果每個帳號都能這麼做,那就沒有安全可言了,因此我們必須限制只有某些帳號才可以擁有 sudo 的能力,CentOS 為此設計了一個 wheel 群組,只有屬於 wheel 群組的使用者才能使用 sudo

首先,將可以使用 sudo 的使用者帳號加入 wheel 群組:

# 先查看目前帳號所屬群組
groups tony
# 結果 tony : tony

# 將帳號加入 wheel 群組
sudo usermod -aG wheel tony

# 再次查看結果
groups tony
# 結果 tony : tony wheel

現在帳號已經加入 wheel 群組了。接著要確認是否有把 wheel 群組設定為可以使用 sudo

sudo visudo 
# 等同於 sudo vim /etc/sudoers
# 接下來會在 vi 中編輯內容

# 直接輸入 /%wheel 來搜尋,會找到以下內容

# Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL # <-- 確認這行的註解有拿掉,意義如下
# %群組名稱    來源主機=(可切換帳號) 可執行的指令

# 完成後存檔離開 (esc -> :wq)

如果你要查看目前有哪些使用者帳號屬於 wheel 群組:

getent group wheel
# 結果 wheel:x:10:tony

3.4.2 su

隨便一個使用者就能切換成 root 也是非常危險的事,所以我們要讓非 wheel 群組的使用者無法使用 su 指令來切換成 root

sudo vim /etc/pam.d/su

auth  required  pam_wheel.so use_uid # <-- 取消這行註解

接著編輯 /etc/login.defs 檔案:

sudo vim /etc/login.defs

# 將 "SU_WHEEL_ONLY yes" 加到 login.defs 檔尾
SU_WHEEL_ONLY yes

使用 su 指令會要求 root 的密碼,使用 sudo 則是使用當前使用者的密碼;有時候可以搭配使用 sudo su ,就不需要輸入 root 的密碼。

3.5 加強 SSH 安全

當你確定可以使用金鑰的方式來連線伺服器後,就可以把其他登入方式封掉,來保證連線的極度安全。

以下我們會修改 SSH 伺服器的設定檔 /etc/ssh/sshd_config 來做 3 件事:

sudo vim /etc/ssh/sshd_config
# 編輯時,請善用斜線加字串來搜尋,例如 /PermitRootLogin
  1. #PermitRootLogin yes 改成 PermitRootLogin no 這個動作會禁止使用 root 帳號來登入。駭客要猜中你的帳號沒那麼容易,但 root 這個帳號大家都知道,只要去猜它的密碼,猜中了就成了這台機器的神,所以禁止使用 root 登入是很重要的事。請使用一般使用者帳號登入後,再視情況切換為 root
  2. #PasswordAuthentication yes 改成 PasswordAuthentication no 猜中密碼這件事是有可能的,但是如果不能使用密碼來驗證登入,那連猜都沒得猜了,所以我們把使用密碼驗證這個功能禁止。但是你的使用者帳號仍然要設定密碼,絕對不要使用空白密碼。
  3. #PermitEmptyPasswords no 改成 PermitEmptyPasswords no 這個動作會禁止使用空白密碼。請記住絕對不要使用空白密碼,任何帳號都是,尤其是 root

以上 3 個原始設定都是被註解掉沒有使用,現在我們將其啟用並且都設為不允許,請記得存檔後離開。

再提醒一次!請先確認你可以使用金鑰來連線登入伺服器,否則當 sshd_config 的設定生效後,你將無法使用一般方式登入伺服器。

記得要重新啟動 SSH 伺服器:

systemctl restart sshd

繼續閱讀:動手學 VPS 架站:使用 CentOS 7 + Nginx + PHP-FPM + MariaDB (6) - 防火牆

本文網址:http://blog.tonycube.com/2018/08/vps-centos-7-nginx-php-fpm-mariadb-5-ssh.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。