简介
ssh是一种用于远程登录的一种协议。通过它我们可以进行远程操作来管理远程主机以及传输文件,同时利用ssh隧道我们也可以突破防火墙。
口令登录
$ ssh [-p port] username@hostname
口令登录的原理
- localhost(本地主机)发送一个登录请求;
- remotehost(远程主机)收到请求后会发送自己的public key(公钥)给localhost;
- localhost用remotehost的public key加密自己登录的password(密码)并且发送回去;
- remotehost用自己的private key(私钥)解开发送的password并且核对是否正确,如果正确就允许远程登录。公钥和私钥的详情可以参考阮一峰的数字证书和数字签名;
$ ssh alps@192.168.0.105
The authenticity of host '192.168.0.105 (192.168.0.105)' can't be established.
ECDSA key fingerprint is SHA256:O4DYkK+I3LBeOFsEvb06y+YcSb1wcZi5wXuizETBtg4.
Are you sure you want to continue connecting (yes/no)?yes
这是我们第一次ssh登录的情况,上面提示的意思是只知道remotehost的public key的fingerprint(指纹),是否继续。我们输入yes。
Warning: Permanently added '192.168.0.105' (ECDSA) to the list of known hosts.
alps@192.168.0.105's password:
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-29-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
147 packages can be updated.
52 updates are security updates.
Last login: Tue Jun 21 08:37:04 2016 from 192.168.0.103
可以看到我们输入password后登录成功。根据提示可以看到public key已经被添加到列表,这个列表就放在我们本地的~/.ssh/know_hosts。
$ cat ~/.ssh/known_hosts
|1|4++LGU0cmvp8/jBQgC3wzVyaAGQ=|0ZjnEkO/yvmznPSAjJ8pnHDc8tw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIYW9MlqOuRMr9JYiWlooF9JFC8jZ9b6YbcabG+8wWybMup36OGSGvcyGq4egAz/p6W3k1oHp1QtKYShJmAKvl8=
这样代表我们就信任这个远程主机了,以后登录我们只要输入password,不要输入yes了。每次都要输入password我们还是觉得很麻烦,这个时候我们可以使用公钥加密。
公钥登录
$ ssh-keygen
$ ssh-copy-id username@hostname
公钥加密的原理
- localhost通过ssh-copy-id命令将自己的public key放到remotehost的~/.ssh/authorized_keys;
- remotehost收到登录请求后向localhost发送一个随机字符串;
- localhost用自己的private key将随机字符串加密后发回给remotehost;
- remotehost收到回信后用localhost的public key能够解开这个字符串那么用户身份就确认成功。公钥和私钥的详情可以参考阮一峰的数字证书和数字签名;
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/alps/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alps/.ssh/id_rsa.
Your public key has been saved in /home/alps/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:LUsZyEqSOc9MpPJkJil9myW/P5QudYghtXYKNsL17jM alps@localhost
The key's randomart image is:
+---[RSA 2048]----+
| . |
| o =.... |
|=.@.=o+.. |
|.BoX=B= .+ |
| .oB*.=So. |
| +o=o. |
| ..+.. |
| E.o |
| +.. |
+----[SHA256]-----+
ssh-keygen会为我们在~/.ssh下面生成一对public key和private key,分别保存到~/.ssh/id_rsa.pub和~/.ssh/id_rsa。输入命令后一路回车,私钥设置口令(passphrase)如果你可以自主选择设置。然后我们再输入ssh-copy-id将公钥传递到remotehost上面。
$ ssh-copy-id alps@192.168.0.105
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
alps@192.168.0.105's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'alps@192.168.0.105'"
and check to make sure that only the key(s) you wanted were added.
以后我们ssh登录不再需要输入密码了。
crawler@LocalHost:~$ ssh alps@192.168.0.105
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-29-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
147 packages can be updated.
52 updates are security updates.
Last login: Tue Aug 16 15:02:05 2016 from 192.168.0.103
alps@RemoteHost:~$
实际上ssh-copy-id就是将本地主机的public key复制到远程主机的~/.ssh/authorized_keys里面,这个过程就是下面这一条命令的执行过程。
$ ssh alps@192.168.0.105 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
通过ssh远程传送文件
ex1
$ cd && tar czv src | ssh alps@192.168.0.105 'tar xz'
src/
复制本地~/src/目录下面的所有文件到远程主机的~/src/目录。
ex2
$ ssh alps@192.168.0.105 'tar cz src' | tar xzv
src/
复制远程主机~/src/目录下面的所有文件到本地的当前目录。
ex3
$ ssh alps@192.168.0.105 'ps aux' | grep apache2
root 6596 0.0 0.1 71568 4588 ? Ss 16:09 0:00 /usr/sbin/apache2 -k start
www-data 6599 0.0 0.1 360724 5980 ? Sl 16:09 0:00 /usr/sbin/apache2 -k start
www-data 6600 0.0 0.1 360724 5980 ? Sl 16:09 0:00 /usr/sbin/apache2 -k start
查看远程主机是否运行进程apache2。
ssh隧道(端口转发)
ex1
$ ssh -D 1080 username@hostname
这条命令可以结合Shadowsocks翻墙来理解,我们将经由本地1080端口的数据全部转发到Shadowsocks远程主机,我们如果用Chrome上网的话可以通过SwitchProxy将浏览器的请求转发到本地1080端口,然后通过本地的Shadowsocks-QT5进行代理。
ex2
现在学校机房禁止我们内网主机连接到外网的213.83.72.215进行ftp,但是我们可以借助外网的93.184.216.34,它可以和213.83.72.215:21进行ftp。这个时候我们可以在192.168.0.103和93.184.216.34之间建立一条双向ssh隧道。我们在本地192.168.0.103执行下面这条命令。
$ ssh -N -f -L 2121:213.83.72.215:21 93.184.216.34
-N和-f参数的作用是使命令在后台运行,-L参数一共接受三个值,分别是”本地端口:目标主机:目标主机端口”,它们之间用冒号分隔。这条命令的意思是将通过本地主机2121端口的数据全部通过ssh隧道传送到隧道另外一边的93.184.216.34,通过93.184.216.34我们来连接213.83.72.215:21的端口。
$ ftp 127.0.0.1 2121
在到本地主机执行ftp命令,通过2121端口的数据通过ssh隧道间接传送到192.168.0.100:21了。
ex3
假设现在192.168.0.103是台内网机器,它可以访问外网的93.184.216.34但是外网的机器却不能访问它。现在我们想让192.168.0.103访问无法直接访问的213.83.72.215进行ftp。解决方法是,既然内网的192.168.0.103能够访问93.184.216.34,那么我们就建立这样一条双向ssh隧道,然后我们192.168.0.103使用这条ssh隧道就可以了。
我们首先在93.184.216.34上执行下面命令.
$ ssh -N -f -R 2121:213.83.72.215:21 192.168.0.103
-R参数也是接受三个值,分别是”远程主机端口:目标主机:目标主机端口”。这条命令的意思是让192.168.0.103监听2121端口,然后将所有数据通过93.184.216.34转发到213.83.72.215。对于93.184.216.34来说192.168.0.103是远程主机,所以这也就做远程主机端口转发。
$ ftp localhost:2121
最后我们在192.168.0.103通过ftp连接本地的2121端口就成功ftp到了213.83.72.215:21。
还有一种情况就是我们只有两台机器,93.184.216.34和192.168.0.103,我们将上面这条命令改为。
$ ssh -N -f -R 2121:127.0.0.1:21 192.168.0.103
这个时候就变为在我们在93.184.216.34和192.168.0.103建立一条ssh隧道,然后通过这条隧道在外网93.184.216.34访问192.168.0.103的21端口。
数字签名和数字证书
Internet通信过程中,我们每一个人都有public key(公钥)和private key(私钥),可以在~/.ssh下面查看,其中每个人的public key在Internet中都是公开的,private key只有我们自己知道。为了保证让接收方确认发信方的身份,由certificate authority(证书机构)诞生了digital signature(数字签名)和digital certificate(数字证书)。
我们首先来看一下只有数字签名而没有数字证书的情况:当A向B发送信息的时候A会先用B的public key加密,这份信息只能由B的private key解开。当B给A回信息的时候,首先调用hash函数生成信息的digest(摘要),然后A用自己的private key对digest加密就生成了digital signature。A收到这份回信后,首先会用B的public key对digital signature解密得到digest,由此证明这封信确实是由B发送的。同时对信件本身使用hash函数也会生成一个digest,如果这个digest和前面那个digest相等,可以证明信息确实没有被修改过。但是这也造成一个问题,如果C将A手中的B的public key替换为自己C的public key,但是A还是会以为自己手中的public key还是B的,这个时候如果C向A发送一份信息,A会以为是B发送的。这个时候我们要做的就是保证public key的身份。
为了避免这种情况,certificate authority就用自己的private key对B的public key和相关信息加密生成digital certificate。B以后向A发送信息,就只要搭上digital signature和digital certificate就可以放心了。A收到B的回信后,用CA的public key得到B的public key,然后和上面一样利用这个public key解密digital signature的得到digest来判断信息是不是由A发送的,因为digital signature就是利用public key加密的。
digital certificate的一个实例就是https协议,首先client向server发送加密request,server向client响应一个自己private key加密的网页和digital certificate。client(browser)的certificate manager(数字证书管理器)有一份合法证书颁布机构的列表,client会根据这份列表的public key解密digital certificate。如果列表记录的网址和你现在访问的网址不一致就会发出一个warning来告诉你这份digital certificate被别人冒用了。还有一种可能就是这份证书没有记载到合法证书颁布机构列表,也会发出另外一种warning。
参考链接
https://chamibuddhika.wordpress.com/2012/03/21/ssh-tunnelling-explained/
http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html
http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html
http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html