SSH usage & login security

ssh的使用与登录方式的安全性问题探索

ssh的使用与登录方式的安全性问题探索

直接跳结论

fingerprint

ssh 连接的第一步需要手动确认服务器的指纹 这是防止中间人攻击和确保安全性的重要一环

查询服务器的指纹有两种方法:

在客户端上 需要先获取服务器公钥文件再计算指纹

1
2
3
4
$ ssh-keyscan __host__ # 获取所有公钥
$ ssh-keyscan -t ed25519 __host__ # 获取 ed25519 加密算法的公钥
$ ssh-keyscan -t ed25519 __host__|ssh-keygen -lf - # 获取 ed25519 公钥的 fingerprint
# 算法集合: rsa,dsa,ecdsa,ed25519

在服务器上 可以直接查看 公钥和私钥在/etc/ssh路径下

1
2
3
$ ssh-keygen -lf /etc/ssh/ssh_host_$algo_key.pub # 查看某种算法的公钥 fingerprint
# algos: rsa,dsa,ecdsa,ed25519
# 可以指定其他签名算法 `[-E md5|sha256|..] (默认使用 SHA256)

加密过程

基本与TLS1.2加密过程相同(经典的RSA密钥交换方案) 不过验证证书(服务器fingerprint)的工作交给了用户来完成

fingerprint 是用于客户端辨别是否为真实服务器的根据 效果等同于 HTTPS 证书

算法

现在在使用的加密算法主要是下面四种

  • DSA (属于是已经不被支持的淘汰算法了)
  • RSA: 3072/4096bit长度是安全选项 长度低于2048比特的密钥已经被认为是不安全的
  • ECDSA: 不太稳定 依赖于机器产生随机数的性能
  • Ed25519: 目前最推荐 加密性能更好同时密钥长度还更短
