SSH(Secure Shell)是一种加密网络协议,用于在不安全的网络(如互联网)上安全地进行远程登录、命令执行、文件传输等操作。它取代了早期不安全的明文协议(如 Telnet、FTP、rlogin),是系统管理员、开发者和IT运维人员必备的核心工具。

一、核心功能与用途

  1. 安全远程登录: 登录到远程服务器执行命令(替代 Telnet)。

  2. 安全文件传输:

    • scp (Secure Copy):基于 SSH 的命令行文件传输工具。

    • sftp (SSH File Transfer Protocol):提供类似 FTP 的交互式文件传输接口。

    • rsync over SSH:高效的文件同步工具,利用 SSH 加密传输。

  3. 端口转发 / 隧道:

    • 本地端口转发: 将本地端口映射到远程服务器的端口(访问本地端口即访问远程服务)。

    • 远程端口转发: 将远程服务器端口映射到本地端口(让远程访问本地服务)。

    • 动态端口转发: 创建 SOCKS 代理,将所有流量通过 SSH 服务器转发。

  4. 安全执行远程命令: 无需登录交互式 Shell,直接在远程执行单条命令。

  5. 安全 X11 转发: 在本地显示运行在远程服务器上的图形界面程序(需要 X Server)。

  6. 代理转发: 允许通过跳板机(Bastion Host/Jump Server)连接到无法直接访问的内网服务器。


二、核心组件

  1. SSH 客户端: 发起连接请求的程序(如 ssh, scp, sftp, PuTTY, SecureCRT, MobaXterm)。

  2. SSH 服务器: 接收连接请求并处理的后台程序(通常称为 sshd)。

  3. 密钥对:

    • 公钥: 放置在远程服务器上(~/.ssh/authorized_keys)。

    • 私钥: 严格保管在本地客户端(~/.ssh/id_rsa, ~/.ssh/id_ed25519 等),通常设置权限 600


三、工作原理(SSHv2)

  1. TCP 连接建立: 客户端连接到服务器的 22 端口(默认)。

  2. 协议版本协商: 客户端和服务端协商使用 SSH 协议版本(强烈推荐使用 SSH-2)。

  3. 密钥交换: 使用 Diffie-Hellman 等算法协商出一个临时的会话密钥。此过程确保即使攻击者截获了交换信息,也无法计算出会话密钥(前向保密)。

  4. 服务端认证:

    • 服务端向客户端发送其 主机密钥(公钥)。

    • 客户端检查此密钥是否在已知信任列表(~/.ssh/known_hosts)中。

    • 如果是首次连接,客户端会提示用户验证并确认接受该主机密钥(防止中间人攻击)。

  5. 用户认证:

    • 密码认证: 用户输入密码,密码通过加密通道传输到服务端验证。

    • 公钥认证(推荐):

      1. 客户端告知服务端其想使用的公钥 ID。

      2. 服务端检查该公钥是否在用户的 authorized_keys 文件中。

      3. 服务端生成一个随机数,用该公钥加密,发送给客户端。

      4. 客户端用对应的私钥解密,将结果发回服务端。

      5. 服务端验证结果正确则认证成功。

    • 其他方式:键盘交互认证(用于一次性密码)、基于主机的认证(较少用)。

  6. 加密通道建立: 使用协商好的会话密钥对称加密算法(如 AES, ChaCha20)加密后续所有通信。

  7. 数据完整性: 使用 HMAC(基于哈希的消息认证码)算法(如 SHA-256)保证传输的数据未被篡改。

  8. 会话复用: 通过 ControlMasterControlPath 配置,复用已建立的连接,避免重复认证开销。


四、配置文件

  • 客户端全局配置: /etc/ssh/ssh_config

  • 客户端用户配置: ~/.ssh/config (非常常用,简化连接)

    • 使用:ssh myserver, ssh internal-db

  • 服务端配置: /etc/ssh/sshd_config (修改后需重启 sshd 服务)

    • 关键配置项:

      • Port:监听端口。

      • PermitRootLogin:是否允许 root 登录 (推荐 noprohibit-password)。

      • PasswordAuthentication:是否允许密码认证 (推荐 no,强制使用公钥)。

      • PubkeyAuthentication:是否启用公钥认证 (推荐 yes)。

      • AllowUsers / AllowGroups:限制可登录的用户/组。

      • X11Forwarding:是否允许 X11 转发。

      • PermitEmptyPasswords:是否允许空密码 (必须 no)。

      • ClientAliveInterval / ClientAliveCountMax:保持连接活跃设置。


