SSH 完全教程 2

SSH 密钥登录

SSH 默认采用密码登录,这种方法有很多缺点,简单的密码不安全,复杂的密码不容易记忆,每次手动输入也很麻烦。密钥登录是b比密码登录更好的解决方案。

密钥是什么

密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。

SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。

如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。

密钥登录的过程

SSH 密钥登录分为以下的步骤。

预备步骤,客户端通过ssh-keygen生成自己的公钥和私钥。

第一步,手动将客户端的公钥放入远程服务器的指定位置。

第二步,客户端向服务器发起 SSH 登录的请求。

第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。

第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。

第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。

ssh-key命令:生成密钥

基本用法

密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen命令,用来生成密钥。

直接输入ssh-keygen,程序会询问一系列问题,然后生成密钥。

$ ssh-keygen

通常做法是使用-t参数,指定密钥的加密算法。

$ ssh-keygen -t dsa

上面示例中,-t参数用来指定密钥的加密算法,一般会选择dsa算法或rsa算法。注意,这个参数没有默认值。

输入上面的命令以后,ssh-keygen会要求用户回答一些问题。

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_dsa):  press ENTER
Enter passphrase (empty for no passphrase): ********
Enter same passphrase again: ********
Your identification has been saved in /home/username/.ssh/id_dsa.
Your public key has been saved in /home/username/.ssh/id_dsa.pub.
The key fingerprint is:
14:ba:06:98:a8:98:ad:27:b5:ce:55:85:ec:64:37:19 username@shell.isp.com

上面示例中,执行ssh-keygen命令以后,会出现第一个问题,询问密钥保存的文件名,默认是~/.ssh/id_dsa文件,这个是私钥的文件名,对应的公钥文件~/.ssh/id_dsa.pub是自动生成的。用户的密钥一般都放在主目录的.ssh目录里面。

如果选择rsa算法,生成的密钥文件默认就会是~/.ssh/id_rsa(私钥)和~/.ssh/id_rsa.pub(公钥)。

接着,就会是第二个问题,询问是否要为私钥文件设定密码保护(passphrase)。这样的话,即使入侵者拿到私钥,还是需要破解密码。如果为了方便,不想设定密码保护,可以直接按回车键,密码就会为空。后面还会让你再输入一次密码,两次输入必须一致。注意,这里“密码”的英文单词是 passphrase,这是为了避免与 Linux 账户的密码单词 password 混淆,表示这不是用户系统账户的密码。

最后,就会生成私钥和公钥,屏幕上还会给出公钥的指纹,以及当前的用户名和主机名作为注释,用来识别密钥的来源。

公钥文件和私钥文件都是文本文件,可以用文本编辑器看一下它们的内容。公钥文件的内容类似下面这样。

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com

上面示例中,末尾的username@shell.isp.com是公钥的注释,用来识别不同的公钥,表示这是哪台主机(shell.isp.com)的哪个用户(username)的公钥,不是必需项。

注意,公钥只有一行。因为它太长了,所以上面分成三行显示。

下面的命令可以列出用户所有的公钥。

$ ls -l ~/.ssh/id_*.pub

生成密钥以后,建议修改它们的权限,防止其他人读取。

$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub

配置项

ssh-keygen的命令行配置项,主要有下面这些。

(1)-b

-b参数指定密钥的二进制位数。这个参数值越大,密钥就越不容易破解,但是加密解密的计算开销也会加大。

一般来说,-b至少应该是1024,更安全一些可以设为2048或者更高。

(2)-C

-C参数可以为密钥文件指定新的注释,格式为username@host

下面命令生成一个4096位 RSA 加密算法的密钥对,并且给出了用户名和主机名。

$ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com"

(3)-f

-f参数指定生成的私钥文件。

$ ssh-keygen -t dsa -f mykey

上面命令会在当前目录生成私钥文件mykey和公钥文件mykey.pub

(4)-F

-F参数检查某个主机名是否在known_hosts文件里面。

$ ssh-keygen -F example.com

(5)-N

-N参数用于指定私钥的密码(passphrase)。