1
2
# 查看当前所使用的密钥
for key in ~/.ssh/*.pub; do ssh-keygen -l -f "${key}"; done

使用 ed25519 算法生成密钥

1
2
3
4
ssh-keygen -t ed25519 [-C "your comment here"] [-f ~/.ssh/your_private_key_file]
# -C 添加备注内容(可选)
# -f 指定私钥文件名(可选) 默认私钥文件名为 id_ed25519
# 公钥文件名默认为 私钥文件名.pub

ssh-copy-id

使用非对称加密需要把客户端的公钥拷贝到服务端上 一般会使用ssh-copy-id

这其实是个脚本文件 核心逻辑在于下面这段

1
2
3
[ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \
  ssh "$@" "exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && { [ -z "'`tail -1c .ssh/authorized_keys 2>/dev/null`'" ] || echo >> .ssh/authorized_keys ; } && cat >> .ssh/authorized_keys || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi'" \
  || exit 1

效果约等于 cat ~/.ssh/your_pub_key|ssh user@ip "cat >> .ssh/authorized_keys"

详解:

  • tail -1c 查看最后一个字节
  • { [ -z ... ] || echo >> .ssh/authorized_keys ; } 保证有个换行 -z 为判空
  • cat >> .ssh/authorized_keys 此处将之前通过管道传入的公钥放入服务器authorized_keys
  • restorecon 恢复(restore)文件上下文(context)

可以看出 这个脚本底层使用 ssh 它的安全性和使用密码登录ssh一致

ssh config

SSH 客户端和服务器可以添加一些配置文件 客户端的默认配置文件为/etc/ssh/ssh_config~/.ssh/config

完整的配置参考见

常用的配置为配置服务器的别名 配置一个服务器的别名的写法如下

1
2
3
4
5
6
Host nickname # 你想使用的别名
  User your_username # 真实的用户名
  HostName ip_or_host # 服务器 IP 或者域名
  IdentityFile ~/.ssh/private_key # 对应的私钥
  IdentitiesOnly yes # 只使用密钥登录
  Port 22 # 设置连接端口 默认为 22

配置一台需要中间跳板的服务器写法如下

1
2
3
4
5
6
7
Host rev_nick
  User your_username # 真实的用户名
  HostName ip_or_host # 服务器 IP 或者域名
  IdentityFile ~/.ssh/private_key # 对应的私钥
  IdentitiesOnly yes # 只使用密钥登录
  Port 22 # 设置连接端口 默认为 22
  ProxyJump nickname

ProxyJump 的值为一台服务器

如此配置之后

1
2
$ ssh nickname # 登录 nickname 服务器
$ ssh rev_nick # 登录 nickname 作为跳板的服务器

补充内容

authentication

现在的授权方式有两种

  • 密码登录
  • 密钥登录(公钥私钥)

对比这两种方式 我个人更倾向于与密钥登录

方式优点缺点
密码使用简单一些ssh GUI工具提供记住密码功能如果监听整个通信 密码可能会被获取并解密大多数人的密码通用且可能比较简单
密钥密码相关数据不会出现在通信过程中使用有一定的理解成本私钥安全性依赖于它的私密性

总体来说 偏好原因如下

  • 使用密钥不会让密码多次在通信中反复出现 更安全一点
  • 使用密钥对于命令行用户更友好(除非sshd没有设置密钥授权)

Pubkey permission

首先先开启服务器的公钥登录

1
2
# in /etc/ssh/sshd_config
PubkeyAuthentication yes

用户目录权限

1
2
3
4
私钥 600 # 保证私钥其他用户没有权限
.ssh 700 # 保证 others 没有写权限
公钥 644 # 同上
.ssh/authorized_keys 644 # 同上

如果权限设置有问题 ssh 公钥登录将不启用

如果不是使用的默认公钥名 那么在使用 user@ip 登录时 需要指定私钥文件 ssh -p _port_ -i private.file u@ip

tunnel

可以将 ssh 用作加密通信的中介: 端口转发

作用

  • 加密数据传输
  • 加密跳板 绕过防火墙
转发方式使用场景指令示例使用示例备注
动态转发用作代理服务器ssh -ND local-port tunnel-hostcurl -x socks5://localhost:local-port http://www.example.com需要使用SOCKS5协议
本地转发指定本地端口数据转发到跳板机端口ssh -NL local-port:target-host:tunnel-port tunnel-hostcurl http://localhost:local-porttunnel-host可达target-host(可以相同)
远程转发指定跳板机端口数据转发到本地端口ssh -NR remote-port:target-host:target-port remote-host

具体见 WangDoc SSH port-forwarding

rsync

rsync: remote sync 远程同步工具 可以只传变动内容

远程传输时 rsync 会默认使用 ssh 协议

1
2
$ rsync remote-host:source dest
$ rsync -e 'ssh -p port' source remote-host:dest

具体使用见 WangDoc rsync

tl;dr

ed25519 算法比 RSA 更安全

同时也更建议使用公钥的方式(同时建议私钥设置密码)

简单介绍一下使用吧

先需要服务器允许公钥登录 配置文件:/etc/ssh/sshd_config

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 生成公钥和私钥 中括号中的参数都是可选的
ssh-keygen [-t ed25519] [-C "your comment here"] [-f ~/.ssh/your_private_key_file]
# 默认加密算法为 RSA 建议使用 ed25519
# 默认私钥文件名: ~/.ssh/id_ed25519 (其实是 id_${加密算法}) 公钥: ~/.ssh/id_ed25519.pub

# 之后是确定密码 建议使用 不过偷懒的话 敲两下回车就好了

ssh-copy-id [-i ~/.ssh/your_private_key_file.pub] _user@_hostname

# 之后就可以用了

为了使用方便的话 一般会设置别名(可选)

在文件 ~/.ssh/config 里面添加 下面一段内容

1
2
3
4
5
6
7
# 设置之后可以通过 `ssh nickname` 的方式快速登录
Host nickname # 你想使用的别名
  User your_username # 真实的用户名
  HostName ip_or_host # 服务器 IP 或者域名
  IdentityFile ~/.ssh/private_key # 对应的私钥
  IdentitiesOnly yes
  Port 22 # 设置端口 默认为 22
Built with Hugo
主题 StackJimmy 设计