• SSH协议基本原理

    什么是SSH

    ssh是(Secure SHell protocol) 的简写,顾名思义,安全外壳协议(SSH)是一种在安全保护下的网络协议,它的本身只是一种协议。ssh协议目前有SSH1和SSH2,SSH2协议兼容了SSH1。目前实现SSH1和SSH2协议的主要软件有OpenSSH。它的存在意义主要有以下两点:

    1. 代替telnet等不安全的远程链接协议,telnet协议采用明文密码传送,在传送过程中对数据也不加密,很不安全。而ssh协议可以通过密码,公钥等方式进行安全验证和数据加密。

    2. 代替FTP等不安全的远程传输协议,提供更安全的远程传输服务,SSH传输的数据是经过压缩的,所以可以加快传输的速度。

    SSH 协议的基本特征

    SSH 协议默认使用的是tcp 22号端口,基于C/S架构,分为服务器端与客户端。服务端的程序有sshd,我们通常所说的OpenSSH 包括sshd主程序与ssh客户端.大概有如下部分组成:

    yy

    sshd ―― SSH服务端程序

    sftp-server ―― SFTP服务端程序(类似FTP但提供数据加密的一种协议)

    scp ―― 非交互式sftp-server的客户端,用来向服务器上传/下载文件

    sftp ―― 交互式sftp-server客户端,用法和ftp命令一样。

    slogin ―― ssh的别名

    ssh ―― SSH协议的客户端程序,用来登入远程系统或远程执行命令

    ssh-add ――    SSH代理相关程序,用来向SSH代理添加dsa key

    ssh-agent ――    ssh代理程序

    ssh-keyscan ―― ssh public key 生成器

    SSH的基本配置

    配置存放路径: /etc/ssh/sshd_config ,主要内容分为以下几个部分:

    1. SSH Server 全局设定,port ,协议 ……

    • # Port 22  #默认端口,也可以使用多个端口
    • Protocol 2 #协议版本号
    • # ListenAddress 0.0.0.0 #默认值是监听所有接口的 SSH 要求
    • # PidFile /var/run/sshd.pid #放置 SSHD 这个 PID 的文件
    • # LoginGraceTime 2m #2分钟之内不输入密码,自动断开
    • # Compression delayed  #使用压缩数据模式进行传输,登入后才将数据压缩 (delayed)

    2. 主要私有Key 存放文件

    • # HostKey /etc/ssh/ssh_host_key # SSH version 1 使用的私钥
    • # HostKey /etc/ssh/ssh_host_rsa_key # SSH version 2 使用的 RSA 私钥
    • # HostKey /etc/ssh/ssh_host_dsa_key # SSH version 2 使用的 DSA 私钥

    3. 关于登录文件的数据与daemon的名称

    • SyslogFacility AUTHPRIV #记录日志/var/log/secure
    • # LogLevel INFO #日志等级

    4. 安全设置

    • # PermitRootLogin yes #是否允许 root 登入
    • # StrictModes yes #是否让 sshd 去检查用户家目录或相关文件的权限数据
    • # PubkeyAuthentication yes #使用密钥登录系统
    • # AuthorizedKeysFile .ssh/authorized_keys #用户登录公钥存放位置
    • PasswordAuthentication yes #登录密码认证
    • # PermitEmptyPasswords no #否允许以空的密码登入
    • # RhostsAuthentication no #系统不使用 .rhosts认证
    • # IgnoreRhosts yes #是否取消使用 ~/.ssh/.rhosts 来做为认证
    • # RhostsRSAAuthentication no #专门给 version 1 用的,使用 rhosts 文件在 /etc/hosts.equiv
    • # HostbasedAuthentication no #上面的项目类似,不过是给 version 2 使用的
    • # IgnoreUserKnownHosts no #是否忽略家目录内的 ~/.ssh/known_hosts
    • ChallengeResponseAuthentication no #允许任何的密码认证
    • UsePAM yes #利用 PAM 管理使用者认证,可以记录与管理

    5. 登录后项目

    • # PrintMotd yes #登入后是否显示出一些信息
    • # PrintLastLog yes #显示上次登入的信息
    • # TCPKeepAlive yes #当达成联机后,服务器会一直传送 TCP 封包给客户端以判断对方式否一直存在联机
    • UsePrivilegeSeparation yes #是否权限较低的程序来提供用户操作
    • MaxStartups 10 #同时允许几个尚未登入的联机画面
    • DenyUsers * #设定受阻止的使用者名称
    • DenyUsers test  #阻止用户
    • DenyGroups test #阻止组

    6. SFTP 设定

    • Subsystem sftp /usr/lib/ssh/sftp-server
    • # UseDNS yes #为了要判断客户端来源是正常合法的,因此会使用 DNS 去反查客户端的主机名,不过在内网这项目设定为 no 会让联机达成速度比较快

    SSH基本原理

    在了解SSH协议的基本原理之前,首先我们得知道几个概念,或者说我们得弄清楚几个问题:

    1. SSH使用的是什么加密算法,有什么好处,还有哪些加密算法?

    2. 这些加密算法的原理是什么?

    3. 在传输过程中是如何保证数据的一致性的?

    目前,主流的加密算法主要有两种,私钥加密(对称加密)和公钥加密.

    私钥加密(对称加密):

    私钥加密,是说加密方和解密方用的都是同一个key,且只有一个key,这个key对于加密方和解密方来说是保密的,第三方是不能知道的。在第三方不知道私钥key的情况下,是很难将加密的数据解密的。一般来说是加密方先产生私钥,然后通过一个安全的途径来告知解密方这个私钥。 即只有一把钥匙.

    公钥加密(非对称加密算法)(公开密钥加密算法) :

    公钥加密必须有两个密钥,一个公钥,一个私钥.解密的一方首先生成一对密钥,一个私钥一个公钥,私钥不会泄漏出去,而公钥则是可以任意的对外发布的。用公钥进行加密的数据,只能用私钥才能解密。加密方首先从解密方获取公钥,然后利用这个公钥进行加密,把数据发送给解密方。解密方利用私钥进行解密。如果解密的数据在传输的过程中被第三方截获,也不用担心,因为第三方没有私钥,没有办法进行解密。 如下图所示:

    yy

    kobe 和 james 是一对好基友,有一天,科比下载到了一部爱情动作片想要分享给詹姆斯.但是他俩都是名人,不能让别人知道.所以他们就采用了如下的传送方式:

    科比有自己的生活密码是123,詹姆斯也有是456.如果他们使用的是对称加密算法,那么科比只能把自己的密码123告诉詹姆斯,詹姆斯才能打开数据.这样会很不方便.于是他们采用了非对称加密算法. 首先,他们根据自己的密码分别生成自己的私钥和公钥. 上面我们说过,用公钥加密的数据只有用配对的私钥才能解开.所以科比就用自己的公钥和詹姆斯的公钥进行了对数据进行了一个加密然后再传给詹姆斯.(箭头1和箭头2),而詹姆斯拿到数据以后,只需要用自己的私钥将数据解开就可以看了.(如箭头3). 在整个过程中,那个data就类似于一个羽毛球筒,我们要想取得羽毛球,只要能打开其中的一端的锁就可以,而刚好有有一端的锁是用自己的公钥锁上的,所以自己的私钥就可以打开了。

     

    SSH协议就是基于非对称加密算法的,他的工作原理如下图所示:

    yy

    SSH基本用法

    SSH主要有两种登陆方式,一种是密码口令登陆,一种是公钥登陆.

    口令密码登陆: 

    假定你要以用户名user,登录远程主机host,只要一条简单命令就可以了。

      $ ssh user@host

    如果本地用户名与远程用户名一致,登录时可以省略用户名。

      $ ssh host

    SSH的默认端口是22,也就是说,你的登录请求会送进远程主机的22端口。使用p参数,可以修改这个端口。

      $ ssh -p 2222 user@host

    上面这条命令表示,ssh直接连接远程主机的2222端口。

    如果你是第一次登录对方主机,系统会出现如下类似提示:

    这段话的意思是,无法确认host主机的真实性,只知道它的公钥指纹,问你还想继续连接吗?

    假定经过风险衡量以后,你决定接受这个远程主机的公钥。

      Are you sure you want to continue connecting (yes/no)? yes

    系统会出现一句提示,表示host主机已经得到认可。

      Warning: Permanently added ‘host,10.10.10.10’ (RSA) to the list of known hosts.

    然后,会要求输入密码。

      Password: (enter password)

    如果密码正确,就可以登录了。

    当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts之中

    。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。

    每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts,保存一些对所有用户都可信赖的远程主机的公钥。

    公钥登陆:

    所谓”公钥登录”,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

    这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:

      $ ssh-keygen

    运 行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可 以设置一个。运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。前者是你的公钥,后者是你的私钥。

    这时再输入下面的命令,将公钥传送到远程主机host上面:

      $ ssh-copy-id user@host

    好了,从此你再登录,就不需要输入密码了。

    远程主机将用户的公钥,保存在登录后的用户主目录的$HOME/.ssh/authorized_keys文件中。公钥就是一段字符串,只要把它追加在authorized_keys文件的末尾就行了。

    如果还是不行,就打开远程主机的/etc/ssh/sshd_config这个文件,检查下面几行前面”#”注释是否取掉。

    RSAAuthentication yes

    PubkeyAuthentication yes

    AuthorizedKeysFile .ssh/authorized_keys

    然后,重启远程主机的ssh服务。

    service ssh restart

    SSH免密码登陆

    假如我们有需求在A和B两台服务器上进行免密码的ssh登陆,那么可以用以下流程试试:

    1. 首先确保iptables和selinux没有设置对应的拦截规则.

    2. 确保A和B两台机器的相关目录的权限:

    • 如下两个目录的所有权必须是user,所属组也应该是user,权限必须为700

    \home\user

    \home\user\.ssh

    • 如下面公钥文件的所有权必须是user,所属组也应该是user,权限必须为644

    \home\user\.ssh\authorized_keys

    • 如下面私钥文件的所有权必须是user,所属组也应该是user,权限必须是600

    \home\user\.ssh\id_rsa

    3. 在A机器上执行ssh-keygen, 一路回车即可

    4. 第3步执行完后,会在对应用户的家目录的.ssh下生成id_rsa.pub文件,将其中的内容拷贝到B上面的对应用户的.ssh目录下的authorized_keys文件下加进去即可.

    这一步可以用 ssh-copy-id -i /root/.ssh/id_rsa.pub root@10.10.10.10 来代替.

    5. 如果执行完前四步还是不行的话,那么检查目标机器上 /etc/ssh/sshd_config里面的下述两个参数是否都是yes?

    PermitRootLogin yes      //是否允许root用户登陆

    PermitEmptyPasswords yes   //是否允许免密码登陆

    如果不是,则可以修改配置文件,然后执行 /etc/init.d/sshd restart来重新启动sshd进程.

    6. 可以清除源端的 ~/.ssh/known_hosts里面关于目的机器的信息部分,并且清除目的机器的~/.ssh/authorized_keys里面关于源端机器的信息部分.然后执行ssh让他们重新认证.

    SHELL 脚本输入密码远程执行命令

    如果你有这么个需求,在shell脚本中在远程服务器执行命令,这时候或许你会有些困扰。貌似只能通过配置免密码登陆的方式来实现,否则就会出现这种情况,程序无法自动执行,因为要你输入密码:

    [root@localhost ~]# cat biu.sh

    #! /bin/bash

    ssh test@123.23.234.125 “ls -l”

    [root@localhost ~]# ./biu.sh

    test@123.23..234.125’s password:

    这就尴尬了,看似一个很小的问题,貌似还不好解决。 因为很多时候我们并不想轻易的配置免密码认证,既麻烦还没有安全性。 这时候或许我们可以借助其他工具,例如sshpass 和 expect:

    sshpass

    它的安装和使用很简单,下面就举个例子:

    1. 安装sshpass

    2. sshpass的使用

    执行成功 !

    expect

    #!/usr/bin/expect                                      //expect和shell一样需要指定执行路径

    set passed “xxxxxxx”                               //他的变量设置用set语法

    set command [lindex $argv 0]                  //获取脚本的第一个参数,并赋值给command

    spawn $command                                  //启动spawn子进程执行command命令

    expect {

    “yes/no” {send “yes\r”;exp_continue}                     // 匹配到“yes/no”这样的时,它自动帮你yes

    “password:” {send “$passwd\r”;exp_continue}     // 匹配到password时,它自动帮你输入密码

    }