跳到主要内容

SSH、FTP 与 SFTP

远程服务器管理和文件传输是现代开发和运维工作的核心环节。SSH(Secure Shell)作为安全远程访问的标准协议,已经成为系统管理的必备工具。理解 SSH 的工作原理、密钥管理和安全配置,对于构建安全的运维体系至关重要。

SSH 协议概述

SSH(Secure Shell)是一种加密的网络传输协议,用于在不安全的网络中安全地传输数据。它取代了不安全的 Telnet、rlogin、rsh 等协议,成为远程登录和命令执行的事实标准。

SSH 协议架构

SSH 协议由三层组成,定义在多个 RFC 文档中:

传输层协议(RFC 4253):负责服务器认证、密钥交换、加密和完整性保护。这是 SSH 安全性的基础。

认证协议(RFC 4252):定义了多种认证方式,包括公钥认证、密码认证、主机认证等。

连接协议(RFC 4254):在加密通道上复用多个逻辑通道,支持远程命令执行、Shell 访问、端口转发等功能。

SSH 与 Telnet 的对比

特性SSHTelnet
数据加密是(AES、ChaCha20 等)否(明文传输)
身份认证公钥、密码、证书仅密码
完整性保护是(HMAC)
端口转发支持不支持
文件传输内置(SCP/SFTP)需要 FTP
安全性极低

SSH 连接建立过程

SSH 连接的建立分为三个阶段:

密钥交换详解

SSH 使用 Diffie-Hellman 或 ECDH 进行密钥交换,确保即使有人截获了通信,也无法推导出会话密钥:

  1. 算法协商:双方交换支持的算法列表,选择双方都支持的最强算法
  2. 密钥交换:使用 DH/ECDH 算法生成共享密钥
  3. 服务器认证:服务器用私钥签名,客户端用已知的公钥验证
  4. 密钥派生:从共享密钥派生出加密密钥、MAC 密钥、IV 等

SSH 密钥管理

公钥认证是 SSH 最安全的认证方式,也是自动化运维的基础。

密钥对生成

# 生成 RSA 密钥对(传统方式,兼容性好)
ssh-keygen -t rsa -b 4096 -C "[email protected]"

# 生成 Ed25519 密钥对(推荐,更安全更高效)
ssh-keygen -t ed25519 -C "[email protected]"

# 生成 ECDSA 密钥对
ssh-keygen -t ecdsa -b 521 -C "[email protected]"

密钥类型对比

类型密钥长度安全性性能兼容性
RSA2048-4096 位中等最好
ECDSA256-521 位
Ed25519固定 256 位很高最快较好

密钥生成交互过程

$ ssh-keygen -t ed25519 -C "[email protected]"
Generating public/private ed25519 key pair.
# 选择保存位置(默认 ~/.ssh/id_ed25519)
Enter file in which to save the key (/home/user/.ssh/id_ed25519):

# 设置密码短语(增加安全性)
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 [email protected]
The key's randomart image is:
+--[ED25519 256]--+
| ooo. |
| o.ooo |
| + .+ o |
| o = +o . |
| . + * S. |
| . = Bo . |
| . *.*o |
| + =+. |
| .E+. |
+----[SHA256]-----+

密钥文件结构