$ ssh-keygen -t dsa -N secretword

(6)-p

-p参数用于重新指定私钥的密码(passphrase)。它与-N的不同之处在于,新密码不在命令中指定,而是执行后再输入。ssh 先要求输入旧密码,然后要求输入两遍新密码。

(7)-R

-R参数将指定的主机公钥指纹移出known_hosts文件。

$ ssh-keygen -R example.com

(8)-t

-t`参数用于指定生成密钥的加密算法,一般为`dsa`或`rsa

手动上传公钥

生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。

OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。

用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。

$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

上面示例中,user@host要替换成你所要登录的用户名和主机名。

注意,authorized_keys文件的权限要设为644,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。

$ chmod 644 ~/.ssh/authorized_keys

只要公钥上传到服务器,下次登录时,OpenSSH 就会自动采用密钥登录,不再提示输入密码。

$ ssh -l username shell.isp.com
Enter passphrase for key '/home/you/.ssh/id_dsa': ************
Last login: Mon Mar 24 02:17:27 2014 from ex.ample.com
shell.isp.com>

上面例子中,SSH 客户端使用私钥之前,会要求用户输入密码(passphrase),用来解开私钥。

ssh-copy-id 命令:自动上传公钥

OpenSSH 自带一个ssh-copy-id命令,可以自动将公钥拷贝到远程服务器的~/.ssh/authorized_keys文件。如果~/.ssh/authorized_keys文件不存在,ssh-copy-id命令会自动创建该文件。

用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器。

$ ssh-copy-id -i key_file user@host

上面命令中,-i参数用来指定公钥文件,user是所要登录的账户名,host是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。

注意,公钥文件可以不指定路径和.pub后缀名,ssh-copy-id会自动在~/.ssh目录里面寻找。

$ ssh-copy-id -i id_rsa user@host

上面命令中,公钥文件会自动匹配到~/.ssh/id_rsa.pub

ssh-copy-id会采用密码登录,系统会提示输入远程服务器的密码。

注意,ssh-copy-id是直接将公钥添加到authorized_keys文件的末尾。如果authorized_keys文件的末尾不是一个换行符,会导致新的公钥添加到前一个公钥的末尾,两个公钥连在一起,使得它们都无法生效。所以,如果authorized_keys文件已经存在,使用ssh-copy-id命令之前,务必保证authorized_keys文件的末尾是换行符(假设该文件已经存在)。


ssh-agent 命令,ssh-add 命令

基本用法

私钥设置了密码以后,每次使用都必须输入密码,有时让人感觉非常麻烦。比如,连续使用scp命令远程拷贝文件时,每次都要求输入密码。

ssh-agent命令就是为了解决这个问题而设计的,它让用户在整个 Bash 对话(session)之中,只在第一次使用 SSH 命令时输入密码,然后将私钥保存在内存中,后面都不需要再输入私钥的密码了。

第一步,使用下面的命令新建一次命令行对话。

$ ssh-agent bash

上面命令中,如果你使用的命令行环境不是 Bash,可以用其他的 Shell 命令代替。比如zshfish

如果想在当前对话启用ssh-agent,可以使用下面的命令。

$ eval `ssh-agent`

上面命令中,ssh-agent会先自动在后台运行,并将需要设置的环境变量输出在屏幕上,类似下面这样。

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-22841-agent; export SSH_AUTH_SOCK;
SSH_AGENT_PID=22842; export SSH_AGENT_PID;
echo Agent pid 22842;

eval命令的作用,就是运行上面的ssh-agent命令的输出,设置环境变量。

第二步,在新建的 Shell 对话里面,使用ssh-add命令添加默认的私钥(比如~/.ssh/id_rsa,或~/.ssh/id_dsa,或~/.ssh/id_ecdsa,或~/.ssh/id_ed25519)。

$ ssh-add
Enter passphrase for /home/you/.ssh/id_dsa: ********
Identity added: /home/you/.ssh/id_dsa (/home/you/.ssh/id_dsa)

