掌握SSH這篇就夠了

SSH 是每一臺(tái)電腦的標(biāo)準(zhǔn)配置,Linux 就不必說了,連 windows 也從 2018 年開始自帶 OpenSSH 了。
它主要的用途是登陸到遠(yuǎn)程電腦中執(zhí)行命令,在云開發(fā)的時(shí)代,它是每個(gè)程序每天都要用到的工具。本文將簡單介紹一下它的原理,
基本用法以及端口轉(zhuǎn)發(fā)和動(dòng)態(tài)轉(zhuǎn)發(fā)等高階用法。

介紹

SSH 叫安全外殼協(xié)議(Secure Shell),是一種加密的網(wǎng)絡(luò)傳輸協(xié)議,可在不安全的網(wǎng)絡(luò)中網(wǎng)絡(luò)服務(wù)提供安全的傳輸環(huán)境。它通過在網(wǎng)絡(luò)中創(chuàng)建安全隧道來實(shí)現(xiàn) SSH 客戶端和服務(wù)器之間的連接。最早的時(shí)候,互聯(lián)網(wǎng)通信都是明文通信,一旦被截獲,內(nèi)容就會(huì)被暴露。1995年,芬蘭學(xué)者 Tatu Ylonen 設(shè)計(jì)了 SSH 協(xié)議,將登錄信息全部加密,成為互聯(lián)網(wǎng)安全的一個(gè)基本解決方案,迅速在全世界獲得推廣,目前已經(jīng)成為所有操作系統(tǒng)的標(biāo)準(zhǔn)配置。

SSH 是一種協(xié)議, 存在多種實(shí)現(xiàn),既有商業(yè)實(shí)現(xiàn),也有開源實(shí)現(xiàn)(OSSH,OpenSSH)。本文使用的自有軟件 OpenSSH, 畢竟它是目前最流行的 SSH 實(shí)現(xiàn),而且是所有操作系統(tǒng)的默認(rèn)組件。

TIPS: OpenSSH發(fā)展史
1995 年 7 月, Tatu Ylonen 以免費(fèi)軟件的形式將一套保護(hù)信息傳輸?shù)某绦颍ㄒ簿褪?SSH )發(fā)布出去。程序很快流行,到年底已經(jīng)有兩萬用戶,遍布五十國家。所以在年底時(shí),他創(chuàng)立了 SSH 通信安全公司來繼續(xù)開發(fā)和銷售 SSH, 所以它變成了專有軟件。在 1999 年,瑞典程序員基于 SSH 最后一個(gè)開源的版本 1.2.12 開發(fā)了 OSSH,之后 OpenBSD 開發(fā)者在 OSSH 的基礎(chǔ)上進(jìn)行大量修改,形成了 OpenSSH。它是目前唯一一種最流行的 SSH 實(shí)現(xiàn),成為了所有操作系統(tǒng)的默認(rèn)組件。

原理介紹

SSH 之所以一經(jīng)提出,就得到了快速發(fā)展,是因?yàn)閿?shù)據(jù)的安全性對(duì)任何人都非常重要。這里我們對(duì)其保護(hù)數(shù)據(jù)安全的原理進(jìn)行探究。

在聊加密前先介紹一下幾個(gè)密碼學(xué)的基本概念:

  • 明文plaintext 指?jìng)魉头剑ㄒ话阒缚蛻舳耍┫胍邮芊剑ㄒ话阒阜?wù)端)獲得的可讀信息
  • 密文ciphertext 指明文經(jīng)過加密后所產(chǎn)生的信息
  • 秘鑰key 指用來完成加密、解密、完整性驗(yàn)證等密碼學(xué)應(yīng)用的密碼信息,是明文轉(zhuǎn)換為密文或密文轉(zhuǎn)換為明文的算法需要的參數(shù)
  • 私鑰 指私有的秘鑰
  • 公鑰 指公開的秘鑰

對(duì)稱加密

對(duì)稱加密就是加密或解密使用的是同一個(gè)秘鑰。比較常用的對(duì)稱加密算法有 AES,DES等。其具體的時(shí)序圖如下:


ssh_symmetric.png