五、基本用法(命令行客户端)

  1. 使用密码登录的方式连接:
    安装SSH

    yum install openssh -y				# Centos和RedHat
    # 或
    apt install openssh-server -y		# Debain和Ubuntu

    修改ssh的配置文件,使客户端可以正常连接

    vim /etc/ssh/sshd_config
    找到并修改以下内容:
        Port 22									# 监听22端口
        Protocol 2								# 强制使用SSHv2
        PermitRootLogin yes						# 运行root用户登录

    0

    重新启动ssh服务

    systemctl restart sshd

    可以使用以下格式连接:

    ssh root@192.168.10.10             # 默认使用22端口,如果使用别的端口,需要使用-p后跟端口(小写p)

    0
    如果我们仅仅允许某个用户登录,其他用户为了安全不允许登录,可以设置白名单

    AllowUsers xxxx
  2. 使用密钥登录:

    本地生成密钥对:ssh-keygen -t ed25519 (推荐) 或 ssh-keygen -t rsa -b 4096

    Windows端

    CMD或PowerShell输入,一直回车即可

    ssh-keygen -t rsa -b 4096                                 # 生成RSA算法的SSH私钥和公钥,不加-d选项也可

    生成私钥和公钥后会存储在C盘该用户目录下的.ssh目录内,接下来将公钥发送到Linux服务器上

    scp C:\Users\OpenNW\.ssh\id_rsa.pub opennw@172.16.0.102:/home/opennw

    Linux端

    cd /hmoe/opennw
    mkdir .ssh
    chmod 700 .ssh
    mv id_rsa.pub authorized_keys
    chmod 600 authorized_keys
    mv authorized_keys .ssh/
    vim /etc/ssh/sshd_config
    修改以下内容:
    Port 22                                            # 监听22端口
    Protocol 2										   # 强制使用SSHv2
    LoginGraceTime 1m                                  # 登录超时时间1分钟
    PermitRootLogin without-password                   # 仅允许Root用户使用秘钥登录
    DenyUsers xxx	                                   # 禁止xxx用户登录
    MaxAuthTries 3                                     # 最大认证次数3
    MaxSessions 2                                      # 最大会话数2
    
    PasswordAuthentication no                          # 禁止密码验证登录
    PermitEmptyPasswords no                            # 禁止空密码验证
    
    UseDNS no										   # 不对客户端进行DNS泛解析验证,加快SSH连接速度
    
    PubkeyAuthentication yes                           # 开启SSH公钥认证登录
    AuthorizedKeysFile .ssh/authorized_keys            # 用户登录公钥路径,如果该用户需要多设备免密登录,可以再authorized_keys文件内另起一行写入其他设备的公钥,也可以在此配置后再跟上.ssh/xxx_keys即可
    RSAAuthentication yes                              # 允许RSA算法验证
    保存并退出
    systemctl restart sshd
    systemctl enable sshd

    随后,客户端使用SSH命令登录服务器端无需输入密码即可登录,且为了安全我们已经设置了强制使用密钥登录(禁止密码登录),接下来我们要做的就是保证刚才生成的私钥文件不被泄露即可~

  3. 执行远程命令:

    ssh username@hostname 'command_to_run'
    # 例如:ssh alice@server.example.com 'ls -l /tmp'
  4. 文件传输:

    • scp (复制文件):
      首先确保ssh服务端配置文件中开启了以下内容

      Subsystem       sftp    /usr/lib/openssh/sftp-server

      随后,在客户端上可进行以下命令使用scp文件传输

      # 复制本地文件到远程
      scp /path/to/local/file username@hostname:/path/to/remote/directory
      # 复制远程文件到本地
      scp username@hostname:/path/to/remote/file /path/to/local/directory
      # 指定端口需要使用scp -P 2222 ...(大写P)
      # 传输目录需要使用scp -r ...
    • sftp (交互式文件传输):

      sftp username@hostname
      sftp> put localfile [remotepath]   # 上传
      sftp> get remotefile [localpath]    # 下载
      sftp> ls                           # 列出远程目录
      sftp> lls                          # 列出本地目录
      sftp> cd, lcd, mkdir, rmdir, ...   # 类似 FTP 命令
      sftp> exit / bye