上面例子中,添加私钥时,会要求输入密码。以后,在这个对话里面再使用密钥时,就不需要输入私钥的密码了,因为私钥已经加载到内存里面了。

如果添加的不是默认私钥,ssh-add命令需要显式指定私钥文件。

$ ssh-add my-other-key-file

上面的命令中,my-other-key-file就是用户指定的私钥文件。

第三步,使用 ssh 命令正常登录远程服务器。

$ ssh remoteHost

上面命令中,remoteHost是远程服务器的地址,ssh 使用的是默认的私钥。这时如果私钥设有密码,ssh 将不再询问密码,而是直接取出内存里面的私钥。

如果要使用其他私钥登录服务器,需要使用 ssh 命令的-i参数指定私钥文件。

$ ssh –i OpenSSHPrivateKey remoteHost

最后,如果要退出ssh-agent,可以直接退出子 Shell(按下 Ctrl + d),也可以使用下面的命令。

$ ssh-agent -k

ssh-add命令

ssh-add命令用来将私钥加入ssh-agent,它有如下的参数。

(1)-d

-d参数从内存中删除指定的私钥。

$ ssh-add -d name-of-key-file

(2)-D

-D参数从内存中删除所有已经添加的私钥。

$ ssh-add -D

(3)-l

-l参数列出所有已经添加的私钥。

$ ssh-add -l

关闭密码登录

为了安全性,启用密钥登录之后,最好关闭服务器的密码登录。

对于 OpenSSH,具体方法就是打开服务器 sshd 的配置文件/etc/ssh/sshd_config,将PasswordAuthentication这一项设为no

PasswordAuthentication no

修改配置文件以后,不要忘了重新启动 sshd,否则不会生效。


SSH 服务器

简介

SSH 的架构是服务器/客户端模式,两端运行的软件是不一样的。OpenSSH 的客户端软件是 ssh,服务器软件是 sshd。本章介绍 sshd 的各种知识。

如果没有安装 sshd,可以用下面的命令安装。

# Debian
$ sudo aptitude install openssh-server

# Red Hat
$ sudo yum install openssh-server

一般来说,sshd 安装后会跟着系统一起启动。如果当前 sshd 没有启动,可以用下面的命令启动。

$ sshd

上面的命令运行后,如果提示“sshd re-exec requires execution with an absolute path”,就需要使用绝对路径来启动。这是为了防止有人出于各种目的,放置同名软件在$PATH变量指向的目录中,代替真正的 sshd。

# Centos、Ubuntu、OS X
$ /usr/sbin/sshd

上面的命令运行以后,sshd 自动进入后台,所以命令后面不需要加上&

除了直接运行可执行文件,也可以通过 Systemd 启动 sshd。

# 启动
$ sudo systemctl start sshd.service

# 停止
$ sudo systemctl stop sshd.service

# 重启
$ sudo systemctl restart sshd.service

下面的命令让 sshd 在计算机下次启动时自动运行。

$ sudo systemctl enable sshd.service

sshd 配置文件

sshd 的配置文件在/etc/ssh目录,主配置文件是sshd_config,此外还有一些安装时生成的密钥。

  • /etc/ssh/sshd_config:配置文件
  • /etc/ssh/ssh_host_ecdsa_key:ECDSA 私钥。
  • /etc/ssh/ssh_host_ecdsa_key.pub:ECDSA 公钥。
  • /etc/ssh/ssh_host_key:用于 SSH 1 协议版本的 RSA 私钥。
  • /etc/ssh/ssh_host_key.pub:用于 SSH 1 协议版本的 RSA 公钥。
  • /etc/ssh/ssh_host_rsa_key:用于 SSH 2 协议版本的 RSA 私钥。
  • /etc/ssh/ssh_host_rsa_key.pub:用于 SSH 2 协议版本的 RSA 公钥。
  • /etc/pam.d/sshd:PAM 配置文件。

注意,如果重装 sshd,上面这些密钥都会重新生成,导致客户端重新 ssh 连接服务器时,会跳出警告,拒绝连接。为了避免这种情况,可以在重装 sshd 时,先备份/etc/ssh目录,重装后再恢复这个目录。