對(duì)稱加密的優(yōu)點(diǎn)是加解密效率高,速度快。對(duì)于服務(wù)端而言,它和每個(gè)客戶端都要有一個(gè)秘鑰,龐大的客戶端數(shù)目導(dǎo)致秘鑰數(shù)目多,而且一旦機(jī)器被登錄,所有的秘鑰都泄露,所以缺點(diǎn)是秘鑰的管理和分發(fā)比較困難,不安全。

非對(duì)稱加密

非對(duì)稱加密需要一對(duì)秘鑰來進(jìn)行加密和解密,公開的秘鑰叫公鑰,私有的秘鑰叫私鑰。注意公鑰加密的信息只有私鑰才能解開(加密過程),私鑰加密的信息只有公鑰才能解開(驗(yàn)簽過程)。比較常用的非對(duì)稱加密算法有 RSA。其具體的時(shí)序圖如下:

ssh_asymmetric.png

非對(duì)稱加密的優(yōu)點(diǎn)是安全性更高,秘鑰管理比較方便,每個(gè)服務(wù)器只要維護(hù)一對(duì)公私鑰即可。缺點(diǎn)是加解密耗時(shí)長,速度慢。不過對(duì)于現(xiàn)在的計(jì)算機(jī)而言,這點(diǎn)成本可以忽略不計(jì)。

中間人攻擊

中間人攻擊的英文全稱是 Man-in-the-middle attack,縮寫為 MITM。在密碼學(xué)和計(jì)算機(jī)安全領(lǐng)域中是指攻擊者與通訊的兩端分別創(chuàng)建獨(dú)立的聯(lián)系,并交換其所收到的數(shù)據(jù),使通訊的兩端認(rèn)為他們正在通過一個(gè)私密的連接與對(duì)方直接對(duì)話,但事實(shí)上整個(gè)會(huì)話都被攻擊者完全控制。在中間人攻擊中,攻擊者可以攔截通訊雙方的通話并插入新的內(nèi)容。在許多情況下這是很簡單的(例如,在一個(gè)未加密的 Wi-Fi 無線接入點(diǎn)的接受范圍內(nèi)的中間人攻擊者,可以將自己作為一個(gè)中間人插入這個(gè)網(wǎng)絡(luò))。其具體的時(shí)序圖如下:


ssh_mitm.png

受到中間人攻擊的關(guān)鍵原因是客戶端不知道服務(wù)端的公鑰真假,服務(wù)端也不知道客戶端的公鑰真假。所以破解這個(gè)問題的關(guān)鍵是如何相互認(rèn)證,也就是要像黃宏《開鎖》小品里一樣證明我就是我,你就是你。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@  WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!   @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:sYNNR1L6T5cSAG4BndqtdDhJEI0eB9LamBTkuIue3+0.
Please contact your system administrator.
Add correct host key in /Users/xx/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/xx/.ssh/known_hosts:40
ECDSA host key for [xx.com] has changed and you have requested strict checking.
Host key verification failed.

基本用法

生成公鑰

ssh-keygen 是安全外殼( SSH )協(xié)議套件的標(biāo)準(zhǔn)組件,用于生成,管理和轉(zhuǎn)換身份驗(yàn)證密鑰。

參數(shù)說明

  • -b bits 指定要?jiǎng)?chuàng)建的秘鑰中的位數(shù),默認(rèn) 2048 位。值越大,密碼越復(fù)雜
  • -C comment 注釋,在 id_rsa.pub 中末尾
  • -t rsa/dsa等 指定要?jiǎng)?chuàng)建的秘鑰類型,默認(rèn)為 RSA
  • -f filename 指定公私鑰的名稱,會(huì)在 $HOME/.ssh 目錄下生產(chǎn)私鑰 filename 和公鑰 filename.pub
  • -N password 指定使用秘鑰的密碼,使得多人使用同一臺(tái)機(jī)器時(shí)更安全

常用命令

# 生成公私鑰,默認(rèn)文件為 ~/.ssh/id_rsa
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

管理秘鑰