六、端口转发(隧道)

  1. 本地端口转发:本地端口绑定到远程服务的端口。

    • 场景: 访问远程服务器内部网络的服务(如数据库)。

    • 命令:

      ssh -L [bind_address:]local_port:remote_host:remote_port username@ssh_server
    • 示例: 将本地 3307 端口映射到远程服务器内网主机 db.internal3306 (MySQL) 端口:

      ssh -L 3307:db.internal:3306 alice@jumpserver.example.com
      • 访问本地的 127.0.0.1:3307 即访问 jumpserver 能访问到的 db.internal:3306

  2. 远程端口转发:远程服务器端口绑定到本地服务的端口。

    • 场景: 将本地开发环境暴露给外部访问(临时演示)、让内网服务被外网访问。

    • 命令:

      ssh -R [bind_address:]remote_port:local_host:local_port username@ssh_server
    • 示例: 将远程服务器 jumpserver8080 端口映射到本地 127.0.0.1:3000 (本地 Web 服务):

      ssh -R 8080:localhost:3000 alice@jumpserver.example.com
      • 访问 jumpserver.example.com:8080 即访问本地的 localhost:3000

    • 注意: 默认远程服务器只监听 127.0.0.1 (localhost),如需外部访问,需在服务端 sshd_config 中设置 GatewayPorts yes 并重启 sshd

  3. 动态端口转发: 创建 SOCKS 代理服务器。

    • 场景: 所有应用程序流量通过 SSH 服务器转发,绕过本地网络限制或加密流量。

    • 命令:

      ssh -D [bind_address:]local_socks_port username@ssh_server
    • 示例: 在本地 1080 端口启动 SOCKS5 代理:

      ssh -D 1080 alice@proxy.example.com
      • 随后终端会像正常连接ssh一样登录到远程服务器上,但同时如果你在Windows终端使用netstat -ano | findstr :1080会看到该端口已经被监听,然后只要终端不关闭,就可以使用Socks5配置SSH代理,使流量被远程服务器代理转发。且由于Socks5是应用层代理也不需要配置复杂的NAT;

      • 系统代理:可在控制面板中,找到网络和InternetInternet选项连接局域网设置—勾选为LAN使用代理服务器高级套接字地址为127.0.0.1,端口为1080,其余都删除。取消掉对本地不使用代理服务器随后代理生效。但需要注意的是,设置了代理后,系统中并不是所有程序都会监听代理,如命令行及UDP,而浏览器默认是支持的,这是和VPN的一个主要区别;

      • 浏览器代理:在火狐浏览器或系统网络设置中配置代理为 SOCKS5,地址 127.0.0.1,端口 1080,则所有流量通过 proxy.example.com 加密转发。

      • 浏览器代理:如果使用的是谷歌浏览器,默认不支持SOCKS5,可在浏览器扩展中安装扩展Socks5 configurator,在扩展页面设置即可好后保存即可,接下来浏览器查询自己的IP地址即可发现IP地址已经发生变化。如果希望关闭代理,最好先在扩展中关闭,然后再关闭终端窗口。

socks5_proxy


七、日志查看(基于debain)

修改SSH配置文件,日志为auth类型

vim /etc/ssh/sshd_config
SyslogFacility AUTH
LogLevel VERBOSE                    # 日志等级为“详细”
保存退出

修改rsyslog中auth类型日志存放位置

vim /etc/rsyslog.conf
auth,authpriv.*                 /var/log/auth.log
保存退出

重启SSH服务和rsyslog服务

systemctl restart sshd
systemctl restart rsyslog

查看登录成功简要信息

last

查看登录失败简要信息

lastb

查看日志中登录成功和失败的详细信息

cat /var/log/auth.log | grep Accepted
cat /var/log/auth.log | grep Failed

八、最佳安全实践

  1. 强制使用 SSHv2: 禁用过时且不安全的 SSHv1。

  2. 禁用密码登录: 仅允许公钥认证。这是防止暴力破解密码的最有效手段 (PasswordAuthentication no)。

  3. 禁用 Root 直接登录: 使用普通用户登录后 sudo (PermitRootLogin noprohibit-password)。

  4. 使用强密码/密码短语: 保护私钥和用户账户。

  5. 限制访问来源: 使用防火墙 (iptables, ufw, firewalld) 限制 SSH 端口访问 IP。

  6. 更改默认端口: 减少自动化扫描攻击 (但非绝对安全,需结合其他措施)。

  7. 使用非标准用户: 避免使用 admin, administrator, test 等常见用户名。

  8. 保持软件更新: 及时更新 SSH 客户端和服务端 (openssh-server, openssh-client)。

  9. 监控日志: 定期检查 /var/log/auth.log/var/log/secure 中的 SSH 登录尝试。

  10. 使用 Fail2ban: 自动封禁多次登录失败的 IP 地址。

  11. 谨慎使用代理转发 (​​ForwardAgent): 仅在完全信任目标服务器时使用。


九、高级技巧/应用场景

  1. ssh-agent ssh-add 管理私钥密码短语,避免多次输入。

  2. 多因素认证 (MFA): 结合 Google Authenticator 等为 SSH 登录增加一层保护。

  3. Git over SSH: Git 远程仓库使用 SSH URL (git@github.com:user/repo.git)。

  4. sshfs 使用 FUSE 将远程目录挂载到本地文件系统。

  5. 远程调试/服务管理:

    ssh -t myserver 'sudo systemctl status nginx; journalctl -u nginx -f'
  6. 连接调试: 使用 -v (verbose) 参数诊断连接问题:

    ssh -vvv username@hostname

总结

SSH 是安全远程管理的基石。理解其核心原理(加密、认证、隧道)、熟练掌握基本命令(登录、scp/sftp、端口转发)和配置文件 (~/.ssh/config, /etc/ssh/sshd_config),并遵循严格的安全实践(禁用密码、禁用root登录、更新、监控),是高效、安全使用 SSH 的关键。它的灵活性和强大功能使其成为连接和管理远程系统的首选工具。