配置文件sshd_config的格式是,每个命令占据一行。每行都是配置项和对应的值,配置项的大小写不敏感,与值之间使用空格分隔。

Port 2034

上面的配置命令指定,配置项Port的值是2034Port写成port也可。

配置文件还有另一种格式,就是配置项与值之间有一个等号,等号前后的空格可选。

Port = 2034

配置文件里面,#开头的行表示注释。

# 这是一行注释

注意,注释只能放在一行的开头,不能放在一行的结尾。

Port 2034 # 此处不允许注释

上面的写法是错误的。

另外,空行等同于注释。

sshd 启动时会自动读取默认的配置文件。如果希望使用其他的配置文件,可以用 sshd 命令的-f参数指定。

$ sshd -f /usr/local/ssh/my_config

上面的命令指定 sshd 使用另一个配置文件my_config

修改配置文件以后,可以用 sshd 命令的-t(test)检查有没有语法错误。

$ sshd -t

配置文件修改以后,并不会自动生效,必须重新启动 sshd。

$ sudo systemctl restart sshd.service

sshd 密钥

sshd 有自己的一对或多对密钥。它使用密钥向客户端证明自己的身份。所有密钥都是公钥和私钥成对出现,公钥的文件名一般是私钥文件名加上后缀.pub

DSA 格式的密钥文件默认为/etc/ssh/ssh_host_dsa_key(公钥为ssh_host_dsa_key.pub),RSA 格式的密钥为/etc/ssh/ssh_host_rsa_key(公钥为ssh_host_rsa_key.pub)。如果需要支持 SSH 1 协议,则必须有密钥/etc/ssh/ssh_host_key

如果密钥不是默认文件,那么可以通过配置文件sshd_configHostKey配置项指定。默认密钥的HostKey设置如下。

# HostKey for protocol version 1
# HostKey /etc/ssh/ssh_host_key

# HostKeys for protocol version 2
# HostKey /etc/ssh/ssh_host_rsa_key
# HostKey /etc/ssh/ssh_host_dsa_ke

上面命令前面的#表示这些行都是注释,因为这是默认值,有没有这几行都一样。

如果要修改密钥,就要去掉行首的#,指定其他密钥。

HostKey /usr/local/ssh/my_dsa_key
HostKey /usr/local/ssh/my_rsa_key
HostKey /usr/local/ssh/my_old_ssh1_key

sshd 配置项

以下是/etc/ssh/sshd_config文件里面的配置项。

AcceptEnv

AcceptEnv指定允许接受客户端通过SendEnv命令发来的哪些环境变量,即允许客户端设置服务器的环境变量清单,变量名之间使用空格分隔(AcceptEnv PATH TERM)。

AllowGroups

AllowGroups指定允许登录的用户组(AllowGroups groupName,多个组之间用空格分隔。如果不使用该项,则允许所有用户组登录。

AllowUsers

AllowUsers指定允许登录的用户,用户名之间使用空格分隔(AllowUsers user1 user2),也可以使用多行AllowUsers命令指定,用户名支持使用通配符。如果不使用该项,则允许所有用户登录。该项也可以使用用户名@域名的格式(比如AllowUsers jones@example.com)。

AllowTcpForwarding

AllowTcpForwarding指定是否允许端口转发,默认值为yesAllowTcpForwarding yes),local表示只允许本地端口转发,remote表示只允许远程端口转发。

AuthorizedKeysFile

AuthorizedKeysFile指定储存用户公钥的目录,默认是用户主目录的ssh/authorized_keys目录(AuthorizedKeysFile .ssh/authorized_keys)。

Banner

Banner指定用户登录后,sshd 向其展示的信息文件(Banner /usr/local/etc/warning.txt),默认不展示任何内容。

ChallengeResponseAuthentication

ChallengeResponseAuthentication指定是否使用“键盘交互”身份验证方案,默认值为yesChallengeResponseAuthentication yes)。