ssh-agent 和 ssh-add 是安全外殼(SSH)協(xié)議套件的標(biāo)準(zhǔn)組件,用于管理私鑰。一般情況下我們使用不帶密碼的 id_rsa 作為我們的默認(rèn)私鑰,此時(shí)是沒必要啟動(dòng) ssh-agent 的。當(dāng)我們碰到以下兩種情況則需要它:

  1. 使用不同的秘鑰連接到不同的主機(jī)時(shí),需要手動(dòng)指定對(duì)應(yīng)的秘鑰。(ssh-agent 幫我們選擇對(duì)應(yīng)的秘鑰進(jìn)行認(rèn)證)
  2. 當(dāng)私鑰設(shè)置了密碼,而我們又需要頻繁的使用私鑰進(jìn)行認(rèn)證。(ssh-agent 幫我們免去重復(fù)輸入密碼)

代理常用命令

# 啟動(dòng)代理
eval `ssh-agent`
# 關(guān)閉代理
ssh-agent -k
# 在 ~/.bashrc 中加入以下來實(shí)現(xiàn)登陸自動(dòng)啟動(dòng) ssh-agent,退出自動(dòng) kill 掉程序
eval $(ssh-agent -s) > /dev/null
trap 'test -n "$SSH_AGENT_PID" && eval `/usr/bin/ssh-agent -k` > /dev/null' 0

# 查看代理中的私鑰
ssh-add -l
# 查看代理中私鑰對(duì)應(yīng)的公鑰
ssh-add -L
# 移除指定的私鑰
ssh-add -d /path/of/key/key_name
# 移除所有的私鑰
ssh-add -D

發(fā)送公鑰

ssh-copy-id 是一個(gè)用來將公鑰放到服務(wù)器上的腳本。它通過 SSH 密碼登陸遠(yuǎn)程服務(wù)器,并將指定的公鑰放到遠(yuǎn)程服務(wù)器 $HOME/.ssh/authorized_keys 中。這個(gè)操作也可以先登陸到服務(wù)器中,然后通過 vi 等文本編輯命令向 $HOME/.ssh/authorized_keys 中加入允許登陸的公鑰。不過對(duì)于云服務(wù)器可以在啟動(dòng)服務(wù)器時(shí)在頁面上操作綁定公鑰,這樣更安全些(阿里云和騰訊云默認(rèn)關(guān)閉秘鑰登陸 PasswordAuthentication no )。特別注意的是,千萬別在公共的網(wǎng)絡(luò)中通過密碼登陸遠(yuǎn)程服務(wù)器,而秘鑰登陸沒有問題。

# 發(fā)送公鑰的兩種方式(等價(jià))
ssh-copy-id -i ~/.ssh/id_rsa.pub user@host
ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub

登錄

登錄配置

SSH 登陸服務(wù)器需要知道服務(wù)器的主機(jī)地址(主機(jī)名或主機(jī) IP 地址),用戶名和密碼,有時(shí)還要指定端口號(hào)(默認(rèn) 22 )。主機(jī)名還好,但是主機(jī)IP 地址就比較難記的,特別是當(dāng)你可能要登錄十幾臺(tái)服務(wù)器時(shí)。一般我們使用的登陸命令如下:

# 登陸目標(biāo)服務(wù)器( 172.17.132.120 )
ssh -p 58422 user@172.17.132.120
# 通過跳板機(jī)登陸目標(biāo)服務(wù)器( 172.17.132.120 )
ssh -p 58422 user@jumper.example.com ssh user@172.17.132.120
# 端口映射
ssh -p 58422 user@jumper.example.com -fNL 5433:172.17.132.120:5432 -N

通過配置 $HOME/.ssh/config 可以使用以下命令來登錄。

# 登陸目標(biāo)服務(wù)器( 172.17.132.120 )
ssh target
# 通過跳板機(jī)登陸目標(biāo)服務(wù)器( 172.17.132.120 )
ssh jump_target
# 端口映射
## 登陸時(shí)通過 LocalForward 配置
ssh jump_target
## 使用-L來實(shí)現(xiàn)本地端口映射
ssh -C -N -g -L 5433:127.0.0.1:5432 jump_target
# 通用配置,所有配置都使用
Host *
    AddKeysToAgent yes      # 將私鑰添加到ssh-agent中
    UseKeychain yes         # 保存密碼到agent中
    ServerAliveInterval 10  # 連接心跳間隔10s
    ServerAliveCountMax 3   # 重連次數(shù)為3
