# SSH 遠端連線
- 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
:::info
#### DEMO: 可用 Wireshark / dsniff 看到明文傳輸 telnet 內容
- **Wireshark**
- 開源的網路封包分析軟體
- 其他類似軟體:tcpdump
- 另一支程式 **dsniff** 能自動幫我們找出明文的帳密
:::
## SSH
- 全名 : **S**ecure **Sh**ell 安全外殼協定
- 解決 telnet 不安全的問題
- 使用非對稱式加密方式做使用者驗證
:::info
#### 不同加密方式[^REF_Crypt]
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)
+ 雙方各有一對公私鑰,互換公鑰後用對方的公鑰加密
![](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 簽名,以達到二次驗證
:::
[^REF_Crypt]: [基礎密碼學(對稱式與非對稱式加密技術). 現代密碼學泛指透過數學演算法與電腦科學對資料(明文)進行加密和解密的科學。 | 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)
:::info
#### Hash 雜湊函式
$H(x) = x \mod B$
- 將不定長度訊息的輸入,演算成固定長度雜湊值的輸出[^hash]
- 由雜湊值是無法反推出原來的訊息
- 雜湊值必須隨明文改變而改變
:::
[^hash]: [[資料結構] 雜湊 (Hash) - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10208884)
:::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 是密碼學中常用來代表「惡意的攻擊者」虛構角色的人名[^Mallory]
- **中間人攻擊** (**M**an-**i**n-**t**he-**M**iddle Attack, 縮寫: **MITM**)
- 在密碼學和電腦安全領域中常提到的一個概念
- 指攻擊者與通訊的兩端分別建立獨立的聯絡,並交換其所收到的資料,使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個對談都被攻擊者完全控制。[^MITM]
:::
[^Mallory]: [Alice and Bob - Wikipedia](https://en.wikipedia.org/wiki/Alice_and_Bob#Cryptographic_systems)
[^MITM]: [中間人攻擊 - 維基百科,自由的百科全書](https://zh.wikipedia.org/wiki/%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB)
- SSH 的驗證方法[^REF_sshauth]
1. 基於密碼的安全驗證
- 知道帳號和密碼,就可以登入到遠端主機。
2. 基於金鑰的安全驗證
- 使用者將公鑰放在需要存取的伺服器上。
- 用戶端軟體發出請求時,會傳自己的公鑰和其他資訊給伺服器。
- 伺服器把存在伺服器與發送過來的公有密鑰進行比較。
- 如果兩個密鑰一致,伺服器就用公鑰加密「質詢」(challenge)並把它發送給用戶端軟體。
- 若用戶端成功解開質詢,回傳的資訊是與伺服器中的正確答案是相符的,則允許登入。
[^REF_sshauth]: [SSH的安全驗證 | 凌群電子報](https://www.syscom.com.tw/ePaper_Content_EPArticledetail.aspx?id=84&EPID...) by 鄭翔文
- 連線建立過程
(1)遠端主機收到使用者的登入請求,把自己的公鑰發給使用者。
(2)使用者使用這個公鑰,將登入密碼加密後,傳送回去給遠端主機。
(3)遠端主機用自己的私鑰,解密登入密碼,如果密碼正確,就同意使用者登入。
![](https://i.imgur.com/OZNj39r.png)
> 圖片來源 [鳥哥的 Linux 私房菜 伺服器建置實務-遠端連線伺服器 ssh 與 VNC](https://dic.vbird.tw/linux_server2/point04.php)
:::info
#### client-server model
![Client-server-model.svg](https://hackmd.io/_uploads/H1UjgI7g1x.png)
> 圖片來源 [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** 特徵
- 被動的角色(從)
- 等待來自使用者端的請求
- 處理請求並傳回結果
:::
### 基礎操作
#### 安裝
- 更新軟體的最新資訊及列表: `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 中已內建,如果沒有要做連入的主機可以不安裝 `openssh-server`
> P.S: Windows 10 1809 的 cmd 中也內建了 openssh-client
:::
#### 確認 server 狀態
- 查看服務狀態
- `sudo systemctl status ssh`
- 查看 ssh 佔用 port
- `sudo ss -ltpn`
- `-l`: 列出傾聽狀態(listening)的 sockets[^list_ports]
- `-t`: 只列出 TCP 的 sockets
- `-p`: 顯示使用 sockets 的程式資訊
- `-n`: 不要嘗試把 port 號解析成服務名稱
[^list_ports]: [使用 ss 指令檢查 Linux 網路 Socket 狀態資訊教學 – G. T. Wang](https://blog.gtwang.org/linux/socket-statistics-ss-command-tutorial/)
#### 開啟關閉與重啟 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 被作為頂級域名,不得有任何網域註冊此名稱
- 登入遠端
- `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]` 等待時間如果超過三秒即斷線
:::
### 密碼登入
- 流程圖[^ref_ssh1][^ref_ssh2]
- ![](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. 最後雙方再以協商的密鑰,接收登入訊息並開始操作系統
[^ref_ssh1]: [SSH加密過程 - HackMD](https://hackmd.io/@yanren1996/rk9OUfY1i) by @yanren1996
[^ref_ssh2]: [Understanding the SSH Encryption and Connection Process | DigitalOcean](https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process) by Justin Ellingwood
### 利用公鑰進行無密碼登入
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 ,現在預設為 `3072` bits
- `2048` bits 以下都不建議用,如需提升安全性可選擇更長的 key ,如:`3,072` 或 `4,096` bits (詳見文末延伸閱讀連結)
- 若選擇 `3072` bits,公鑰會被 OpenSSH 編碼成 `544` 個 16 進位字元(chars)
- `ed25519` 較推薦使用
- 較新,OpenSSH 6.5 版本以後就都支援[^REF_Crypto2]
- 安全性最好
- 更快的產生金鑰
- 更快的身分驗證
- 長度固定
- 公鑰 `256` bits,被 OpenSSH 編碼成 `68` 個 16 進位字元(chars)
- 是使用 SHA-512(SHA-2)和 Curve25519 的 EdDSA 簽名方式
- 扭曲的愛德華茲曲線
- `ecdsa`
- 有 `256`, `384`, `521` bits 三種 key 長度可以選擇,無法選擇其他的使用
- 公鑰長度相比 RSA 較小[^REF_Crypto1]
- 應用了**橢圓曲線加密法**
[^REF_Crypto1]: [Day 24. 非對稱式加密演算法 - 橢圓曲線密碼學 Elliptic Curve Cryptography , ECC (觀念篇) - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10251031) by 羊小咩 (lamb_mei)
[^REF_Crypto2]: [選擇 SSH key 的加密演算法. 在 ssh-keygen 的 man page 說明中有一個… | by Chris Yuan, 袁昇禾 | Medium](https://medium.com/@honglong/%E9%81%B8%E6%93%87-ssh-key-%E7%9A%84%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95-70ca45c94d8e)
:::
2. 把公鑰複製到遠端主機 server 上
- 方法一
- 用 ssh-copy-id 傳送公鑰到遠端主機
`ssh-copy-id -i ~/.ssh/id_ed25519.pub [username]@[hostname]`
* 方法二,手動複製
1. 先用帳號密碼登入遠端主機 server
2. `cd ~/.ssh`
3. 在遠端主機新增檔案 `touch authorized_keys`
4. 將 `id_ed25519.pub` 公鑰內容放入 `authorized_keys`中,以換行方式區分不同支公鑰
`vim authorized_keys`
5. `chmod -R go= ~/.ssh` 把這個資料夾中所有檔案的 group 及 other 權限拿掉
3. client 直接 ssh 到遠端主機 server
- 採用預設 key: `ssh [username]@[hostname]`
- 或自行指定 key: `ssh -i ~/.ssh/id_ed25519 [username]@[hostname]`
- 若是 client 第一次連到這台 server,會輸出:
```
$ ssh username@remote_host
The authenticity of host '203.0.113.1 (203.0.113.1)' can't be established.
ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
Are you sure you want to continue connecting (yes/no)? yes
```
- 意思是你的 client 還不認識這台 server。輸入 `yes` 後按 Enter 即可繼續連線
:::info
若遇到權限問題,用
`chmod 600 ~/.ssh/authorized_keys`
:::
:::info
#### 更換 ssh-server 公鑰[^Remove_REF]
- 為了讓大家得知什麼樣的情況會跳出警告
- 先關閉 ssh 服務
> 做任何相關設定檔調整前建議關閉服務再進行調整
- `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` 中
:::
[^Remove_REF]: [Ubuntu / Debian Linux 重新產生 OpenSSH Host Keys 的方法 | The Will Will Web](https://blog.miniasp.com/post/2010/08/30/Ubuntu-Debian-Linux-Regenerate-OpenSSH-Host-Keys)
### Forward 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 為公司用機
> 網站要做部署,要從 Server B 拿資料,但員工遠端工作在家
- 使用 Agent Forwarding 可解決
- client 端可以使用金鑰登入 Server A 與 Server B,但因為 Server B 不允許外部連入
- client 端登入 Server A 時將 SSH Key 一起轉給 A ,A 就可以利用 client 的 Key 登入 B
### 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 操作[^REF_FTP]
- `ftp [ip address]` 登入
- 如果是公眾的 server,username 可輸入`anonymous`作為匿名,密碼可空白
- `put [client_file] [server_pwd] ` 上傳檔案,如 server 上已有重複的檔案則覆蓋
- `get [file] [client_pwd]` 下載檔案,如 client 上已有重複的檔案則覆蓋
- `ls` 與 Linux 指令一樣, list
- `cd` 與 Linux 指令一樣, change directory
- `lpwd` 顯示本機端目前位置
- `lcd` 切換本機端位置
- `help` 查看更多指令
- `bye` 退出
[^REF_FTP]: [Linux ftp 指令 - Linux 技術手札](https://www.hkcode.com/linux/linux-ftp-command)
### 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 > SFTP
- 安全性
- FTP < SFTP
- 登入
- `sftp [user]@[hostname]`
### SCP
- **S**SH copy <!-- 不一定是 SSH backend? -->
- `cp` 在 Linux 是複製
- 而 `scp` 為遠端複製檔案
#### scp 操作[^REF_SCP]
- 用法
- `scp [參數] [source] [destination]`
- 從本機上傳至遠端
- `scp [本機檔案路徑] [usr_name]@[hostname]:[遠端檔案路徑]`
- `path` 不輸入則為家目錄
- 從遠端下載到本機
- `scp [usr_name]@[hostname]:[遠端檔案路徑] [本機檔案路徑]`
- `-r`: recursive ,目錄中所有檔案
- `scp [folder]/** [destination]`
[^REF_SCP]: [Linux 的 scp 指令用法教學與範例:遠端加密複製檔案與目錄 – G. T. Wang](https://blog.gtwang.org/linux/linux-scp-command-tutorial-examples/)
### Rsync
- Rsync 能做到 `cp` 跟 `scp` 的事,但 Rsync 的效率比 `cp` 跟 `scp` 好
- 靈活性高
- 除了複製檔案,也非常適合用來作備份工具
- 可使用於本機與遠端
- 支援連結檔與設備檔
- 支援複製後保留檔案的屬性(擁有者、群組與權限設定)
- 在第一次複製檔案時,會複製完整的檔案內容
- 如複製時發現有一樣檔案在裡面,會利用 delta-transfer 演算法**檢查新舊檔案之間的差異,只傳送有變動的部份**
- 節省複製的時間,可加快備份速度(大檔案傳輸時會有更明顯的差異)
- 進行遠端傳輸時,可節省網路頻寬
- 支援資料的自動壓縮與解壓縮,也可節省網路頻寬
#### rsync 操作 [^Rsync_REF1][^Rsync_REF2]
- 為內建工具,但如果沒安裝
- `sudo apt install rsync`
#### 基礎語法
- `rsync [參數] [來源檔案] [目的檔案]`
#### 常見參數
| 參數 | 說明 |
| ----------------------- |:-------------------------------------------------------------------------------------------------- |
| `-v` | verbose 模式,輸出比較詳細的訊息 | |
| `-a` | 封裝備份模式,遞迴備份所有子目錄下的目錄與檔案,保留連結檔、檔案的擁有者、群組、權限以及時間戳記。 |
| `-z` | 啟用壓縮。 |
| `-h` | 將數字以比較容易閱讀的格式輸出。 | |
| `-P` / `--progress` | 顯示傳輸進度 |
| `--delete` | 同步將不存在於來源端的檔案刪除 |
#### 常見使用情境
#### 基本本機複製
- `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/`
[^Rsync_REF1]: [Linux 使用 rsync 遠端檔案同步與備份工具教學與範例 – G. T. Wang](https://blog.gtwang.org/linux/rsync-local-remote-file-synchronization-commands/)
[^Rsync_REF2]:[rsync & scp - HackMD](https://hackmd.io/@celineyeh/ByHCum98B) by 葉佳臻 @celineyeh
## 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]`
- **Client**
- 你的電腦
- **SSH Server**
- 防火牆後的 Server
- `[username]@[server]`
- **Target Server**
- 防火牆後的 Server
- localhost:8080
> `bind address`沒輸入代表使用預設 `localhost`
> 如果要開放對外可以改成 `0.0.0.0`
> `host` 的 `localhost` 是只針對 `server` 的 `localhost`
- **情境二:**
- ![](https://hackmd.io/_uploads/r1R2IUCza.png)
- 前面情境為 Server 能連入的情況,那如果今天權限不足以連入要怎麼辦
- 如果防火牆後有一台你的機器且可用 ssh 連入即可完成
:::spoiler
- ![](https://hackmd.io/_uploads/S1wRPLAfa.png)
:::
- ![](https://hackmd.io/_uploads/r1FbcUwl1e.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`
:::
- **情境二:**
- ![](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
- 語法
- `ssh -D [bind_address:][port] [username]@[SSH Server]`
- 情境
- ![Untitled Diagram-Page-6.drawio (1).png](https://hackmd.io/_uploads/rk4uPXUmT.png)
- 只要有一台位於內網且具有外部 IP 的機器,你就可以利用這個方法建立一個 SOCKS 代理伺服器,讓你能夠從外面連回內網裡的所有服務
[^port_fwd_1][^port_fwd_2_img_src]
[^port_fwd_1]: [使用SSH Tunnel提供更安全的存取通道 | 恆逸講師技術文章發表UCOM TIPS](https://www.uuu.com.tw/Public/content/article/17/170320tips.htm) by 陳勇勳
[^port_fwd_2_img_src]: [SSH Tunneling (Port Forwarding) 詳解 · John Engineering Stuff](https://johnliu55.tw/ssh-tunnel.html)
> FIXME: 三種 tunnel 模式想個 demo
> FIXME: 線要畫確實,包括從哪進、從哪出,下面幾張圖亦然
## 補充資料
- [如何讓兩台虛擬機可以用 ssh 連線 - HackMD](https://hackmd.io/@oJ7l_4AbTkCmGKJnAmApWw/ryXtBNePF)
- [遠端連線虛擬機 - HackMD](https://hackmd.io/@wzray07/Bkhh64xGT)
## 延伸閱讀
[cryptography - SSH Key: Ed25519 vs RSA - Information Security Stack Exchange](https://security.stackexchange.com/questions/90077/ssh-key-ed25519-vs-rsa)
[EdDSA - 維基百科,自由的百科全書](https://zh.wikipedia.org/wiki/EdDSA#Ed25519) 當中的 Ed25519 章節
## 參考資料
- 1121 LSA-I Week 08 [Linux 遠端連線 - HackMD](https://hackmd.io/@wzray07/HJN8ChbC3) by Ray @wzray07
- 1111 LSA-I Week 06 [Linux ssh 遠端連線 - HackMD](https://hackmd.io/7kiV5QwqT3y7L46EZF8DQQ?view) by @Alanjy-Huang
- [OpenSSH Server | Ubuntu](https://ubuntu.com/server/docs/openssh-server)
- [How to Set Up SSH Keys on Ubuntu 22.04 | DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-22-04) by Alex Garnett
- 國家教育研究院 [樂詞網 : 局部回送位址](https://terms.naer.edu.tw/detail/f76cc81a062b80afb496c8c94b5329f4/?startswith=zh&seq=20)
- [Introduction | Ed25519: high-speed high-security signatures](https://ed25519.cr.yp.to/)
- [使用 ss 指令檢查 Linux 網路 Socket 狀態資訊教學 – G. T. Wang](https://blog.gtwang.org/linux/socket-statistics-ss-command-tutorial/)
- [Day18- Diffie–Hellman - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天](https://ithelp.ithome.com.tw/articles/10294073) by nynapig
- [An Illustrated Guide to SSH Agent Forwarding](http://unixwiz.net/techtips/ssh-agent-forwarding.html) 較簡易的圖解
- [RFC 4251 - The Secure Shell (SSH) Protocol Architecture](https://datatracker.ietf.org/doc/html/rfc4251)
- [RFC 4252 - The Secure Shell (SSH) Authentication Protocol](https://datatracker.ietf.org/doc/html/rfc4252)
- [RFC 4254 - The Secure Shell (SSH) Connection Protocol](https://datatracker.ietf.org/doc/html/rfc4254)