从理论上讲,“键盘交互”身份验证方案可以向用户询问多重问题,但是实践中,通常仅询问用户密码。如果要完全禁用基于密码的身份验证,请将PasswordAuthenticationChallengeResponseAuthentication都设置为no

Ciphers

Ciphers指定 sshd 可以接受的加密算法(Ciphers 3des-cbc),多个算法之间使用逗号分隔。

ClientAliveCountMax

ClientAliveCountMax指定建立连接后,客户端失去响应时,服务器尝试连接的次数(ClientAliveCountMax 8)。

ClientAliveInterval

ClientAliveInterval指定允许客户端发呆的时间,单位为秒(ClientAliveInterval 180)。如果这段时间里面,客户端没有发送任何信号,SSH 连接将关闭。

Compression

Compression指定客户端与服务器之间的数据传输是否压缩。默认值为yesCompression yes

DenyGroups

DenyGroups指定不允许登录的用户组(DenyGroups groupName)。

DenyUsers

DenyUsers指定不允许登录的用户(DenyUsers user1),用户名之间使用空格分隔,也可以使用多行DenyUsers命令指定。

FascistLogging

SSH 1 版本专用,指定日志输出全部 Debug 信息(FascistLogging yes)。

HostKey

HostKey指定 sshd 服务器的密钥,详见前文。

KeyRegenerationInterval

KeyRegenerationInterval指定 SSH 1 版本的密钥重新生成时间间隔,单位为秒,默认是3600秒(KeyRegenerationInterval 3600)。

ListenAddress

ListenAddress指定 sshd 监听的本机 IP 地址,即 sshd 启用的 IP 地址,默认是 0.0.0.0(ListenAddress 0.0.0.0)表示在本机所有网络接口启用。可以改成只在某个网络接口启用(比如ListenAddress 192.168.10.23),也可以指定某个域名启用(比如ListenAddress server.example.com)。

如果要监听多个指定的 IP 地址,可以使用多行ListenAddress命令。

ListenAddress 172.16.1.1
ListenAddress 192.168.0.1

LoginGraceTime

LoginGraceTime指定允许客户端登录时发呆的最长时间,比如用户迟迟不输入密码,连接就会自动断开,单位为秒(LoginGraceTime 60)。如果设为0,就表示没有限制。

LogLevel

LogLevel指定日志的详细程度,可能的值依次为QUIETFATALERRORINFOVERBOSEDEBUGDEBUG1DEBUG2DEBUG3,默认为INFOLogLevel INFO)。

MACs

MACs指定sshd 可以接受的数据校验算法(MACs hmac-sha1),多个算法之间使用逗号分隔。

MaxAuthTries

MaxAuthTries指定允许 SSH 登录的最大尝试次数(MaxAuthTries 3),如果密码输入错误达到指定次数,SSH 连接将关闭。

MaxStartups

MaxStartups指定允许同时并发的 SSH 连接数量(MaxStartups)。如果设为0,就表示没有限制。

这个属性也可以设为A:B:C的形式,比如MaxStartups 10:50:20,表示如果达到10个并发连接,后面的连接将有50%的概率被拒绝;如果达到20个并发连接,则后面的连接将100%被拒绝。

PasswordAuthentication

PasswordAuthentication指定是否允许密码登录,默认值为yesPasswordAuthentication yes),建议改成no(禁止密码登录,只允许密钥登录)。

PermitEmptyPasswords

PermitEmptyPasswords指定是否允许空密码登录,即用户的密码是否可以为空,默认为yesPermitEmptyPasswords yes),建议改成no(禁止无密码登录)。

PermitRootLogin

PermitRootLogin指定是否允许根用户登录,默认为yesPermitRootLogin yes),建议改成no(禁止根用户登录)。

还有一种写法是写成prohibit-password,表示 root 用户不能用密码登录,但是可以用密钥登录。

PermitRootLogin prohibit-password

PermitUserEnvironment

PermitUserEnvironment指定是否允许 sshd 加载客户端的~/.ssh/environment文件和~/.ssh/authorized_keys文件里面的environment= options环境变量设置。默认值为noPermitUserEnvironment no)。

