SSH基础使用
SSH基础使用
SSH 是什么
历史上,网络主机之间的通信是不加密的,属于明文通信。这使得通信很不安全,一个典型的例子就是服务器登录。登录远程服务器的时候,需要将用户输入的密码传给服务器,如果这个过程是明文通信,就意味着传递过程中,线路经过的中间计算机都能看到密码,这是很可怕的。
SSH 就是为了解决这个问题而诞生的,它能够加密计算机之间的通信,保证不被窃听或篡改。它还能对操作者进行认证(authentication)和授权(authorization)。明文的网络协议可以套用在它里面,从而实现加密
SSH 架构
SH 的软件架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH 软件分成两个部分:向服务器发出请求的部分,称为客户端(client),OpenSSH 的实现为 ssh;接收客户端发出的请求的部分,称为服务器(server),OpenSSH 的实现为 sshd
OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp)
SSH 客户端
OpenSSH 的客户端是二进制程序 ssh。它在 Linux/Unix 系统的位置是 /usr/local/bin/ssh
Linux 系统一般都自带 ssh,如果没有就需要安装
1 |
|
安装以后,可以使用-V参数输出版本号,查看一下是否安装成功。
1 |
|
ssh 登录服务器的命令
1 |
|
hostname是主机名,它可以是域名,也可能是 IP 地址或局域网内部的主机名。不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。如果要指定用户名,可以采用下面的语法
1 |
|
用户名也可以使用ssh的-l参数指定,这样的话,用户名和主机名就不用写在一起了。
1 |
|
ssh 默认连接服务器的22端口,-p参数可以指定其他端口。
1 |
|
执行远程命令
SSH 登录成功后,用户就进入了远程主机的命令行环境,所看到的提示符,就是远程主机的提示符。这时,你就可以输入想要在远程主机执行的命令
另一种执行远程命令的方法,是将命令直接写在ssh命令的后面
1 |
|
采用这种语法执行命令时,ssh 客户端不会提供互动式的 Shell 环境,而是直接将远程命令的执行结果输出在命令行。但是,有些命令需要互动式的 Shell 环境,这时就要使用-t参数。
1 |
|
加密参数
SSH 连接的握手阶段,客户端必须跟服务端约定加密参数集(cipher suite)。
加密参数集包含了若干不同的加密参数,它们之间使用下划线连接在一起,下面是一个例子。
1 |
|
- TLS:加密通信协议
- RSA:密钥交换算法
- AES:加密算法
- 128:加密算法的强度
- CBC:加密算法的模式
- SHA:数字签名的 Hash 函数
ssh 命令行配置项
ssh 命令有很多配置项,修改它的默认行为。
-c 参数指定加密算法。
1 |
|
上面命令指定使用加密算法blowfish或3des。
-C 参数表示压缩数据传输。
1 |
|
-D 参数指定本机的 Socks 监听端口,该端口收到的请求,都将转发到远程的 SSH 主机,又称动态端口转发
1 |
|
-f 参数表示 SSH 连接在后台运行。
-F 参数指定配置文件。
1 |
|
-i 参数用于指定私钥,意为“identity_file”,默认值为/.ssh/id_dsa(DSA 算法)和/.ssh/id_rsa(RSA 算法)。注意,对应的公钥必须存放到服务器。
1 |
|
-l 参数指定远程登录的账户名。
1 |
|
-L 参数设置本地端口转发。
1 |
|
上面命令中,所有发向本地9999端口的请求,都会经过remoteserver发往 targetServer 的 80 端口,这就相当于直接连上了 targetServer 的 80 端口。
-m 参数指定校验数据完整性的算法(message authentication code,简称 MAC)。
1 |
|
上面命令指定数据校验算法为hmac-sha1或hmac-md5。
-N 参数用于端口转发,表示建立的 SSH 只用于端口转发,不能执行远程命令,这样可以提供安全性
-o 参数用来指定一个配置命令。
1 |
|
使用等号时,配置命令可以不用写在引号里面,但是等号前后不能有空格。
1 |
|
-p 参数指定 SSH 客户端连接的服务器端口。
1 |
|
-q 参数表示安静模式(quiet),不向用户输出任何警告信息。
1 |
|
-R 参数指定远程端口转发
1 |
|
上面命令需在跳板服务器执行,指定本地计算机local监听自己的 9999 端口,所有发向这个端口的请求,都会转向 targetServer 的 902 端口。
-t 参数在 ssh 直接运行远端命令时,提供一个互动式 Shell。
1 |
|
-v 参数显示详细信息。
1 |
|
-v可以重复多次,表示信息的详细程度,比如-vv和-vvv。
1 |
|
-V参 数输出 ssh 客户端的版本。
1 |
|
-X 参数表示打开 X 窗口转发。
1 |
|
-4指定使用 IPv4 协议,这是默认值。
-6指定使用 IPv6 协议。
1 |
|
客户端配置文件
SSH 客户端的全局配置文件是/etc/ssh/ssh_config,用户个人的配置文件在~/.ssh/config,优先级高于全局配置文件
- ~/.ssh/id_ecdsa:用户的 ECDSA 私钥。
- ~/.ssh/id_ecdsa.pub:用户的 ECDSA 公钥。
- ~/.ssh/id_rsa:用于 SSH 协议版本2 的 RSA 私钥。
- ~/.ssh/id_rsa.pub:用于SSH 协议版本2 的 RSA 公钥。
- ~/.ssh/identity:用于 SSH 协议版本1 的 RSA 私钥。
- ~/.ssh/identity.pub:用于 SSH 协议版本1 的 RSA 公钥。
- ~/.ssh/known_hosts:包含 SSH 服务器的公钥指纹
用户个人的配置文件~/.ssh/config,可以按照不同服务器,列出各自的连接参数,从而不必每一次登录都输入重复的参数
1 |
|
登录remote.example.com时,只要执行ssh remoteserver命令,就会自动套用 config 文件里面指定的参数
1 |
|
配置命令的语法
ssh 客户端配置文件的每一行,就是一个配置命令。配置命令与对应的值之间,可以使用空格,也可以使用等号。
1 |
|
主要配置命令
- AddressFamily inet:表示只使用 IPv4 协议。如果设为inet6,表示只使用 IPv6 协议。
- BindAddress 192.168.10.235:指定本机的 IP 地址(如果本机有多个 IP 地址)。
- CheckHostIP yes:检查 SSH 服务器的 IP 地址是否跟公钥数据库吻合。
- Ciphers blowfish,3des:指定加密算法。
- Compression yes:是否压缩传输信号。
- ConnectionAttempts 10:客户端进行连接时,最大的尝试次数。
- ConnectTimeout 60:客户端进行连接时,服务器在指定秒数内没有回复,则中断连接尝试。
- DynamicForward 1080:指定动态转发端口。
- GlobalKnownHostsFile /users/smith/.ssh/my_global_hosts_file:指定全局的公钥数据库文件的位置。
- Host server.example.com:指定连接的域名或 IP 地址,也可以是别名,支持通配符。Host命令后面的所有配置,都是针对该主机的,直到下一个Host命令为止。
- HostKeyAlgorithms ssh-dss,ssh-rsa:指定密钥算法,优先级从高到低排列。
- HostName myserver.example.com:在Host命令使用别名的情况下,HostName指定域名或 IP 地址。
- IdentityFile keyfile:指定私钥文件。
- LocalForward 2001 localhost:143:指定本地端口转发。
- LogLevel QUIET:指定日志详细程度。如果设为QUIET,将不输出大部分的警告和提示。
- MACs hmac-sha1,hmac-md5:指定数据校验算法。
- NumberOfPasswordPrompts 2:密码登录时,用户输错密码的最大尝试次数。
- PasswordAuthentication no:指定是否支持密码登录。不过,这里只是客户端禁止,真正的禁止需要在 SSH 服务器设置。
- Port 2035:指定客户端连接的 SSH 服务器端口。
- PreferredAuthentications publickey,hostbased,password:指定各种登录方法的优先级。
- Protocol 2:支持的 SSH 协议版本,多个版本之间使用逗号分隔。
- PubKeyAuthentication yes:是否支持密钥登录。这里只是客户端设置,还需要在 SSH 服务器进行相应设置。
- RemoteForward 2001 server:143:指定远程端口转发。
- SendEnv COLOR:SSH 客户端向服务器发送的环境变量名,多个环境变量之间使用空格分隔。环境变量的值从客户端当前环境中拷贝。
- ServerAliveCountMax 3:如果没有收到服务器的回应,客户端连续发送多少次keepalive信号,才断开连接。该项默认值为3。
- ServerAliveInterval 300:客户端建立连接后,如果在给定秒数内,没有收到服务器发来的消息,客户端向服务器发送keepalive消息。如果不希望客户端发送,这一项设为0。
- StrictHostKeyChecking yes:yes表示严格检查,服务器公钥为未知或发生变化,则拒绝连接。no表示如果服务器公钥未知,则加入客户端公钥数据库,如果公钥发生变化,不改变客户端公钥数据库,输出一条警告,依然允许连接继续进行。ask(默认值)表示询问用户是否继续进行。
- TCPKeepAlive yes:客户端是否定期向服务器发送keepalive信息。
- User userName:指定远程登录的账户名。
- UserKnownHostsFile /users/smith/.ssh/my_local_hosts_file:指定当前用户的known_hosts文件(服务器公钥指纹列表)的位置。
- VerifyHostKeyDNS yes:是否通过检查 SSH 服务器的 DNS 记录,确认公钥指纹是否与known_hosts文件保存的一致。
SSH 密钥登录
密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。
SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。
如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。
密钥登录的过程
SSH 密钥登录分为以下的步骤。
预备步骤,客户端通过ssh-keygen生成自己的公钥和私钥。
第一步,手动将客户端的公钥放入远程服务器的指定位置。
第二步,客户端向服务器发起 SSH 登录的请求。
第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。
第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。
ssh-keygen命令:生成密钥
OpenSSH 提供了一个工具程序ssh-keygen命令,用来生成密钥
直接输入ssh-keygen,程序会询问一系列问题,然后生成密钥。
通常做法是使用-t参数,指定密钥的加密算法。
1 |
|
下面的命令可以列出用户所有的公钥。
1 |
|
生成密钥以后,建议修改它们的权限,防止其他人读取。
1 |
|
ssh-keygen的命令行配置项
主要有下面这些。
-b 参数指定密钥的二进制位数。这个参数值越大,密钥就越不容易破解,但是加密解密的计算开销也会加大。
一般来说,-b至少应该是1024,更安全一些可以设为2048或者更高。
-C 参数可以为密钥文件指定新的注释,格式为username@host。
下面命令生成一个4096位 RSA 加密算法的密钥对,并且给出了用户名和主机名。
1 |
|
-f 参数指定生成的私钥文件。
1 |
|
上面命令会在当前目录生成私钥文件mykey和公钥文件mykey.pub。
-F 参数检查某个主机名是否在known_hosts文件里面。
1 |
|
-N 参数用于指定私钥的密码(passphrase)。
1 |
|
-p 参数用于重新指定私钥的密码(passphrase)。它与-N的不同之处在于,新密码不在命令中指定,而是执行后再输入。ssh 先要求输入旧密码,然后要求输入两遍新密码。
-R 参数将指定的主机公钥指纹移出known_hosts文件。
1 |
|
-t 参数用于指定生成密钥的加密算法,一般为dsa或rsa
手动上传公钥.
生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。
OpenSSH 规定,用户公钥保存在服务器的/.ssh/authorized_keys文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的/.ssh/authorized_keys文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建
用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。
1 |
|
注意,authorized_keys文件的权限要设为644,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。
1 |
|
ssh-copy-id 命令:自动上传公钥
OpenSSH 自带一个ssh-copy-id命令,可以自动将公钥拷贝到远程服务器的/.ssh/authorized_keys文件。如果/.ssh/authorized_keys文件不存在,ssh-copy-id命令会自动创建该文件
用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器。
1 |
|
上面命令中,-i参数用来指定公钥文件,user是所要登录的账户名,host是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。
注意,公钥文件可以不指定路径和.pub后缀名,ssh-copy-id会自动在~/.ssh目录里面寻找。
1 |
|
注意,ssh-copy-id是直接将公钥添加到authorized_keys文件的末尾。如果authorized_keys文件的末尾不是一个换行符,会导致新的公钥添加到前一个公钥的末尾,两个公钥连在一起,使得它们都无法生效。所以,如果authorized_keys文件已经存在,使用ssh-copy-id命令之前,务必保证authorized_keys文件的末尾是换行符
ssh-agent 命令,ssh-add 命令
私钥设置了密码以后,每次使用都必须输入密码,有时让人感觉非常麻烦。比如,连续使用scp命令远程拷贝文件时,每次都要求输入密码。
ssh-agent命令就是为了解决这个问题而设计的,它让用户在整个 Bash 对话(session)之中,只在第一次使用 SSH 命令时输入密码,然后将私钥保存在内存中,后面都不需要再输入私钥的密码了
第一步,使用下面的命令新建一次命令行对话。
1 |
|
如果想在当前对话启用ssh-agent,可以使用下面的命令。
1 |
|
eval命令的作用,就是运行上面的ssh-agent命令的输出,设置环境变量。
第二步,在新建的 Shell 对话里面,使用ssh-add命令添加默认的私钥(比如/.ssh/id_rsa,或/.ssh/id_dsa,或/.ssh/id_ecdsa,或/.ssh/id_ed25519)。
1 |
|
上面例子中,添加私钥时,会要求输入密码。以后,在这个对话里面再使用密钥时,就不需要输入私钥的密码了,因为私钥已经加载到内存里面了。
第三步,使用 ssh 命令正常登录远程服务器。
1 |
|
最后,如果要退出ssh-agent,可以直接退出子 Shell(按下 Ctrl + d),也可以使用下面的命令。
1 |
|
ssh-add命令
-d 参数从内存中删除指定的私钥。
1 |
|
-D 参数从内存中删除所有已经添加的私钥。
1 |
|
-l 参数列出所有已经添加的私钥。
1 |
|
为了安全性,启用密钥登录之后,最好关闭服务器的密码登录。
对于 OpenSSH,具体方法就是打开服务器 sshd 的配置文件/etc/ssh/sshd_config,将PasswordAuthentication这一项设为no
SSH 服务器
SSH 的架构是服务器/客户端模式,两端运行的软件是不一样的。OpenSSH 的客户端软件是 ssh,服务器软件是 sshd
如果没有安装 sshd,可以用下面的命令安装。
1 |
|