owned this note
owned this note
Published
Linked with GitHub
# 遠端連線與傳輸
> 維護網路伺服器最簡單的方式不是跑去實體伺服器前面登入,而是透過遠端連線伺服器連線功能來登入主機, 然後再來進行其他有的沒的維護就是了。[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. 對稱式加密:雙方都使用同一把密鑰加解密

> 圖片來源 [基礎密碼學(對稱式與非對稱式加密技術). | 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):遠端主機使用你的公鑰加密的資料,在本地端就能夠使用私鑰來進行解密。由於私鑰是這麼的重要, **因此私鑰是不能夠外流的!只能保護在自己的主機上**。

> 圖片來源 [基礎密碼學(對稱式與非對稱式加密技術). | 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
### 中間人攻擊

> 圖片來源 [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

> 圖片來源 [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]` 找軟體指令
- 
- 可以觀察到有許多 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]'` 執行單行指令,很長的時候再包起來
- 
- `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]` 等待時間如果超過三秒即斷線
:::
---
## 密碼登入
- 流程圖
- 
> 流程圖來源: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 服務
> 做任何相關設定檔調整前建議關閉服務再進行調整
- `sudo rm /etc/ssh/ssh_host*` 刪除
- 
- `sudo dpkg-reconfigure openssh-server` 重新設定
- 
- 再把 ssh 服務開啟
- 試著用連線過的 client 去連線
- 
- 因為公鑰已經被換過,所以比對的時候發現不一樣
- 解決辦法:
- `ssh-keygen -f "~/.ssh/known_hosts" -R "[hostname]"`
- 
- 或是手動刪除也可以
- 根據警告提示行數刪掉
- Tips: 有時 SSH 升級時也會發現公鑰被替換的警告畫面,很可能是因為發現加密的密鑰存在漏洞,所以進行替換
> 手動刪除不會紀錄在 `known_host.old` 中
:::
---
## Forward Agent
:::info
**SSH Agent 是什麼?**
它是一個專門管理你的 **私鑰**,以及幫你作 **數位簽章** 的程式
在 SSH 中,**agent 就是一個「代簽私鑰的保管員」**,它不會交出私鑰本身,只在需要時幫忙完成簽章
:::
- 
> 圖片來源 [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 拿資料,但員工 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`
- 
:::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`
- **基礎設定**
- 
:::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 存放私鑰位置
- **認證相關**
- 
- 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 設定
- 觀察檔案會有一行
- 
- 在 `/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`
- 
- 安裝後確認
- `/etc/vsftpd.conf` 設定檔位置
- 以下介紹匿名模式的設定(不建議大家利用 ftp 傳送重要檔案)
- 
:::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 後可以先登入本機測試
- 
- 輸入 `anonymous` 表示匿名登入
- 密碼可以選擇不輸入(不過密碼會紀錄)
- 紀錄檔 `/var/log/vsftpd.log`
- 
### 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 > SFTP
- 安全性
- FTP < 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:什麼都不顯示
> 
> - rsync -avz -P
> 
> - rsync -az -P
> 
> - rsync -avz --info=progress2:背景模式跑 rsync,且會有進度條
> 
:::
### 常見使用情境
### 基本本機複製
- `rsync -avh /home/wzray/a/ /home/wzray/b/`
- `-a` 這個參數包含 `-r`,所以要複製整個目錄下的檔案也沒問題
- `rsync -avh /home/wzray/a/ /home/wzray/b/`
- 試著修改一個檔案,再敲一次指令後,觀察他處理了什麼檔案
- 
### 遠端備份
- 本機 => 遠端
- `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 -> 讓使用者可以寫入資料
步驟紀錄







:::
---
# 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`
- **情境一:**
- 
- 防火牆後有一台 Server ,但防火牆設定不接受 8080 port 連入,不過接受 22 port
- 使用 tunneling 將 client 中的某個 port (圖中範例 port 9090),對他發送的資料經 SSH 通道轉送至 8080 port,等於連上 client 9090 port 就可以連上 Server 8080 port ,完成繞過防火牆限制
- 
- `ssh -L 9090:localhost:8080 [username]@[server]`
:::success
**Lab 作業!**

我們在 moli.lsa.tw port 8080 開了一個簽到網站,請你用上 ssh tunnel 所學,想辦法進到這個網站完成簽到並截圖,網站的 url 也要截進去!
簽到的紀錄會放在 `/opt/signin-app/signlog.csv`,請你用上遠端檔案傳輸方式,把這個簽到紀錄下載到自己的虛擬機裡,截圖裡面的內容
:::
- **Client**
- 你的電腦
- **SSH Server**
- 防火牆後的 Server
- `[username]@[server]`
- **Target Server**
- 防火牆後的 Server
- localhost:8080
> `bind address`沒輸入代表使用預設 `localhost`
> 如果要開放對外可以改成 `0.0.0.0`
> `host` 的 `localhost` 是只針對 `server` 的 `localhost`
- **情境二:**
- 
- 前面情境為 Server 能連入的情況,那如果今天權限不足以連入要怎麼辦
- 如果防火牆後有一台你的機器且可用 ssh 連入即可完成
:::spoiler
- 
:::
- 
- `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]`
- **情境一:**
- 
- 你的電腦上完成了一個服務,並架上 8080 port ,但你的電腦沒有對外 ip,僅有內部 ip
- 準備一台有 Internet 的機器當作對外機器,即可使用 Remote Forwarding 完成
- 對外機器開啟一 port 客戶連入 (圖片範例 port 9090)
- 對外機器藉由 SSH 通道將轉送到 port 8080,客戶即可取得服務
- 
- `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 連回來:
- 
- 與情境一不同,服務另外架在其他機器上
- 一樣也可以使用 Remote Forwarding
- 
- `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]`
- 情境
- 
- 只要有一台位於內網且具有外部 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)