Port

Port指定 sshd 监听的端口,即客户端连接的端口,默认是22(Port 22)。出于安全考虑,可以改掉这个端口(比如Port 8822)。

配置文件可以使用多个Port命令,同时监听多个端口。

Port 22
Port 80
Port 443
Port 8080

上面的示例表示同时监听4个端口。

PrintMotd

PrintMotd指定用户登录后,是否向其展示系统的 motd(Message of the day)的信息文件/etc/motd。该文件用于通知所有用户一些重要事项,比如系统维护时间、安全问题等等。默认值为yesPrintMotd yes),由于 Shell 一般会展示这个信息文件,所以这里可以改为no

PrintLastLog

PrintLastLog指定是否打印上一次用户登录时间,默认值为yesPrintLastLog yes)。

Protocol

Protocol指定 sshd 使用的协议。Protocol 1表示使用 SSH 1 协议,建议改成Protocol 2(使用 SSH 2 协议)。Protocol 2,1表示同时支持两个版本的协议。

PubKeyAuthentication

PubKeyAuthentication指定是否允许公钥登录,默认值为yesPubKeyAuthentication yes)。

QuietMode

SSH 1 版本专用,指定日志只输出致命的错误信息(QuietMode yes)。

RSAAuthentication

RSAAuthentication指定允许 RSA 认证,默认值为yesRSAAuthentication yes)。

ServerKeyBits

ServerKeyBits指定 SSH 1 版本的密钥重新生成时的位数,默认是768(ServerKeyBits 768)。

StrictModes

StrictModes指定 sshd 是否检查用户的一些重要文件和目录的权限。默认为yesStrictModes yes),即对于用户的 SSH 配置文件、密钥文件和所在目录,SSH 要求拥有者必须是根用户或用户本人,用户组和其他人的写权限必须关闭。

SyslogFacility

SyslogFacility指定 Syslog 如何处理 sshd 的日志,默认是 Auth(SyslogFacility AUTH)。

TCPKeepAlive

TCPKeepAlive指定打开 sshd 跟客户端 TCP 连接的 keepalive 参数(TCPKeepAlive yes)。

UseDNS

UseDNS指定用户 SSH 登录一个域名时,服务器是否使用 DNS,确认该域名对应的 IP 地址包含本机(UseDNS yes)。打开该选项意义不大,而且如果 DNS 更新不及时,还有可能误判,建议关闭。

UseLogin

UseLogin指定用户认证内部是否使用/usr/bin/login替代 SSH 工具,默认为noUseLogin no)。

UserPrivilegeSeparation

UserPrivilegeSeparation指定用户认证通过以后,使用另一个子线程处理用户权限相关的操作,这样有利于提高安全性。默认值为yesUsePrivilegeSeparation yes)。

VerboseMode

SSH 2 版本专用,指定日志输出详细的 Debug 信息(VerboseMode yes)。

X11Forwarding

X11Forwarding指定是否打开 X window 的转发,默认值为 no(X11Forwarding no)。

修改配置文件以后,可以使用下面的命令验证,配置文件是否有语法错误。

$ sshd -t

新的配置文件生效,必须重启 sshd。

$ sudo systemctl restart sshd

sshd 的命令行配置项

sshd 命令有一些配置项。这些配置项在调用时指定,可以覆盖配置文件的设置。

(1)-d

-d参数用于显示 debug 信息。

$ sshd -d

(2)-D

-D参数指定 sshd 不作为后台守护进程运行。

$ sshd -D

(3)-e

-e参数将 sshd 写入系统日志 syslog 的内容导向标准错误(standard error)。

(4)-f

-f参数指定配置文件的位置。

(5)-h

-h参数用于指定密钥。

$ sshd -h /usr/local/ssh/my_rsa_key

(6)-o

-o参数指定配置文件的一个配置项和对应的值。

$ sshd -o "Port 2034"

配置项和对应值之间,可以使用等号。

$ sshd -o "Port = 2034"

如果省略等号前后的空格,也可以不使用引号。