# target配置
Host target
    HostName 172.17.132.120
    User user
    Port 58422
    IdentityFile ~/.ssh/id_rsa
# 跳板機(jī)配置
Host jumper
    HostName jumper.example.com
    User user
    Port 58422
    IdentityFile ~/.ssh/id_rsa
Host jump_target
    HostName 172.17.132.120
    User user
    Port 22
    IdentityFile ~/.ssh/id_rsa
    ProxyCommand ssh user@jumper -W %h:%p 2>/dev/null
    LocalForward 5433 localhost:5432    # 本地5433映射到j(luò)ump_target的5432

TIPS:
VS Code 的 Remote 插件會(huì)讀取本地的配置文件 $HOME/.ssh/config,以便像本地一樣進(jìn)行遠(yuǎn)程開發(fā)。

首次登陸

一般在 $HOME/.ssh 目錄下除了公私鑰文件,config 配置文件,authorized_keys 認(rèn)證文件外,還有一個(gè) known_hosts 文件。
這個(gè)文件記錄了遠(yuǎn)程主機(jī) ip 和遠(yuǎn)程主機(jī)對(duì)應(yīng)的公鑰指紋。我們?cè)诘谝淮蔚顷懀艽a或秘鑰登陸)服務(wù)器時(shí),會(huì)有如下的提示界面:

### SSH 首次登陸的提示
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:HosOqhcUmbB7QG81yCuDPkvxTgot+vpple+czXPrEug.
ECDSA key fingerprint is MD5:fd:d7:e1:2c:42:4e:b4:2d:a3:21:4d:d1:c4:74:64:2d.
Are you sure you want to continue connecting (yes/no)?

此時(shí) known_hosts 并沒有 127.0.0.1 這臺(tái)機(jī)器的指紋信息,所以顯示這個(gè)提示來讓我們確認(rèn)這個(gè)指紋是否是目標(biāo)機(jī)器的 ECDSA 算法的指紋。
當(dāng)我們輸入 yes 確認(rèn)后,在下次登錄的時(shí)候,遠(yuǎn)程主機(jī)發(fā)送過來的公鑰指紋,直接和 known_hosts 文件中對(duì)應(yīng) ip 的公鑰指紋比較即可。

# 本機(jī)查看服務(wù)器 172.17.132.120 的所有公鑰(要與服務(wù)器上 /etc/ssh 下面的公鑰 *.pub 一致)
ssh-keyscan -p 22 172.17.132.120

# 查看服務(wù)器公鑰 ecdsa 的指紋 -E md5/sha256 指紋 hash 算法
ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ecdsa_key.pub
## 256 MD5:84:3d:9c:6e:75:f2:6b:b2:0b:40:aa:d6:29:2f:b4:40 no comment (ECDSA)
## 256 SHA256:ZoGnph63gnKLC9wQYrHYVU8ROTf6+K9LKAjn+jrXB2o no comment (ECDSA)

# 從客戶端查看服務(wù)器公鑰 ecdsa 的指紋(初次登陸時(shí)要驗(yàn)證的指紋)
ssh-keyscan -t ecdsa -p 22 172.17.132.120 |ssh-keygen -lf -

# 公鑰轉(zhuǎn)換成特定指紋 hash 算法的指紋
awk '{print $2}' /etc/ssh/ssh_host_ecdsa_key.pub | base64 -d|openssl sha256 -binary |base64

TIPS: known_hosts的重要性
known_hosts 這個(gè)文件是客戶端驗(yàn)證服務(wù)端身份的重要依據(jù)。每次客戶端向服務(wù)端發(fā)起連接請(qǐng)求時(shí),不僅服務(wù)端要驗(yàn)證客戶端的合法性,客戶端也需要驗(yàn)證服務(wù)端的身份??蛻舳司褪峭ㄟ^ known_hosts 中的公鑰指紋來驗(yàn)證服務(wù)器是否發(fā)生了變化。它在一定程度上能避免中間人攻擊,除了第一次登陸,因?yàn)槟菚r(shí) known_hosts 中還沒有服務(wù)器的身份信息,所以對(duì)于首次提示的登陸指紋信息還是需要和服務(wù)器比對(duì)的。最安全保險(xiǎn)的做法是第一次登陸就使用秘鑰登陸。