私钥文件(id_ed25519

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDGxMTE0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA4
-----END OPENSSH PRIVATE KEY-----

公钥文件(id_ed25519.pub

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGXAMPLE... [email protected]

公钥文件格式为:算法名 公钥数据 注释

密钥部署

将公钥部署到远程服务器:

# 方法 1:使用 ssh-copy-id(推荐)
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

# 方法 2:手动复制
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# 方法 3:手动编辑
# 将公钥内容添加到服务器的 ~/.ssh/authorized_keys 文件中

密钥权限设置

正确的文件权限对于 SSH 安全至关重要:

# 本地机器
chmod 700 ~/.ssh # .ssh 目录
chmod 600 ~/.ssh/id_ed25519 # 私钥
chmod 644 ~/.ssh/id_ed25519.pub # 公钥
chmod 644 ~/.ssh/known_hosts # 已知主机

# 远程服务器
chmod 700 ~/.ssh # .ssh 目录
chmod 600 ~/.ssh/authorized_keys # 授权密钥

权限设置错误会导致 SSH 拒绝使用密钥:

Permissions 0644 for '/home/user/.ssh/id_ed25519' are too open.
It is required that your private key files are NOT accessible by others.

SSH Agent 管理

使用 SSH Agent 可以避免每次连接都输入密码短语:

# 启动 SSH Agent
eval "$(ssh-agent -s)"

# 添加密钥到 Agent
ssh-add ~/.ssh/id_ed25519

# 列出已添加的密钥
ssh-add -l

# 删除所有密钥
ssh-add -D

# 锁定 Agent(需要密码解锁)
ssh-add -x

# 解锁 Agent
ssh-add -X

SSH 配置详解

客户端配置文件

SSH 客户端配置文件位于 ~/.ssh/config,可以简化连接命令:

# 全局默认配置
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3

# 服务器别名配置
Host web-server
HostName 192.168.1.100
User admin
Port 2222
IdentityFile ~/.ssh/web_server_key

# 通过跳板机连接
Host internal-server
HostName 10.0.0.50
User deploy
ProxyJump jump-server

# 跳板机配置
Host jump-server
HostName jump.example.com
User jumper
IdentityFile ~/.ssh/jump_key

# 多重跳板
Host final-server
HostName 10.10.10.10
User admin
ProxyJump jump1,jump2

# 会话复用
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600

配置后,可以直接使用别名连接:

# 不需要记住 IP、端口、用户名
ssh web-server

# 自动通过跳板机连接
ssh internal-server

服务器配置文件

SSH 服务器配置文件位于 /etc/ssh/sshd_config

# 监听端口
Port 22

# 监听地址(0.0.0.0 表示所有接口)
ListenAddress 0.0.0.0

# 协议版本(SSH-2)
Protocol 2

# 主机密钥
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# 认证配置
PermitRootLogin no # 禁止 root 登录
PubkeyAuthentication yes # 启用公钥认证
PasswordAuthentication no # 禁用密码认证
PermitEmptyPasswords no # 禁止空密码
ChallengeResponseAuthentication no # 禁用挑战响应认证

# 授权密钥文件
AuthorizedKeysFile .ssh/authorized_keys

# 连接限制
MaxAuthTries 3 # 最大认证尝试次数
MaxSessions 10 # 最大会话数
LoginGraceTime 60 # 登录超时时间

# 安全配置
X11Forwarding no # 禁用 X11 转发
AllowTcpForwarding yes # 允许 TCP 转发
AllowAgentForwarding yes # 允许 Agent 转发

# 加密算法(推荐配置)
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]

# 允许的用户/组
AllowUsers admin deploy
# AllowGroups ssh-users

# 日志
SyslogFacility AUTH
LogLevel INFO

修改配置后需要重启服务:

# 检查配置语法
sudo sshd -t

# 重启服务
sudo systemctl restart sshd

# 查看状态
sudo systemctl status sshd

SSH 隧道与端口转发

SSH 隧道可以安全地转发网络流量,是解决内网穿透的经典方案。

本地端口转发

将远程服务的端口映射到本地:

# 语法:ssh -L 本地端口:目标主机:目标端口 跳板机
ssh -L 8080:internal-server:80 jump-server

# 访问本地 8080 端口等于访问 internal-server:80
curl http://localhost:8080

应用场景:通过跳板机访问内网服务

远程端口转发

将本地服务的端口暴露到远程:

# 语法:ssh -R 远程端口:本地主机:本地端口 远程服务器
ssh -R 3000:localhost:3000 server.example.com

# 远程服务器上访问 localhost:3000 等于访问本地的 3000 端口

应用场景:让外部访问本地开发服务器

# 在本地运行开发服务器
npm run dev # 监听 localhost:3000

# 通过 SSH 暴露到公网服务器
ssh -R 8080:localhost:3000 [email protected]

# 外部访问 public-server.com:8080 即可访问本地服务

动态端口转发(SOCKS 代理)

创建一个 SOCKS 代理服务器:

# 语法:ssh -D 本地端口 远程服务器
ssh -D 1080 server.example.com

# 配置浏览器使用 SOCKS5 代理:localhost:1080
# 所有流量都通过 SSH 隧道转发

应用场景:安全浏览、绕过网络限制

配置文件中的端口转发

~/.ssh/config 中配置:

Host tunnel-web
HostName jump-server.example.com
User admin
LocalForward 8080 internal-server:80
LocalForward 3306 db-server:3306

Host expose-local
HostName public-server.example.com
User deploy
RemoteForward 8080 localhost:3000

SCP 与 SFTP 文件传输

SCP(Secure Copy)

SCP 是基于 SSH 的简单文件复制命令:

# 上传文件
scp local-file.txt user@server:/remote/path/

# 下载文件
scp user@server:/remote/file.txt ./local/path/

# 上传目录
scp -r local-directory/ user@server:/remote/path/

# 从跳板机下载
scp -J jump-server user@internal-server:/file.txt ./

# 使用特定端口
scp -P 2222 file.txt user@server:/path/

# 显示进度
scp -v large-file.iso user@server:/path/

SFTP(SSH File Transfer Protocol)

SFTP 提供交互式文件传输,功能更丰富:

# 连接服务器
sftp [email protected]

# SFTP 交互命令
sftp> ls # 列出远程目录
sftp> lcd ~/Downloads # 切换本地目录
sftp> get remote-file.txt # 下载文件
sftp> put local-file.txt # 上传文件
sftp> mget *.txt # 下载多个文件
sftp> mput *.jpg # 上传多个文件
sftp> mkdir new-dir # 创建远程目录
sftp> rm file.txt # 删除远程文件
sftp> exit # 退出

SFTP 与 FTP 的对比

特性SFTPFTP
传输协议SSH独立协议
端口2220, 21
数据加密
通道数量单一通道控制连接 + 数据连接
防火墙友好否(需要被动模式)
断点续传支持支持

SSH 安全最佳实践

服务器端安全加固

# 1. 禁用密码认证,只允许密钥
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes

# 2. 禁止 root 登录
PermitRootLogin no

# 3. 使用非标准端口
Port 2222

# 4. 限制登录用户
AllowUsers admin deploy

# 5. 配置失败锁定
# 安装 fail2ban
sudo apt install fail2ban

# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600

# 6. 使用强加密算法
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]