$ sshd -o Port=2034

-o参数可以多个一起使用,用来指定多个配置关键字。

(7)-p

-p参数指定 sshd 的服务端口。

$ sshd -p 2034

上面命令指定 sshd 在2034端口启动。

-p参数可以指定多个端口。

$ sshd -p 2222 -p 3333

(8)-t

-t参数检查配置文件的语法是否正确。

SSH 端口转发

简介

SSH 除了登录服务器,还有一大用途,就是作为加密通信的中介,充当两台服务器之间的通信加密跳板,使得原本不加密的通信变成加密通信。这个功能称为端口转发(port forwarding),又称 SSH 隧道(tunnel)。

端口转发有两个主要作用:

(1)将不加密的数据放在 SSH 安全连接里面传输,使得原本不安全的网络服务增加了安全性,比如通过端口转发访问 Telnet、FTP 等明文服务,数据传输就都会加密。

(2)作为数据通信的加密跳板,绕过网络防火墙。

端口转发有三种使用方法:动态转发,本地转发,远程转发。下面逐一介绍。

动态转发

动态转发指的是,本机与 SSH 服务器之间创建了一个加密连接,然后本机内部针对某个端口的通信,都通过这个加密连接转发。它的一个使用场景就是,访问所有外部网站,都通过 SSH 转发。

动态转发需要把本地端口绑定到 SSH 服务器。至于 SSH 服务器要去访问哪一个网站,完全是动态的,取决于原始通信,所以叫做动态转发。

$ ssh -D local-port tunnel-host -N

上面命令中,-D表示动态转发,local-port是本地端口,tunnel-host是 SSH 服务器,-N表示这个 SSH 连接只进行端口转发,不登录远程 Shell,不能执行远程命令,只能充当隧道。

举例来说,如果本地端口是2121,那么动态转发的命令就是下面这样。

$ ssh -D 2121 tunnel-host -N

注意,这种转发采用了 SOCKS5 协议。访问外部网站时,需要把 HTTP 请求转成 SOCKS5 协议,才能把本地端口的请求转发出去。

下面是 SSH 隧道建立后的一个使用实例。

$ curl -x socks5://localhost:2121 http://www.example.com

上面命令中,curl 的-x参数指定代理服务器,即通过 SOCKS5 协议的本地2121端口,访问http://www.example.com

如果经常使用动态转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config)。

DynamicForward tunnel-host:local-port

本地转发

本地转发(local forwarding)指的是,SSH 服务器作为中介的跳板机,建立本地计算机与特定目标网站之间的加密连接。本地转发是在本地计算机的 SSH 客户端建立的转发规则。

它会指定一个本地端口(local-port),所有发向那个端口的请求,都会转发到 SSH 跳板机(tunnel-host),然后 SSH 跳板机作为中介,将收到的请求发到目标服务器(target-host)的目标端口(target-port)。

$ ssh -L local-port:target-host:target-port tunnel-host

上面命令中,-L参数表示本地转发,local-port是本地端口,target-host是你想要访问的目标服务器,target-port是目标服务器的端口,tunnel-host是 SSH 跳板机。

举例来说,现在有一台 SSH 跳板机tunnel-host,我们想要通过这台机器,在本地2121端口与目标网站www.example.com的80端口之间建立 SSH 隧道,就可以写成下面这样。

$ ssh -L 2121:www.example.com:80 tunnel-host -N

然后,访问本机的2121端口,就是访问www.example.com的80端口。

$ curl http://localhost:2121

注意,本地端口转发采用 HTTP 协议,不用转成 SOCKS5 协议。

另一个例子是加密访问邮件获取协议 POP3。

$ ssh -L 1100:mail.example.com:110 mail.example.com

上面命令将本机的1100端口,绑定邮件服务器mail.example.com的110端口(POP3 协议的默认端口)。端口转发建立以后,POP3 邮件客户端只需要访问本机的1100端口,请求就会通过 SSH 跳板机(这里是mail.example.com),自动转发到mail.example.com的110端口。