登陸流程

  1. 版本號(hào)協(xié)商階段
  2. 密鑰和算法協(xié)商階段
    服務(wù)端和客戶端分別發(fā)送算法協(xié)商報(bào)文給對(duì)方,報(bào)文中包含自己支持的公鑰算法列表、加密算法列表、消息驗(yàn)證碼算法列表、壓縮算法列表等。服務(wù)端和客戶端根據(jù)對(duì)方和自己支持的算法得出最終使用的算法。服務(wù)端和客戶端利用 DH 交換算法、主機(jī)密鑰對(duì)等參數(shù),生成會(huì)話密鑰和會(huì)話 ID。
  3. 認(rèn)證階段( publickey > gssapi-keyex > gssapi-with-mic > password )
  4. 會(huì)話請(qǐng)求階段
  5. 會(huì)話交互階段

密碼登陸

密碼登陸的認(rèn)證流程如下:

  1. 客戶端使用密鑰和算法協(xié)商階段生成的會(huì)話密鑰加密賬號(hào)、認(rèn)證方法、口令,將結(jié)果發(fā)送給服務(wù)器。
  2. 服務(wù)端使用獲得的會(huì)話密鑰解密報(bào)文,得到賬號(hào)和口令。
  3. 服務(wù)端對(duì)這個(gè)賬號(hào)和口令進(jìn)行判斷,如果失敗,向客戶端發(fā)送認(rèn)證失敗報(bào)文,其中包含了可以再次認(rèn)證的方法列表。
  4. 客戶端從認(rèn)證方法列表中選擇一種方法進(jìn)行再次認(rèn)證。
  5. 這個(gè)過程反復(fù)進(jìn)行,直到認(rèn)證成功或者認(rèn)證次數(shù)達(dá)到上限,服務(wù)端關(guān)閉本次TCP連接。
ssh_password

秘鑰登陸

秘鑰登陸的認(rèn)證流程如下:

  1. 客戶端使用密鑰和算法協(xié)商階段生成的會(huì)話密鑰加密賬號(hào)、認(rèn)證方法、id_rsa.pub,將結(jié)果發(fā)送給服務(wù)端。
  2. 服務(wù)端使用會(huì)話密鑰解密報(bào)文,得到賬號(hào)、id_rsa.pub。服務(wù)端在 $HOME/.ssh/authorized_keys 中找對(duì)應(yīng)的公鑰,如果沒有找到,發(fā)送失敗消息給客戶端,如果找到,比較客戶發(fā)送過來的這個(gè)公鑰和找到的公鑰,如果內(nèi)容相同,服務(wù)端生成一個(gè)隨機(jī)的字符串,簡稱“質(zhì)詢”,然后使用找到的公鑰加密這個(gè)質(zhì)詢,然后使用會(huì)話密鑰再次加密。
  3. 服務(wù)端把這個(gè)雙重加密的數(shù)據(jù)發(fā)送給客戶端
  4. 客戶端使用會(huì)話密鑰解密報(bào)文,然后使用 id_rsa 再次解密數(shù)據(jù),得到質(zhì)詢。
  5. 客戶端使用會(huì)話密鑰加密質(zhì)詢,發(fā)送給服務(wù)端。
  6. 服務(wù)端使用會(huì)話密鑰解密報(bào)文,得到質(zhì)詢,判斷是不是自己生成的那個(gè)質(zhì)詢,如果不相同,發(fā)送失敗消息給客戶端,如果相同,認(rèn)證通過。
ssh_key

二者區(qū)別

我們常說使用秘鑰登陸比密碼登陸更方便更安全,為什么這么說呢?方便是因?yàn)椴挥糜浢艽a,安全是一方面敏感關(guān)鍵的密碼沒有在傳輸,另一方面是因?yàn)橘|(zhì)詢的存在使得在一次對(duì)話中同時(shí)驗(yàn)證了客戶端和服務(wù)端。