客户端安全建议

# 1. 使用密码短语保护私钥
ssh-keygen -t ed25519 -C "[email protected]"
# 设置一个强密码短语

# 2. 定期轮换密钥
# 建议每年更换一次密钥对

# 3. 使用 SSH Agent 转发时要谨慎
# 只在信任的网络中使用
ForwardAgent yes # 仅在需要时启用

# 4. 验证服务器指纹
# 首次连接时验证指纹是否正确
ssh-keygen -l -f ~/.ssh/known_hosts

# 5. 使用 known_hosts 进行主机验证
StrictHostKeyChecking ask
UserKnownHostsFile ~/.ssh/known_hosts

密钥管理最佳实践

# 1. 为不同用途使用不同密钥
~/.ssh/
├── id_ed25519 # 日常使用
├── id_ed25519_github # GitHub 专用
├── id_ed25519_aws # AWS 专用
└── id_ed25519_deploy # 部署专用

# 2. 备份私钥(加密存储)
# 将私钥备份到安全位置,如密码管理器

# 3. 定期审计授权密钥
# 检查服务器上的 authorized_keys
cat ~/.ssh/authorized_keys

# 4. 使用证书认证(大规模环境)
# SSH CA 可以集中管理密钥信任关系

SSH 故障排查

常见问题诊断

# 1. 详细输出模式
ssh -vvv user@server

# 2. 检查配置文件语法
sudo sshd -t

# 3. 测试特定端口
ssh -p 2222 user@server

# 4. 检查服务器是否运行
sudo systemctl status sshd
sudo netstat -tlnp | grep 22

# 5. 检查防火墙
sudo ufw status
sudo iptables -L -n | grep 22

# 6. 查看日志
sudo tail -f /var/log/auth.log
sudo journalctl -u sshd -f

常见错误及解决

错误 1:Permission denied (publickey)

原因:密钥认证失败 解决:

# 检查密钥是否正确
ssh-add -l

# 检查服务器上的 authorized_keys
cat ~/.ssh/authorized_keys

# 检查权限
ls -la ~/.ssh/

错误 2:Host key verification failed

原因:服务器指纹变化(可能是重新安装或中间人攻击) 解决:

# 删除旧指纹
ssh-keygen -R server.example.com

# 重新连接验证新指纹
ssh [email protected]

错误 3:Connection refused

原因:SSH 服务未运行或端口错误 解决:

# 检查服务状态
sudo systemctl status sshd

# 检查端口
sudo netstat -tlnp | grep sshd

# 尝试其他端口
ssh -p 2222 user@server

FTP 协议简介

FTP(File Transfer Protocol)是历史悠久的文件传输协议,但由于安全性问题,现在已被 SFTP 替代。

FTP 工作模式

FTP 使用两个连接:

控制连接(端口 21):传输命令和响应 数据连接(端口 20 或随机端口):传输文件内容

主动模式与被动模式

主动模式:服务器主动连接客户端的数据端口

  • 客户端告诉服务器自己的数据端口
  • 服务器从端口 20 连接客户端
  • 问题:客户端防火墙通常阻止入站连接

被动模式:客户端连接服务器的数据端口

  • 服务器告诉客户端自己的数据端口
  • 客户端主动连接服务器
  • 现代 FTP 的默认模式

FTP 的安全问题

问题说明
明文传输用户名、密码、数据都是明文
多端口防火墙配置复杂
被动模式端口预测可能被利用进行端口扫描

结论:生产环境应使用 SFTP 替代 FTP。

总结

SSH 是现代系统管理的基石,掌握 SSH 的核心技能对于运维和开发工作至关重要:

  • 协议架构:传输层、认证层、连接层三层结构确保安全性
  • 密钥管理:Ed25519 密钥是当前最佳选择,正确设置权限是安全的前提
  • 配置优化:通过配置文件简化连接,服务器端加固提升安全性
  • 隧道技术:端口转发实现内网穿透,解决复杂网络环境下的访问问题
  • 文件传输:SFTP 比 FTP 更安全,SCP 适合简单快速的文件复制

在安全威胁日益严峻的今天,正确使用 SSH 并遵循最佳实践,是保护服务器安全的基本要求。

[!TIP] 想了解其他应用层协议?请看 DNS 域名系统HTTP 协议详解