上面这种情况有一个前提条件,就是mail.example.com必须运行 SSH 服务器。否则,就必须通过另一台 SSH 服务器中介,执行的命令要改成下面这样。

$ ssh -L 1100:mail.example.com:110 other.example.com

上面命令中,本机的1100端口还是绑定mail.example.com的110端口,但是由于mail.example.com没有运行 SSH 服务器,所以必须通过other.example.com中介。本机的 POP3 请求通过1100端口,先发给other.example.com的22端口(sshd 默认端口),再由后者转给mail.example.com,得到数据以后再原路返回。

注意,采用上面的中介方式,只有本机到other.example.com的这一段是加密的,other.example.commail.example.com的这一段并不加密。

这个命令最好加上-N参数,表示不在 SSH 跳板机执行远程命令,让 SSH 只充当隧道。另外还有一个-f参数表示 SSH 连接在后台运行。

如果经常使用本地转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config)。

Host test.example.com
LocalForward client-IP:client-port server-IP:server-port

远程转发

远程端口指的是在远程 SSH 服务器建立的转发规则。

这种场景比较特殊,主要针对内网的情况。本地计算机在外网,SSH 跳板机和目标服务器都在内网,而且本地计算机无法访问内网之中的 SSH 跳板机,但是 SSH 跳板机可以访问本机计算机。

由于本机无法访问内网 SSH 跳板机,就无法从外网发起 SSH 隧道,建立端口转发。必须反过来,从 SSH 跳板机发起隧道,建立端口转发,这时就形成了远程端口转发。

$ ssh -R local-port:target-host:target-port -N local

上面的命令,首先需要注意,不是在本机执行的,而是在 SSH 跳板机执行的,从跳板机去连接本地计算机。-R参数表示远程端口转发,local-port是本地计算机的端口,target-hosttarget-port是目标服务器及其端口,local是本地计算机。

显然,远程端口转发要求本地计算机也安装了 SSH 服务器,这样才能接受 SSH 跳板机的远程登录。

比如,跳板机执行下面的命令,绑定本地计算机的2121端口,去访问www.example.com:80

$ ssh -R 2121:www.example.com:80 local -N

执行上面的命令以后,跳板机到本地计算机的隧道已经建立了。然后,就可以从本机访问目标服务器了,即在本机执行下面的命令。

$ curl http://localhost:2121

执行上面的命令以后,命令就会输出服务器www.example.com的80端口返回的内容。

如果经常执行远程端口转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config)。

Host test.example.com
RemoteForward local-IP:local-port target-ip:target-port

实例

下面看两个端口转发的实例。

简易VPN

VPN 用来在外网与内网之间建立一条加密通道。内网的服务器不能从外网直接访问,必须通过一个跳板机,如果本机可以访问跳板机,就可以使用 SSH 本地转发,简单实现一个 VPN。

$ ssh -L 2080:corp-server:80 -L 2443:corp-server:443 tunnel-host -N

上面命令通过 SSH 跳板机,将本机的2080端口绑定内网服务器的80端口,本机的2443端口绑定内网服务器的443端口。

两极跳板

端口转发可以有多级,比如新建两个 SSH 隧道,第一个隧道转发给第二个隧道,第二个隧道才能访问目标服务器。

首先,在本机新建第一级隧道。

$ ssh -L 7999:localhost:2999 tunnel1-host

上面命令在本地7999端口与tunnel1-host之间建立一条隧道,隧道的出口是tunnel1-hostlocalhost:2999,也就是tunnel1-host收到本机的请求以后,转发给自己的2999端口。

然后,在第一台跳板机(tunnel1-host)执行下面的命令,新建第二级隧道。

$ ssh -L 2999:target-host:7999 tunnel2-host -N

上面命令将第一台跳板机tunnel1-host2999端口,通过第二台跳板机tunnel2-host,连接到目标服务器target-host7999端口。

最终效果就是,访问本机的7999端口,就会转发到target-host7999端口。

参考链接

posted @ 2022-05-31 07:58  edolf  阅读(921)  评论(0编辑  收藏  举报