高階用法

免密安全傳輸

scp/rsync/sftp 都可以基于 SSH 來進(jìn)行免密安全傳輸,常見命令如下:

# 從本地同步 src.tar.gz 文件到遠(yuǎn)程服務(wù)器 jump_target 的目錄 /path/to/des/
scp src.tar.gz jump_target:/path/to/des/
rsync -avz src.tar.gz jump_target:/path/to/des/

# 從遠(yuǎn)程服務(wù)器 jump_target 的文件 /path/to/src.tar.gz 到本地
scp jump_target:/path/to/src.tar.gz .
rsync -avz jump_target:/path/to/src.tar.gz .

端口轉(zhuǎn)發(fā)

SSH 不僅僅能夠自動(dòng)加密和解密 SSH 客戶端與服務(wù)端之間的網(wǎng)絡(luò)數(shù)據(jù),同時(shí),SSH 還能夠提供了一個(gè)非常有用的功能,那就是端口轉(zhuǎn)發(fā),即將 TCP 端口的網(wǎng)絡(luò)數(shù)據(jù),轉(zhuǎn)發(fā)到指定的主機(jī)某個(gè)端口上,在轉(zhuǎn)發(fā)的同時(shí)會(huì)對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的加密及解密。如果工作環(huán)境中的防火墻限制了一些網(wǎng)絡(luò)端口的使用,但是允許 SSH 的連接,那么也是能夠通過使用 SSH 轉(zhuǎn)發(fā)后的端口進(jìn)行通信。轉(zhuǎn)發(fā)主要分為本地轉(zhuǎn)發(fā)與遠(yuǎn)程轉(zhuǎn)發(fā)兩種類型。

轉(zhuǎn)發(fā)常用參數(shù)

  • -C: 壓縮傳輸,提高傳輸速度。
  • -f: 將 SSH 傳輸轉(zhuǎn)入后臺(tái)執(zhí)行,不占用當(dāng)前 SHELL, 常與 -N 一起使用
  • -N: 建立靜默連接(建立了連接但看不到具體會(huì)話)
  • -g: 在 -L/-R/-D 參數(shù)中,允許遠(yuǎn)程主機(jī)連接到建立的轉(zhuǎn)發(fā)的端口,如果不加這個(gè)參數(shù),只允許本地主機(jī)建立連接。
  • -L: 本地端口轉(zhuǎn)發(fā)
  • -R: 遠(yuǎn)程端口轉(zhuǎn)發(fā)
  • -D:動(dòng)態(tài)轉(zhuǎn)發(fā)( SOCKS 代理)
  • -P: 指定 SSH 端口

本地端口轉(zhuǎn)發(fā)

由本地網(wǎng)絡(luò)服務(wù)器的端口 A,轉(zhuǎn)發(fā)到遠(yuǎn)程服務(wù)器端口 B。說白了就是,將發(fā)送到本地端口 A 的請(qǐng)求,轉(zhuǎn)發(fā)到目標(biāo)端口 B。格式如下

ssh -L 本地網(wǎng)卡地址:本地端口:目標(biāo)地址:目標(biāo)端口 用戶@目標(biāo)地址
常見的應(yīng)用場(chǎng)景見下圖:

ssh_local

對(duì)應(yīng)的命令如下:

# jump_target 服務(wù)器上的 3306 端口服務(wù)映射到本地 33306 `mysql -u root -p root -H localhost -P 33306`
## 1 是 2,3,5 路線中的加密通道,將本地 33306 的網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)發(fā)到 jump_target 的 3306 端口
ssh -C -N -g -L 33306:localhost:3306 jump_target
## 在 2,3 中搞了個(gè)加密通道,然后在跳板機(jī)上將本地 33306 的網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)發(fā)到 172.17.132.120 的 3306 端口
ssh -C -N -g -L 33306:172.17.132.120:3306 jumper

遠(yuǎn)程端口轉(zhuǎn)發(fā)

