# 遠端連線與傳輸 > 維護網路伺服器最簡單的方式不是跑去實體伺服器前面登入,而是透過遠端連線伺服器連線功能來登入主機, 然後再來進行其他有的沒的維護就是了。[name=鳥哥] - Book mode: https://hackmd.io/@ncnu-opensource/book [TOC] ## 為什麼需要遠端連線 ### 情境 - 在學校想用家裡的好電腦 - 想使用 server 但又不能直接進去機房 ### 為什麼要遠端連線 - 更好的運算能力 - 方便管理主機 - 透過遠端連線伺服器的服務 ## 遠端連線方式概覽 1. 文字介面明文傳輸: telnet, rsh (remote shell) 等為主,目前非常少用; 2. 文字介面加密傳輸: ssh 為主,是 telnet, rsh 等明文連線技術的替代品; 3. 圖形介面: VNC, RDP 等較為常見 ### Telnet - 比較古老的系統環境會支援 - 使用明文來傳輸資料(未加密) - 可以利用監聽軟體 (e.g tcpdump ) 的監聽竊取 - 例子: 遠端連線進主機時,需要輸入帳號密碼,若沒有加密,帳號密碼都會被別人看光光 - 還有哪些明文傳送? - rsh 過時的遠端命令執行工具 - ftp 用於電腦之間傳輸檔案的標準網路通訊協定 - http 用於在客戶端(如網頁瀏覽器)和伺服器之間傳輸超媒體文件,如 HTML 頁面、圖像、影片等。 --- # SSH 網路傳輸協定 - 全名 : **S**ecure **Sh**ell 安全外殼協定 - 解決 telnet 明文傳輸的問題,但不代表使用 SSH 就不會被干擾、竊聽甚至解密 - 使用**非對稱式加密**方式做使用者驗證 :::info ### 不同加密方式 1. 對稱式加密:雙方都使用同一把密鑰加解密 ![](https://i.imgur.com/wM9nfL4.png) > 圖片來源 [基礎密碼學(對稱式與非對稱式加密技術). | by Chan @RiverChan | Medium](https://medium.com/@RiverChan/%E5%9F%BA%E7%A4%8E%E5%AF%86%E7%A2%BC%E5%AD%B8-%E5%B0%8D%E7%A8%B1%E5%BC%8F%E8%88%87%E9%9D%9E%E5%B0%8D%E7%A8%B1%E5%BC%8F%E5%8A%A0%E5%AF%86%E6%8A%80%E8%A1%93-de25fd5fa537) + 對稱式加密最大的弱點是,要是這把鑰匙在第一次傳送時,被中間人攔截且複製,再原封不動傳給接收方,那之後所有攔截到的加密訊息,都能被輕易破解 2. 非對稱式加密 (Asymmetric encryption) + 雙方各有一對公私鑰,互換公鑰後用對方的公鑰加密 + 公鑰 (public key):提供給遠端主機進行資料加密的行為,也就是說,**大家都能取得你的公鑰來將資料加密**的意思; + 私鑰 (private key):遠端主機使用你的公鑰加密的資料,在本地端就能夠使用私鑰來進行解密。由於私鑰是這麼的重要, **因此私鑰是不能夠外流的!只能保護在自己的主機上**。 ![](https://i.imgur.com/4rlNFQe.png) > 圖片來源 [基礎密碼學(對稱式與非對稱式加密技術). | by Chan @RiverChan | Medium](https://medium.com/@RiverChan/%E5%9F%BA%E7%A4%8E%E5%AF%86%E7%A2%BC%E5%AD%B8-%E5%B0%8D%E7%A8%B1%E5%BC%8F%E8%88%87%E9%9D%9E%E5%B0%8D%E7%A8%B1%E5%BC%8F%E5%8A%A0%E5%AF%86%E6%8A%80%E8%A1%93-de25fd5fa537) + 若單純用公私鑰,仍然會有被偽造的風險 + 數位簽章可解決 + 傳送方除了使用接收方的公鑰加密外,也使用自己的私鑰對該封加密訊息的 Hash 簽名,以達到二次驗證 > FIXME: 多講數位簽章跟加密的東東 ::: :::info ### Hash 雜湊函式 $H(x) = x \mod B$ - 將不定長度訊息的輸入,演算成固定長度雜湊值的輸出[^hash] - 由雜湊值是無法反推出原來的訊息 - 雜湊值必須隨明文改變而改變 ::: [^hash]: [[資料結構] 雜湊 (Hash) - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10208884) - SSH 的驗證方法 1. 基於密碼的安全驗證 - 知道帳號和密碼,就可以登入到遠端主機 2. 基於金鑰的安全驗證 - 使用者將公鑰放在需要存取的伺服器上 - 使用者端提出身份驗證,告訴伺服器:「我要用 **某個公開金鑰** 登入」 - 伺服器檢查這個公鑰是否存在於 `~/.ssh/authorized_keys` - 伺服器隨機產生一段訊息,加密後送給使用者端,並要求使用者端用 **自己的私鑰 (private key)** 來「簽署」這段挑戰 - 若使用者端成功解開質詢,代表使用者端確實擁有私鑰 → 登入成功 --- 假設今天我想要使用 SSH 傳一個訊息給 BT, 我們 ==*"已經互相擁有對方的公鑰"*== 了 ,並且擁有各自的私鑰,此時會有五個步驟: 1. 我用自己的私鑰將訊息簽名。 2. 我用 BT 的公鑰將訊息加密。(此時,被加密的訊息連我自己也無法還原-只有 BT 的私鑰可以!) 3. 我將訊息傳給 BT。 4. BT 將訊息用自己的私鑰解密。 5. BT 用我的公鑰來確認這個訊息是用我的私鑰簽名的。 上面的例子聽起來萬無一失,但是假設今天我與 BT 還沒有交換公鑰,他們就必須要先連線傳送公鑰給對方。如果壞人屁眼在我要把公鑰傳給 BT 時調包,換成屁眼自己的公鑰,這時與 BT 建立「安全連線」的人,就會是屁眼而不是我了,SSH 能夠提供的保護只在確保公鑰的擁有者同時擁有相對應的私鑰,但是不能保證擁有這個公私鑰組合的人是不是壞人。這就是著名的 **「中間人攻擊」(man-in-the-middle-attack)**。 :::info ### 中間人攻擊 ![image alt](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Man_in_the_middle_attack.svg/800px-Man_in_the_middle_attack.svg.png?20110724142026 "title" =640x454) > 圖片來源 [File:Man in the middle attack.svg](https://commons.wikimedia.org/w/index.php?title=File:Man_in_the_middle_attack.svg&oldid=676928010). by [Miraceti](https://commons.wikimedia.org/wiki/User:Miraceti) . Wikimedia Commons > - 圖中 Mallory 是密碼學中常用來代表「惡意的攻擊者」虛構角色的人名 - **中間人攻擊** (**M**an-**i**n-**t**he-**M**iddle Attack, 縮寫: **MITM**) - 在密碼學和電腦安全領域中常提到的一個概念 - 指攻擊者與通訊的兩端分別建立獨立的聯絡,並交換其所收到的資料,使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個對談都被攻擊者完全控制。 ::: :::warning **我用我自己設定好的帳密登入,不就是用同一把密鑰登入,算不算對稱式加密?** ::: --- ## SSH 連線完整流程 ### 登場角色 + Client:你輸入 `ssh user@server` 的電腦 + Server:伺服器,第一次被連線 ### 1. TCP 連線 Client 與 Server 透過 TCP 建立連線(通常在 port 22) ### 2. 協商與版本交換 雙方交換 SSH 協議版本與支援的演算法清單(加密、壓縮、MAC…),例: + Client:`SSH-2.0-OpenSSH_9.7` + Server:`SSH-2.0-OpenSSH_8.2` ### 3. Host Key 驗證 (伺服器身分驗證) + Server 把它的 **主機公鑰 (Host Public Key)** 傳給 Client。 + Client 端檢查: + **第一次連線** → Client 本地 `~/.ssh/known_hosts` 沒有記錄 → 跳出提示: ```bash= The authenticity of host 'server (192.168.x.x)' can't be established. ECDSA key fingerprint is SHA256:xxxx... Are you sure you want to continue connecting (yes/no/[fingerprint])? ``` + 使用者如果選「yes」→ 伺服器的 host key 會被寫入 `~/.ssh/known_hosts`。 + 之後每次連線都會比對 host key,若不同就會警告(避免遭到中間人攻擊 MITM)。 **這一步不是驗證使用者,而是驗證伺服器真的是我們要的那台。** ### 4. Key Exchange (會話金鑰產生) + 雙方透過 **非對稱金鑰演算法 (例:Diffie–Hellman, ECDH, Curve25519)** 進行 **金鑰交換**。 + 雙方獨立算出一個 **共享會話金鑰 (session key)**,不需在網路上傳輸。 + 之後所有流量都用這個 session key 進行 **對稱式加密 (AES, ChaCha20 …)**。 **從這一步開始,所有通訊都在加密通道中進行。** :::warning **加密通道在 OSI 哪個 Layer?** ::: ### 5. 使用者身份驗證 (Authentication) **密碼登入情況** 1. Client 輸入密碼。 2. 密碼經過已建立的 **加密通道** 傳到 Server。 3. Server 驗證密碼是否正確 4. 正確 → 登入成功;錯誤 → 拒絕。 :::info ### client-server model ![Client-server-model.svg](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Client-server-model.svg/1000px-Client-server-model.svg.png?20141205053432) > 圖片來源 [File:Client-server-model.svg](https://commons.wikimedia.org/w/index.php?title=File:Client-server-model.svg&oldid=928363449). 由 Calimo 以 David Vignoni 的 [Gnome-fs-client.svg](https://commons.wikimedia.org/wiki/File:Gnome-fs-client.svg), [Gnome-fs-server.svg](https://commons.wikimedia.org/wiki/File:Gnome-fs-server.svg) 為基礎來創作. Wikimedia Commons. - 主從(ㄗㄨㄥˋ)式架構 - 客人與櫃台的關係 - **client** 特徵 - 主動的角色(主) - 發送請求 - 等待直到收到回應 - **server** 特徵 - 被動的角色(從) - 等待來自使用者端的請求 - 處理請求並傳回結果 ::: :::warning **所以 SSH 到底是對稱還是非對稱加密?** ::: --- ## 基礎操作 ### 安裝 - 更新軟體的最新資訊及列表: `sudo apt update` - 安裝 server 端套件: `sudo apt install openssh-server` - 同時安裝 server 及 client: `sudo apt install ssh` :::info ### Appendix - ssh 好多種? - `apt-cache search [keyword]` 找軟體指令 - ![](https://hackmd.io/_uploads/r1GbPzn-p.png) - 可以觀察到有許多 ssh ,可以注意到以下這三種 - `openssh-client` - `openssh-server` - `ssh` (metapackage) - `openssh-server` for server ,必須等待來自使用者端的請求,所以於遠端的主機必須要有 ssh-server - 而 `openssh-client` 只負責發送資訊給 server 對應的 port - ssh (metapackage) 則是包含 client and server - metapackage 表示它不包含任何軟體安裝檔,它是導向到所需的相依安裝檔 - 把使用 ssh 完整服務所需要的所有檔案都安裝 - 延伸閱讀:[MetaPackages - Community Help Wiki](https://help.ubuntu.com/community/MetaPackages) - `openssh-client` 於 Ubuntu Desktop 中已內建,如果沒有要做連入的主機可以不安裝 `openssh-server` > P.S: Windows 10 1809 的 cmd 中也內建了 openssh-client ::: ### 確認 server 狀態 - 查看服務狀態 - `sudo systemctl status ssh` - 查看 ssh 佔用 port - `sudo ss -ltpn` - `-l`: 列出傾聽狀態(listening)的 sockets - `-t`: 只列出 TCP 的 sockets - `-p`: 顯示使用 sockets 的程式資訊 - `-n`: 不要嘗試把 port 號解析成服務名稱 :::success **Q. http & https 分別用哪個 port?** ::: ### 開啟關閉與重啟 server - `sudo systemctl start ssh` 開始 - `sudo systemctl stop ssh` 停止 - `sudo systemctl restart ssh` 重新啟動;關掉再打開 ### 由 client 登入 - 登入本機 - `ssh localhost` - `ssh 127.0.0.1` - `ssh [username]@127.0.0.1` - 本機地址 / 局部回送位址 (local loopback addresses) - 通常 `localhost` 會被解析成 `127.0.0.1` - 見 `/etc/hosts` 檔案 - IP 中 `127.0.0.1/8` 被設定為保留地址,所有向這個 IP 發送的封包都會留在本機 - 而 localhost 被作為頂級域名,不得有任何網域註冊此名稱 :::info 大部分情況下你不會特地 `ssh localhost`,因為直接在本機打指令就能做,最常見情況是: 剛安裝或修改過 `OpenSSH Server` 設定時,會用 `ssh localhost` 確認服務能連上、帳號登入沒問題 ::: - 登入遠端 - `ssh [username]@[hostname]` - 不指定使用者則以目前狀態的使用者進行遠端登入 ### 常用操作參數 - `ssh -p [port num] [username]@[hostname]` 指定 server 的 port 號(預設 22) - server 端可以在設定檔中改變 port 號,如 port 號被更改就需要利用此方式登入 - `ssh [username]@[hostname] '[cmd]'` 執行單行指令,很長的時候再包起來 - ![](https://hackmd.io/_uploads/SJ7BnLgfp.png) - `ssh -f [username]@[hostname] '[cmd]'` 背景執行指令 - 即送出指令後可在原本的本機做事情 - `ssh -v [username]@[hostname] ` 使用偵錯模式連線 - 可使用 `-vv`、`-vvv`,v 越多,過程顯示的越多 - 有問題可以去看出了什麼問題 - `exit` / `logout` / `Ctrl+D` 退出連線 - `ssh -A` 允許 Forward agent :::spoiler 點此展開進階用法,暫時略過 > FIXME: 可能要加一下 -A 和 -X 成功的 demo - `ssh -X` 允許遠端打開圖形化介面視窗 > FIXME: -X 可能會無法運作,理解一下原因以及解法 > Ref: [xorg - X11 forwarding - Putty - Xming: Why app run on the server instead of the client side? - Super User](https://superuser.com/questions/1843704/x11-forwarding-putty-xming-why-app-run-on-the-server-instead-of-the-client) > Ubuntu 22.04 預設是 Wayland,而不是 X server - `ssh -o` 根據 ssh_config 做單次的設定 - `ssh -o ConnectTimeout=3 [username]@[hostname]` 等待時間如果超過三秒即斷線 ::: --- ## 密碼登入 - 流程圖 - ![](https://hackmd.io/_uploads/B1pHVWkGT.png =600x) > 流程圖來源:1121 LSA-I Week 08 [Linux 遠端連線](https://hackmd.io/@wzray07/HJN8ChbC3#%E5%AF%86%E7%A2%BC%E7%99%BB%E5%85%A5) 講義 by @wzray07 1. Client 請求登入,Server 回覆版本以及加密協議 2. Session Encryption Negotiation,進行密鑰協商 4. 密鑰協商後的 key 為最終資料傳輸的金鑰 5. Server 發公鑰給 Client,讓 Client 比對 Server 的身分 6. 上一步沒問題,使用者輸入帳密後,Cliient 將密碼使用 server 的公鑰加密後傳輸給 server 7. 最後雙方再以協商的密鑰,接收登入訊息並開始操作系統 :::success **Lab 登入** 打開你的 terminal,登入 ```bash= ssh [s學號]@moli.lsa.tw ``` 密碼是 `Temp#2025!` ::: --- ## 利用公鑰進行無密碼登入 一般我們登入伺服器可以透過密碼進行登入,但是安全性的程度會比較沒有像 SSH key 那個安全,而且如果使用 SSH key 登入的話可以就不用每次手動輸入密碼,會方便許多,本篇教如何產生 SSH key 並且設定到伺服器上。 ### 1. 在自己的使用者端 (client) 電腦上,產生一組金鑰對: 公開金鑰 (public key) / 私密金鑰 (private key) - `ssh-keygen -t ed25519` - `-t`: 指定用哪種加密方式,預設為 rsa - `-b`: 指定要生幾 bits 的金鑰 (不一定需要這參數) - 以安全性推薦使用 ed25519 代替 rsa,但舊的伺服器可能只支援 rsa - 輸出: ``` $ ssh-keygen -t ed25519 Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_ed25519): /home/user/.ssh/id_ed25519_lsademo Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_ed25519_lsademo Your public key has been saved in /home/user/.ssh/id_ed25519_lsademo.pub The key fingerprint is: SHA256:icqDAThC3dD/aQItF7e5ZU4n0vXgn4ot3JvxicYtEjI user@host The key's randomart image is: +--[ED25519 256]--+ | ...+ | |o . o . . o | |= o o + o o | |.o o = = * o . | | . = S O o . .| | + . . E o o | | . + o + *.o | | . = B=..| | ++oo | +----[SHA256]-----+ ``` - 會問你要存在哪個位置,若不輸入直接按 Enter 則採用預設位置: - 私鑰會存在 `~/.ssh/id_ed25519` -> 自己留著,不能給別人的 - 公鑰會存在 `~/.ssh/id_ed25519.pub` -> 傳給別人的 - 若遇到檔名已存在,輸入 `y` 會覆蓋過去 ``` /home/user/id_ed25519 already exists. Overwrite (y/n)? y ``` - passphrase 可輸可不輸 - 若不輸入直接按 Enter 則無 passphrase - 若有設則後續每次使用此金鑰都會問你這段密碼 - 但現代一點的 OS 會有 ssh-agent 幫你暫時記住 - Fingerprint / randomart - 舊版本只有 Fingerprint 供大家可以連線時核對,但要檢查一長串文字不太容易[^Random_art] - 新版本更新成隨機圖像樣式,讓大家在連線時核對更方便 - 如何核對? - `ssh -o VisualHostKey=yes [username]@[hostname]` [^Random_art]: [ssh-keygen 在建立金鑰時所產生的 randomart 是做什麼用的? – G. T. Wang](https://blog.gtwang.org/tips/ssh-keygen-randomart/) :::info ### RSA 和 ED25519 差別 - `rsa` 預設 - **R**ivest–**S**hamir–**A**dleman,3 個人名組成的縮寫 - 相容性最好,支援稍舊的版本 - 密碼長度可選擇 `1,024` ~ `16,384` bits ,現在預設為 `2,048` bits - `2,048` bits 以下都不建議用,如需提升安全性可選擇更長的 key ,如:`4,096` bits - `ed25519` 較推薦使用 - 較新,OpenSSH 6.5 版本以後就都支援 - 安全性最好 - 更快的產生金鑰 - 更快的身分驗證 - 長度固定 - 公鑰 `256` bits,被 OpenSSH 編碼成 `68` 個 16 進位字元(chars) - 是使用 SHA-512(SHA-2)和 Curve25519 的 EdDSA 簽名方式 - 扭曲的愛德華茲曲線 - `ecdsa` - 有 `256`, `384`, `521` bits 三種 key 長度可以選擇,無法選擇其他的使用 - 公鑰長度相比 RSA 較小 - 應用了**橢圓曲線加密法** :::warning **鑰匙長度越長 → 一定比較安全?** - RSA - 安全性建立在「大整數分解困難」上。 - 攻擊者必須把一個由兩個大質數乘起來的數拆解回去,這在數學上困難,但隨著硬體與演算法進步(像是 Number Field Sieve, NFS),RSA 的安全性會慢慢下降。 - 因此要維持安全,只能一直「加大鑰匙長度」。 - 今天常見的 **RSA-2048**,大約相當於 **112-bit 對稱金鑰強度**。 - Ed25519 (Elliptic Curve Digital Signature, Edwards Curve 25519) - 安全性建立在「橢圓曲線離散對數問題 (Elliptic Curve Discrete Logarithm Problem, ECDLP)」的困難度上。 - 相較於整數分解,這個問題目前沒有像 NFS 那樣高效的解法。 - 因此 **短很多的鑰匙長度就能達到相同甚至更高的安全強度**。 - Ed25519 的 256-bit 鑰匙安全等級大約等同於 **128-bit 對稱金鑰強度**。 如果要在 RSA 達到類似安全強度,得用到 **RSA-3072 (≈128-bit 強度)** 或 **RSA-4096 (≈152-bit 強度)**。 ::: ### 2. 把公鑰複製到遠端主機 server 上 - 方法一 - 用 ssh-copy-id 傳送公鑰到遠端主機 `ssh-copy-id -i ~/.ssh/id_ed25519.pub [username]@[hostname]` - 若要指定 port `ssh-copy-id -i ~/.ssh/id_ed25519.pub -p [port] [username]@[hostname]` * 方法二,手動複製 1. `cat ~/.ssh/id_ed25519.pub` 2. 用帳號密碼登入遠端主機 server 3. `cd ~/.ssh` 4. 在遠端主機新增檔案 `touch authorized_keys` 5. 將 `id_ed25519.pub` 公鑰內容放入 `authorized_keys`中,以換行方式區分不同支公鑰 `vim authorized_keys` 5. `chmod -R go= ~/.ssh` 把這個資料夾中所有檔案的 group 及 other 權限拿掉 ### 3. 測試是否成功 試試看是否能正常登入使用key登入 ``` $ ssh username@remote_host ``` 如果能夠不需要輸入密碼 就表示已經成功了 :::success **Lab 把金鑰放到剛剛登入的 server** ::: :::info 若遇到權限問題,用 `chmod 600 ~/.ssh/authorized_keys` ::: :::info ### 更換 ssh-server 公鑰 - 為了讓大家得知什麼樣的情況會跳出警告 - 先關閉 ssh 服務 &gt; 做任何相關設定檔調整前建議關閉服務再進行調整 - `sudo rm /etc/ssh/ssh_host*` 刪除 - ![](https://hackmd.io/_uploads/Hy0MNvAbp.png =500x) - `sudo dpkg-reconfigure openssh-server` 重新設定 - ![](https://hackmd.io/_uploads/S1WrNPRZp.png =600x) - 再把 ssh 服務開啟 - 試著用連線過的 client 去連線 - ![](https://hackmd.io/_uploads/B1EerP0ba.png =500x) - 因為公鑰已經被換過,所以比對的時候發現不一樣 - 解決辦法: - `ssh-keygen -f "~/.ssh/known_hosts" -R "[hostname]"` - ![](https://hackmd.io/_uploads/H1wxODRbp.png =500x) - 或是手動刪除也可以 - 根據警告提示行數刪掉 - Tips: 有時 SSH 升級時也會發現公鑰被替換的警告畫面,很可能是因為發現加密的密鑰存在漏洞,所以進行替換 > 手動刪除不會紀錄在 `known_host.old` 中 ::: --- ## Forward Agent :::info **SSH Agent 是什麼?** 它是一個專門管理你的 **私鑰**,以及幫你作 **數位簽章** 的程式 在 SSH 中,**agent 就是一個「代簽私鑰的保管員」**,它不會交出私鑰本身,只在需要時幫忙完成簽章 ::: - ![](https://hackmd.io/_uploads/B1dy17-G6.png =400x) > 圖片來源 [SSH 免除重複輸入金鑰密碼教學:SSH Agent 與 Forwarding – G. T. Wang](https://blog.gtwang.org/linux/using-ssh-agent-forwarding-to-avoid-being-asked-passphrase/) - 範例狀況:client 端是員工筆電,Server A 與 Server B 為公司 Server - 無法使用 Server A 金鑰登入 Server B,密碼驗證也被關閉 - Server B 設定不允許任何外部 IP 連入 - ==Server B 擁有 Client 的公鑰== - 實例: Server A 為網站 Server , Server B 為公司用機 &gt; 網站要做部署,要從 Server B 拿資料,但員工 Work from home - 使用 Agent Forwarding 可解決,透過 client 端登入 Server A 時將 SSH Key 一起轉給 A ,A 就可以利用 client 的 Key 登入 B 流程: 1. client 在本地有 `ssh-agent`,裡面已經有私鑰。 2. client 連上 `ssh ServerA -A`(`-A` 開啟 agent forwarding)。 3. ServerA 上的 `ssh` 如果要再連 ServerB,它會把簽名請求透過 SSH 通道回傳到 client 的 agent。 4. client agent 幫忙完成簽章,再回傳結果。 關鍵點: - 私鑰 **永遠不會離開本地電腦**。 - 遠端機器只能透過 SSH 通道「借用」你的 agent 做簽章。 :::danger **舉一反三** - 如果你登入的遠端主機 (hostA) 已被入侵,攻擊者可能利用你的 agent 代理去登入其他機器 (hostB)。 - 雖然私鑰不會洩漏,但只要 agent session 還活著,他們就能「借用」你的身分。 - 僅在信任的主機上使用 `-A`。 更安全的替代方案是 ProxyJump / ProxyCommand 或 ssh certificates。 ::: --- ## ssh 相關設定檔案 - 設定檔中 `#` 為註解,且註解後通常為藍字 - 註解的內容為預設內容 - ssh 相關設定檔案 `/etc/ssh/` ### Client - `/etc/ssh/ssh_config` - ![](https://hackmd.io/_uploads/S1oowgbMp.png =500x) :::spoiler 文字版 ```config Include /etc/ssh/ssh_config.d/*.conf Host * # ForwardAgent no # ForwardX11 no # ForwardX11Trusted yes # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # GSSAPIKeyExchange no # GSSAPITrustDNS no # BatchMode no # CheckHostIP yes # AddressFamily any # ConnectTimeout 0 # StrictHostKeyChecking ask # IdentityFile ~/.ssh/id_rsa # IdentityFile ~/.ssh/id_dsa # IdentityFile ~/.ssh/id_ecdsa # IdentityFile ~/.ssh/id_ed25519 # Port 22 # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc # MACs hmac-md5,hmac-sha1,umac-64@openssh.com # EscapeChar ~ # Tunnel no # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h # UserKnownHostsFile ~/.ssh/known_hosts.d/%k SendEnv LANG LC_* HashKnownHosts yes GSSAPIAuthentication yes ``` ::: - ForwardAgent 驗證代理 - 讓本地 SSH Key 可由遠端 server 轉送 - IdentityFile - 指定要用哪個私鑰 - PasswordAuthentication - 允許 / 不允許 client 使用密碼登入 ssh server - CheckHostIP - 確認已連線過的主機是否有 IP 不同的問題,發現就提醒 - ConnectTimeout - 連線超過指定秒數就斷線 - Port - 預設使用 22 port 進行連線 - 針對指定 Server 做此設定 - 例如 ```conf= Host ec2 User lsa Port 22 Hostname lsalab.moli.rocks ``` - 如此在下 `ssh ec2` 指令時,會採用以上設定連線 - 可放置在 `/etc/ssh_config` 中,也可以建立一個檔案 `~/.ssh/config` ### Server - `/etc/ssh/sshd_config` - **基礎設定** - ![](https://hackmd.io/_uploads/SypzHWWGa.png =500x) :::spoiler 文字版 ``` #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key ``` ::: - Port 選擇使用 port 號 (預設 22 ) - ListenAddress 允許連入的 IP address 預設 `0.0.0.0` 為 IPv4 中允許主機所擁有的任何 IP 連入 - `::` 為 IPv6 中,允許主機所擁有的任何 IP 連入 - HostKey 存放私鑰位置 - **認證相關** - ![](https://hackmd.io/_uploads/SJoF4WWzp.png =600x) - PermitRootLogin - 是否允許使用 root 登入(預設為禁止使用密碼登入) - PubkeyAuthentication - 是否允許使用 Public Key 登入 (預設為 yes) - PasswordAuthentication ⭐ - 是否允許 client 使用密碼登入(預設為 yes) - 若設 `no` ,剩下 public key 驗證模式,可大大降低猜密碼攻擊危險性 - PermitEmptyPasswords - 是否允許輸入空密碼登入(預設為 no) - 針對單獨 client 設定 - Match User anoncvs - 如果你只想針對某使用者進行特殊設定,可使用這個功能 ```conf= Match User ray PasswordAuthentication no ClientAliveInterval 30 ClientAliveCountMax 20 ``` - 針對 client 端叫 ray 的人給他這樣的設定 :::info ### SSH config include 設定 - 觀察檔案會有一行 - ![](https://hackmd.io/_uploads/HyZsJfWMT.png =300x) - 在 `/etc/ssh/` 中會發現有一個目錄 `sshd_config.d` - 用來存放使用者想更動的設定,為了防止 sshd_config 被改壞 - ssh 在運作時更改設定很可能會出問題,所以建議是以關閉狀態改變設定或是在這個目錄新增 `.conf` 檔去做設定 ::: --- # 遠端檔案傳輸 ## FTP - File Transfer Protocol - 古老的檔案傳輸協定 - 明文傳輸 (沒有加密) 方式 - client 可以把檔案**上傳至 / 下載 from** ftp server - 優點 - 傳輸速度快 - 與 HTTP 相比,他不需要包很多 Header ,所以封包自然也就比較輕 - 缺點 - 傳輸不安全 - 如需登入帳密會有安全性問題 - port 號 - 20 port 資料連線通道 - 21 port 控制連線通道 - 雖然不安全,但如果是公共檔案就比較沒有問題 - 安裝檔、給大家的~~作業~~文件, etc. - 可匿名使用 - 雖可匿名,但仍會紀錄登入請求來源 ### FTP Server - 常見: vsftpd、proftpd - 以下用 vsftpd 示範 - `sudo apt install vsftpd` - `sudo service vsftpd status` - ![](https://hackmd.io/_uploads/rk9gCP0fp.png) - 安裝後確認 - `/etc/vsftpd.conf` 設定檔位置 - 以下介紹匿名模式的設定(不建議大家利用 ftp 傳送重要檔案) - ![](https://hackmd.io/_uploads/S1tbW_0f6.png) :::info ### 參數參考 - `anonymous_enable=YES (NO)` - 是否允許匿名者 - `anon_other_write_enable=YES (NO)` - 匿名者是否有寫入檔案的權限(預設為 NO ) - `anon_mkdir_write_enable=YES (NO)` - 匿名者是否有目錄創建的功能(預設為 NO ) - `anon_upload_enable=YES (NO)` - 匿名者是否有上傳檔案的功能 - `no_anon_password=YES (NO)` - 匿名者登入是否需要密碼,預設為 NO ,需要密碼 - `anon_root = /var/ftp/` - 匿名者登入初始路徑 - `guest_enable=YES (NO)` 與 `local_enable=YES (NO)` - 如不允許實體使用者即可設定為 NO - **如果沒有設定參數需自行加進 conf 檔** ::: > FIXME: 開設定好匿名上傳下載的 server 給大家玩? - 完成設定後,重啟 service - 重啟 service 後可以先登入本機測試 - ![](https://hackmd.io/_uploads/SJWFSO0fT.png) - 輸入 `anonymous` 表示匿名登入 - 密碼可以選擇不輸入(不過密碼會紀錄) - 紀錄檔 `/var/log/vsftpd.log` - ![](https://hackmd.io/_uploads/BylvOdRGT.png) ### FTP 操作 - `ftp [ip address]` 登入 - 如果是公眾的 server,username 可輸入`anonymous`作為匿名,密碼可空白 - `put [client_file] [server_file] ` 上傳檔案,如 server 上已有重複的檔案則覆蓋 - `get [server_file] [client_file]` 下載檔案,如 client 上已有重複的檔案則覆蓋 - `ls` 與 Linux 指令一樣, list - `cd` 與 Linux 指令一樣, change directory - `lpwd` 顯示本機端目前位置 - `lcd` 切換本機端位置 - `help` 查看更多指令 - `bye` 退出 --- ## SFTP - **S**SH **F**ile **T**ransfer **P**rotocol - client 指令基本上與 FTP 語法一樣,只是 SFTP 是 SSH 的一部分 > 所以 server 端需要 SSH 才能使用 :::info 在 **sshd_config** 檔案中,有 ```config # override default of no subsystems Subsystem sftp /usr/lib/openssh/sftp-server ``` ::: - 利用 SSH 傳輸,所以預設與 SSH 一樣使用 22 port - 解決 FTP 明文傳輸的問題 - 效率 - FTP &gt; SFTP - 安全性 - FTP &lt; SFTP - 登入 - `sftp [user]@[hostname]` :::success **實做** 在你本機捏一個 `學號.abc` 用 ftp or sftp 丟到 moli.lsa.tw `/var/class1001/` 裡頭 ::: ## SCP - **S**SH copy <!-- 不一定是 SSH backend? --> - `cp` 在 Linux 是複製 - 而 `scp` 為遠端複製檔案 ### scp 操作 - 用法 - `scp [參數] [source] [destination]` - 從本機上傳至遠端 - `scp [本機檔案路徑] [usr_name]@[hostname]:[遠端檔案路徑]` - `path` 不輸入則為家目錄 - 從遠端下載到本機 - `scp [usr_name]@[hostname]:[遠端檔案路徑] [本機檔案路徑]` - `-r`: recursive ,目錄中所有檔案 - `scp [folder]/** [destination]` --- ## Rsync - Rsync 能做到 `cp` 跟 `scp` 的事,但 Rsync 的效率比 `cp` 跟 `scp` 好 - 靈活性高 - 除了複製檔案,也非常適合用來作備份工具 - 可使用於本機與遠端 - 支援連結檔與設備檔 - 支援複製後保留檔案的屬性(擁有者、群組與權限設定) - 在第一次複製檔案時,會複製完整的檔案內容 - 如複製時發現有一樣檔案在裡面,會利用 delta-transfer 演算法**檢查新舊檔案之間的差異,只傳送有變動的部份** - 節省複製的時間,可加快備份速度(大檔案傳輸時會有更明顯的差異) - 進行遠端傳輸時,可節省網路頻寬 - 支援資料的自動壓縮與解壓縮,也可節省網路頻寬 ### rsync 操作 - 為內建工具,但如果沒安裝 - `sudo apt install rsync` ### 基礎語法 - `rsync [參數] [來源檔案] [目的檔案]` ### 常見參數 | 參數 | 說明 | | ----------------------- |:-------------------------------------------------------------------------------------------------- | | `-v` | verbose 模式,輸出比較詳細的訊息 | | | `-a` | 封裝備份模式,遞迴備份所有子目錄下的目錄與檔案,保留連結檔、檔案的擁有者、群組、權限以及時間戳記。 | | `-z` | 啟用壓縮。 | | `-h` | 將數字以比較容易閱讀的格式輸出。 | | | `-P` / `--progress` | 顯示傳輸進度 | | `--delete` | 同步將不存在於來源端的檔案刪除 | :::spoiler > FIXME: 指令測試 > - rsync -az:什麼都不顯示 > ![image](https://hackmd.io/_uploads/BJrxXVl2lx.png) > - rsync -avz -P > ![image](https://hackmd.io/_uploads/HySqXEx3ex.png) > - rsync -az -P > ![image](https://hackmd.io/_uploads/ryIAXNl2ex.png) > - rsync -avz --info=progress2:背景模式跑 rsync,且會有進度條 > ![image](https://hackmd.io/_uploads/Sk0XxEe3ge.png) ::: ### 常見使用情境 ### 基本本機複製 - `rsync -avh /home/wzray/a/ /home/wzray/b/` - `-a` 這個參數包含 `-r`,所以要複製整個目錄下的檔案也沒問題 - `rsync -avh /home/wzray/a/ /home/wzray/b/` - 試著修改一個檔案,再敲一次指令後,觀察他處理了什麼檔案 - ![](https://hackmd.io/_uploads/B1XrvtRzp.png =500x) ### 遠端備份 - 本機 => 遠端 - `rsync -avzh ~/file wzray@192.168.1.12:/home/wzray/` - 遠端 => 本機 - `rsync -avzh wzray@192.168.1.12:/home/wzray/ ~/file` - 跟 `scp` 語法很像 ### 同步刪除檔案 - 如果第二次複製時發送端的部分檔案已刪除,想要在目的端同步刪除該檔案 - `rsync -avh --delete /home/wzray/a/ /home/wzray/b/` --- :::spoiler > FIXME: BT 小筆記 - 不透過 ssh 的方式把遠端的資料 mirror 回來 - 沒有經過 ssl 加密 -> 密碼用明文 - read only: no -> 讓使用者可以寫入資料 步驟紀錄 ![image](https://hackmd.io/_uploads/Sys2Rmxnll.png) ![image](https://hackmd.io/_uploads/Sy-C07xhlg.png) ![image](https://hackmd.io/_uploads/rJMkkVe3xl.png) ![image](https://hackmd.io/_uploads/SyVg1Elhle.png) ![image](https://hackmd.io/_uploads/Byeby4xhll.png) ![image](https://hackmd.io/_uploads/BJa-kNe2el.png) ![image](https://hackmd.io/_uploads/r1bz1Eghge.png) ::: --- # SSH Tunnel > - 基於 SSH Protocol 所延伸的技術 - 將網路上的 A、B 兩個端點用 Tunnel 連接起來,形成一個**隧道** - 基本過程: - A 點上的某個 Port X 所傳送的資料轉送 至 B 點上的 Port Y - 又被稱 Port Forwarding - **好處** - 可突破防火牆限制 - 如防火牆有擋掉特定 port , 沒有擋掉 22 port ,可利用此種方式穿透此限制 - 將通訊內容加密避免洩漏 - 利用 SSH 加密特性來進行通訊 - Tunneling 中通常會出現以下三種角色 - **Client** - 任何你可以敲 ssh 指令來啟動 Port Forwarding 的機器 - **SSH Server** - 可以被 Client 用 SSH 連進去的機器 - **Target Server** - 某一台你想建立連線的機器,通常是為了對外開放這台機器上的服務 - Client 與 SSH Server 本身都可以是 Target Server ,不是真的要有三台機器才可以進行 Port Forwarding! --- ## Local Port Forwarding - 語法 - `ssh -L [bind_address:][port]:[host]:[host_port] [SSH Server]` - `[bind address:]` 不輸入預設為 `localhost` - **情境一:** - ![](https://hackmd.io/_uploads/B1AfAd7fT.png) - 防火牆後有一台 Server ,但防火牆設定不接受 8080 port 連入,不過接受 22 port - 使用 tunneling 將 client 中的某個 port (圖中範例 port 9090),對他發送的資料經 SSH 通道轉送至 8080 port,等於連上 client 9090 port 就可以連上 Server 8080 port ,完成繞過防火牆限制 - ![image](https://hackmd.io/_uploads/S1wAKUDgyg.png) - `ssh -L 9090:localhost:8080 [username]@[server]` :::success **Lab 作業!** ![圖片](https://hackmd.io/_uploads/BkOMc_jhlx.png) 我們在 moli.lsa.tw port 8080 開了一個簽到網站,請你用上 ssh tunnel 所學,想辦法進到這個網站完成簽到並截圖,網站的 url 也要截進去! 簽到的紀錄會放在 `/opt/signin-app/signlog.csv`,請你用上遠端檔案傳輸方式,把這個簽到紀錄下載到自己的虛擬機裡,截圖裡面的內容 ::: - **Client** - 你的電腦 - **SSH Server** - 防火牆後的 Server - `[username]@[server]` - **Target Server** - 防火牆後的 Server - localhost:8080 &gt; `bind address`沒輸入代表使用預設 `localhost` &gt; 如果要開放對外可以改成 `0.0.0.0` &gt; `host` 的 `localhost` 是只針對 `server` 的 `localhost` - **情境二:** - ![](https://hackmd.io/_uploads/r1R2IUCza.png) - 前面情境為 Server 能連入的情況,那如果今天權限不足以連入要怎麼辦 - 如果防火牆後有一台你的機器且可用 ssh 連入即可完成 :::spoiler - ![](https://hackmd.io/_uploads/S1wRPLAfa.png) ::: - ![圖片](https://hackmd.io/_uploads/rJSrtDG2xe.png) - `ssh -L 9090:192.168.2.10:8080 [username]@[server]` - **Client** - 你的電腦 - **SSH Server** - 你的機器 - `192.168.2.10:8080` - **Target Server** - 防火牆後的 Server - `[username]@[server]` --- ## Remote Port Forwarding - 語法 - `ssh -R [bind_address:][port]:[host]:[host_port] [username]@[server]` - **情境一:** - ![](https://hackmd.io/_uploads/H1Dn_YXMT.png) - 你的電腦上完成了一個服務,並架上 8080 port ,但你的電腦沒有對外 ip,僅有內部 ip - 準備一台有 Internet 的機器當作對外機器,即可使用 Remote Forwarding 完成 - 對外機器開啟一 port 客戶連入 (圖片範例 port 9090) - 對外機器藉由 SSH 通道將轉送到 port 8080,客戶即可取得服務 - ![](https://hackmd.io/_uploads/S1KIjtXfa.png) - `ssh -R 0.0.0.0:9090:localhost:8080 [username]@[SSH Server]` - 因為要開放對外,所以設定`0.0.0.0` - `localhost` 是針對你的電腦 - **Client** - 你的電腦 - **SSH Server** - 對外機器 - `[username]@[server]` - **Target Server** - 你的電腦 :::warning - 基於安全考量,Remote Forwarding 的預設都只能夠 bind 在 SSH Server 的 localhost 上 - 所以必須要改變設定 - 至 sshd 內的設定檔 - `GatewayPorts yes` ::: - **情境二:** - 有一個在內網裡的內部服務,你的電腦可以用 IP `192.168.1.100` 和 Port 8080 連到這個服務,但因為都在內網所以大家都沒有 Internet IP,所以無法讓你從家裡透過 Internet 連回來: - ![](https://hackmd.io/_uploads/Byzqeq7Ga.png) - 與情境一不同,服務另外架在其他機器上 - 一樣也可以使用 Remote Forwarding - ![](https://hackmd.io/_uploads/Bk45G9mza.png) - `ssh -R 0.0.0.0:9090:192.168.1.100:8080 [username]@[SSH Server]` - `192.168.1.100` 為內部其他電腦服務 ip,透過你的電腦做資料轉送 - **Client** - 你的電腦 - **SSH Server** - 對外機器 - `[username]@[server]` - **Target Server** - 內部服務 - `192.168.1.100:8080` --- ## Dynamic Port Forwarding 一般的 Port Forwarding 只能夠轉送一個 IP 上的一個 Port ,當你有很多 IP 或很多 Port 想轉時就只能一個一個開,很不方便 - 語法 - `ssh -D [bind_address:][port] [username]@[SSH Server]` - 情境 - ![dynamic](https://hackmd.io/_uploads/HJx-Cvz2lx.png) - 只要有一台位於內網且具有外部 IP 的機器,你就可以利用這個方法建立一個 SOCKS 代理伺服器,讓你能夠從外面連回內網裡的所有服務 > FIXME: 三種 tunnel 模式想個 demo > FIXME: 線要畫確實,包括從哪進、從哪出,下面幾張圖亦然 > FIXME: 記得留時間,後面 tunnal 部分需要緩衝 --- # 作業 登入 lsa server,在 /var/exercise/ 裡有多個檔案,這些檔案裡頭除了有幾百行亂碼,裡面還參雜你們的學號,你們必須找到所有出現你學號的檔案 # 補充資料 - [如何讓兩台虛擬機可以用 ssh 連線 - HackMD](https://hackmd.io/@oJ7l_4AbTkCmGKJnAmApWw/ryXtBNePF) - [遠端連線虛擬機 - HackMD](https://hackmd.io/@wzray07/Bkhh64xGT)