由遠(yuǎn)程服務(wù)器的某個(gè)端口,轉(zhuǎn)發(fā)到本地網(wǎng)絡(luò)的服務(wù)器某個(gè)端口。說白了,就是將發(fā)送到遠(yuǎn)程端口的請(qǐng)求,轉(zhuǎn)發(fā)到目標(biāo)端口。格式如下:

ssh -R 遠(yuǎn)程網(wǎng)卡地址:遠(yuǎn)程端口:目標(biāo)地址:目標(biāo)端口 用戶@目標(biāo)地址
常見的應(yīng)用場(chǎng)景有個(gè)專用術(shù)語叫內(nèi)網(wǎng)穿透,結(jié)構(gòu)如下圖:

ssh_remote

# 將公網(wǎng)上的服務(wù)器 jump_target 的端口 33333 映射到本地的 22,這樣就可以通過在 jump_target 上通過 SSH 來訪問本地機(jī)器
ssh -f -N -g -R 33333:127.0.0.1:22 jump_target

TIPS:
公網(wǎng)上的服務(wù)器 jump_target 要設(shè)置 GatewayPorts yes,默認(rèn)為 no。此外要映射的端口 33333 要可以訪問。

動(dòng)態(tài)轉(zhuǎn)發(fā)

動(dòng)態(tài)轉(zhuǎn)發(fā)就是建立一個(gè)SSH加密的SOCKS 4/5代理通道。任何支持 SOCKS 4/5 協(xié)議的程序都可以使用這個(gè)加密的通道進(jìn)行訪問。格式如下:
ssh -D [本地地址:]本地端口號(hào) 遠(yuǎn)程用戶@遠(yuǎn)程地址

# 將訪問本地 55558 端口的請(qǐng)求都轉(zhuǎn)發(fā)給 jump_target ,并讓它去執(zhí)行
ssh -C -N -g -T -D 127.0.0.1:55558 jump_target

日常使用問題

跳板機(jī)的配置

# 跳板機(jī)的配置
Host jump
  HostName  jumper.example.com
  Port      58422
  User      haojunyu
  IdentityFile ~/.ssh/dg_rsa
  AddKeysToAgent yes    # 將私鑰添加到 agent 中
  UseKeychain yes       # 保存密碼到 agent 中
# 目標(biāo)機(jī)的配置
Host ws
  HostName  172.17.132.120
  Port      22
  User      haojunyu
  IdentityFile ~/.ssh/dg_rsa
  ProxyCommand ssh haojunyu@jump -W %h:%p 2>/dev/null
  ServerAliveInterval 10
  ServerAliveCountMax 3

內(nèi)網(wǎng)任意服務(wù)訪問

日常工作中經(jīng)常會(huì)啟很多服務(wù)在內(nèi)網(wǎng)機(jī)器上,然后通過打洞(本地端口轉(zhuǎn)發(fā))來將本地的端口映射到內(nèi)網(wǎng)機(jī)器上服務(wù)端口。
這樣有個(gè)問題就是一個(gè)服務(wù)就得維持一個(gè)打洞命令 ssh -C -N -g -L 33306:172.17.132.120:3306 jumper。
對(duì)應(yīng)這樣的問題,最好的解決方案是使用動(dòng)態(tài)轉(zhuǎn)發(fā) ssh -C -N -g -T -D 127.0.0.1:55557 hb_jumper,
本地通過 SwitchyOmega 或 proxifier 工具來將內(nèi)網(wǎng) IP 段 172.17.* 的請(qǐng)求轉(zhuǎn)發(fā)到本地的 55557 端口。

git push 報(bào)權(quán)限不允許(公鑰)

通常在服務(wù)器上執(zhí)行 git push 時(shí)會(huì)報(bào)如下錯(cuò)誤

具體報(bào)錯(cuò)信息:
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

報(bào)錯(cuò)的原因是當(dāng)前機(jī)器上沒有服務(wù)告訴 git 要使用哪個(gè)私鑰來進(jìn)行 git 的操作。
對(duì)應(yīng)的解決方法也比較多,推薦解法一和二:

  • 解法一:通過 ~/.ssh/config 指定(適用個(gè)人機(jī)器)

    Host github.com
        HostName  github.com
        User      haojunyu
        IdentityFile ~/.ssh/id_rsa
    
  • 解法二:配置倉庫或全局的 core.sshCommand(指定倉庫適用共享機(jī)器,全局適用個(gè)人機(jī)器.git版本高于2.3.0

    git config core.sshCommand "ssh -i ~/.ssh/id_rsa -F /dev/null"
    
  • 解法三:ssh-agent 臨時(shí)授權(quán)(適用共享機(jī)器)

    eval `ssh-agent`
    ssh-add ~/.ssh/id_rsa
    

端口轉(zhuǎn)發(fā)命令服務(wù)化

這個(gè)情況是希望開機(jī)時(shí)就把端口轉(zhuǎn)發(fā)開通,并且一直保持著。這就得介紹 linux 中常用的兩種服務(wù)化的工具:Supervisor 和 Systemd。
前者是需要安裝 Supervisor, 但工具比較輕量,使用也比較簡單,后者雖然比較重,但是基本所有系統(tǒng)都自帶。下面提供兩者的配置方法:

  • Supervisor 的配置
[program:ssh-wifi_ol]
command=ssh -C -N -g -L 9789:127.0.0.1:9789 jump
stdout_logfile=/Users/haojunyu/.supervisord_log/ssh-wifi_ol.log
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
  • Systemd 的配置
# gfw service
[Unit]
Description=gfw
After=network.target
[Service]
Type=simple
User=hjy
ExecStart=ssh -C -N -g -T -D 127.0.0.1:55558 gfw
Restart=on-failure
[Install]
WantedBy=multi-user.target

TIPS:
把一些經(jīng)常用的服務(wù)通過端口轉(zhuǎn)發(fā)服務(wù)化,而一些臨時(shí)性的服務(wù)通過命令來進(jìn)行端口轉(zhuǎn)發(fā),也可以使用同事編寫的端口轉(zhuǎn)發(fā)的 Python 程序來進(jìn)行。

參考文獻(xiàn)

  1. 什么是SSH?你應(yīng)該用過吧
  2. 維基百科-SSH
  3. windows支持openssh
  4. 圖解SSH原理
  5. SSH官方文檔
  6. 所有配圖
  7. 中間人攻擊
  8. 了解ssh代理
  9. ssh遠(yuǎn)程登陸中的鑰匙指紋是什么以及如何比對(duì)
  10. ssh登陸認(rèn)證過程詳解

如果該文章對(duì)您產(chǎn)生了幫助,或者您對(duì)技術(shù)文章感興趣,可以關(guān)注微信公眾號(hào): 技術(shù)茶話會(huì), 能夠第一時(shí)間收到相關(guān)的技術(shù)文章,謝謝!

本篇文章由一文多發(fā)平臺(tái)ArtiPub自動(dòng)發(fā)布

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 大綱 一、前言 今天又像打了雞血一樣,想好好學(xué)習(xí)了。正好看到一篇介紹http和https的文章,想到以前面試的時(shí)候...
    Python來了閱讀 1,955評(píng)論 0 3
  • 第1章 SSH服務(wù) 1.1 SSH服務(wù)協(xié)議說明 SSH 是 Secure Shell Protocol 的簡寫,由...
    喝可樂的貓兒閱讀 745評(píng)論 0 1
  • 遠(yuǎn)程管理服務(wù)概念介紹 ssh 安全的遠(yuǎn)程連接,數(shù)據(jù)信息是加密的 端口22 ssh默認(rèn)root連接telnet...
    大仙兒沒溜兒閱讀 354評(píng)論 0 1
  • 37.day05--ssh遠(yuǎn)程協(xié)議1.SSH基本概述SSH是一個(gè)安全協(xié)議,在進(jìn)行數(shù)據(jù)傳輸時(shí),會(huì)對(duì)數(shù)據(jù)包進(jìn)行加密處理...
    優(yōu)秀磚閱讀 2,585評(píng)論 0 0
  • 久違的晴天,家長會(huì)。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,870評(píng)論 16 22

友情鏈接更多精彩內(nèi)容