地址

第1章 ssh命令和SSH服务详解

Windows 下通过 cmder 远程连接 Linux 服务器

sshd 中文手册

监控服务器ssh登录,并发送报警邮件

加密

对称加密:加密和解密使用一样的算法,只要解密时提供与加密时一致的密码就可以完成解密。例如QQ登录密码,银行卡密码,只要保证密码正确就可以。

非对称加密:通过公钥(public key)和私钥(private key)来加密、解密。公钥加密的内容可以使用私钥解密,私钥加密的内容可以使用公钥解密。一般使用公钥加密,私钥解密,但并非绝对如此,例如CA签署证书时就是使用自己的私钥加密。在接下来介绍的SSH服务中,虽然一直建议分发公钥,但也可以分发私钥。

所以,如果A生成了(私钥A,公钥A),B生成了(私钥B,公钥B),那么A和B之间的非对称加密会话情形包括:

  1. A将自己的公钥A分发给B,B拿着公钥A将数据进行加密,并将加密的数据发送给A,A将使用自己的私钥A解密数据。
  2. A将自己的公钥A分发给B,并使用自己的私钥A加密数据,然后B使用公钥A解密数据。
  3. B将自己的公钥B分发给A,A拿着公钥B将数据进行加密,并将加密的数据发送给B,B将使用自己的私钥B解密数据。
  4. B将自己的公钥B分发给A,并使用自己的私钥B加密数据,然后A使用公钥B解密数据。

SSH的身份验证阶段,SSH只支持服务端保留公钥,客户端保留私钥的方式,所以方式只有两种:

  1. 客户端生成密钥对,将公钥分发给服务端;
  2. 服务端生成密钥对,将私钥分发给客户端。

SSH概要

  • SSH服务的守护进程为sshd,默认监听在22端口上。

  • 所有ssh客户端工具,包括ssh命令,scp,sftp,ssh-copy-id等命令都是借助于ssh连接来完成任务的。也就是说它们都连接服务端的22端口,只不过连接上之后将待执行的相关命令转换传送到远程主机上,由远程主机执行。

  • ssh客户端命令(ssh、scp、sftp等)读取两个配置文件:

    1. 全局配置文件/etc/ssh/ssh_config
    2. 用户配置文件~/.ssh/config

    生效的优先级是:命令行配置选项 > ~/.ssh/config > /etc/ssh/ssh_config。

SSH原理

SSH加密传输原理类似HTTPS的加密传输,即使用混合加密传输:

  1. A要与B通信
  2. A生成一对密钥
  3. A将公钥发送给B
  4. B拿到公钥,生成一个随机密码串(对称加密的key,用于认证完成后的通信),并用公钥加密这个密码串,发送给A
  5. A拿到密文,用私钥解密,获得到这个随机密码串
  6. B继续发送一个利用上个随机密码串加密的数据给A,A收到后用随机密码串解密这个数据
  7. A解密正常后通知B
  8. 加密通道建立完成,以后的通信都用这个随机密码串加解密

基于用户和口令登录验证

image

  1. 首先在客户端生成一对密钥(ssh-keygen)
  2. 并将客户端的公钥ssh-copy-id 拷贝到服务端
  3. 当客户端再次发送一个连接请求,包括ip、用户名
  4. 服务端得到客户端的请求后,会到authorized_keys中查找,如果有响应的IP和用户,就会随机生成一个字符串,例如:acdf
  5. 服务端将使用客户端拷贝过来的公钥进行加密,然后发送给客户端
  6. 得到服务端发来的消息后,客户端会使用私钥进行解密,然后将解密后的字符串发送给服务端
  7. 服务端接受到客户端发来的字符串后,跟之前的字符串进行对比,如果一致,就允许免密码登录

基于公钥认证机制实现双机互信

在身份验证阶段,由于默认情况下基于公钥认证的机制顺序优先于基于密码认证的机制,所以基于公钥认证身份,就可以免输入密码,即实现双机互信(实际上只是单方向的信任)。

实现步骤

在客户端使用ssh-keygen生成密钥对,存放路径按照配置文件的指示,默认是在~/.ssh/目录下。

1
2
3
4
5
6
7
8
ssh-keygen -t rsa    # -t参数指定算法,可以是rsa或dsa

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): # 询问私钥保存路径
Enter passphrase (empty for no passphrase): # 询问是否加密私钥文件
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.

将上面生成的公钥使用ssh-copy-id分发(即复制)到远程待信任主机上。

ssh-copy-id用法很简单,只需指定待信任主机及目标用户即可。如果生成的公钥文件,路径不是~/.ssh/id_rsa.pub,则使用”-i”选项指定要分发的公钥。

1
ssh-copy-id [-i [identity_file]] [user@]machine

例如

1
ssh-copy-id 172.16.10.6

说人话

  1. 在客户端生成密钥对

    1
    2
    3
    ssh-keygen
    cat id_rsa
    id_rsa id_rsa.pub
  2. 把公钥文件传输至远程服务器对应用户的家目录

    1
    ssh-copy-id -i id_rsa.pub root@192.168.4.100

    如果在COPY的时候不小心把公钥写成了私钥,放心,实际执行时只会复制公钥。

    会在用户的家目录的.ssh/目录生成authorized_keys文件

  3. 测试

1
ssh root@192.168.4.100
  1. 实现了免密登录了

更为简单的ssh-key步骤

  1. 在本机生成 SSH 密钥对

    1
    ssh-keygen -t rsa
  2. 上传公钥到 Linux 服务器

    创建文件(远程)

    1
    2
    mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys
    chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys

    本机上传(本机)

    1
    scp C:\Users\<用户名>\.ssh\id_rsa.pub <username>@<server-ip-address>:~/.ssh/authorized_keys
  3. 上传成功后输入以下命令即可成功连接服务器

    1
    ssh <username>@<server-ip-address>
  4. 配置 config 文件简化登录输入

    1
    vim C:\Users\<用户名>\.ssh\config
  5. 输入以下内容:

    1
    2
    3
    4
    Host <name-you-want>
    HostName <server-ip-address>
    User <username>
    PubkeyAuthentication yes
  6. config 文件创建好后,直接输入以下命令登录服务器

    1
    ssh <name-you-want>

sshd

  • sshd 是 OpenSSH SSH 守护进程。用于在不可信网络上提供安全的连接通道。
  • sshd 守护进程通常由root用户启动,它监听来自客户端的连接,然后为每个连接派生一个子进程。子进程负责处理密钥交换、加密、认证、执行命令、数据交换等具体事务。
  • sshd 的行为可以通过使用命令行选项和配置文件(默认是sshd_config进行控制,但命令行选项会覆盖配置文件中的设置。

sshd任务

当某个用户成功登录后,sshd 将会按照下列顺序做一系列动作:

  1. 如果在一个 tty 登录,并且没有指定执行任何命令,那么将打印上次登录时间和 /etc/motd 的内容。
    /etc/motd 的内容可以通过配置文件或者 ~/.hushlogin 禁止。

  2. 如果在一个 tty 登录,那么记录登录时间。

  3. 如果存在 /etc/nologin 文件,并且登录用户不是root,那么打印 /etc/nologin 文件的内容并结束。

  4. 切换身份至非特权用户运行

  5. 设置基本环境变量

  6. 如果配置文件允许用户修改环境变量,则处理 ~/.ssh/environment 文件并设置相应的环境变量
    细节参见 sshd_config(5) 手册页中的 PermitUserEnvironment 指令。

  7. 切换到该用户的家目录

  8. 如果存在 ~/.ssh/rc 文件则运行它,否则运行 /etc/ssh/sshrc (如果存在)。
    如果上面两个都不存在则运行 xauth 程序。参见下面的”SSHRC”小节。

  9. 启动用户的 shell 或运行指定的命令。

监控服务器ssh登录,并发送报警邮件

/etc/sshsshrc

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#获取登录者的用户名
user=$USER
#获取登录者的IP地址
ip=${SSH_CLIENT%% *}
#获取登录的时间
time=$(date +%F%t%k:%M)
#服务器的IP地址
hostname=$(hostname)
echo "content=$time,$user,$ip,$hostname" > log

python /etc/ssh/testEmail.py "$time" "$user" "$ip" "$hostname"

/etc/ssh/testEmail.py :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import smtplib
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import sys


def send_mail(dtime,duser,dip,dhostname):
#基础信息
# from_addr = input("From:")
from_addr = "yaohong@qq.com"
password = "授权码"
#to_addr = from_addr
to_addr = "yaohong@qq.com"
# password = raw_input("Password:")
# to_addr = input("To:")

def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))

smtp_server = "smtp.qq.com"
mimetex = '您的机器:',dhostname,',于:',dtime,',被IP:',dip,'以账号',duser,'进行登录,请确认是否为公司员工。'
#构造邮件
msg = MIMEText(''.join(mimetex), 'plain', 'utf-8')
msg['From'] = _format_addr("yaohong")
msg['To'] = _format_addr("yaohong@qq.com")
msg['Subject'] = Header("来自yaohong", 'utf-8').encode()
#发送邮件
server = smtplib.SMTP_SSL(smtp_server, 465)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()


if __name__ == "__main__":
send_mail(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

SCP

  • scp是全量拷贝

    1
    >scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]src_file ... [[user@]host2:]dest_file

    选项说明:
    -1:使用ssh v1版本,这是默认使用协议版本
    -2:使用ssh v2版本
    -C:拷贝时先压缩,节省带宽
    -l limit:限制拷贝速度,Kbit/s,1Byte=8bit,所以”-l 800”表示的速率是100K/S
    -o ssh_option:指定ssh连接时的特殊选项,一般用不上。
    -P port:指定目标主机上ssh端口,大写的字母P,默认是22端口
    -p:拷贝时保持源文件的mtime,atime,owner,group,privileges
    -r:递归拷贝,用于拷贝目录。注意,scp拷贝遇到链接文件时,会拷贝链接的源文件内容填充到目标文件中(scp的本质就是填充而非拷贝)
    -v:输出详细信息,可以用来调试或查看scp的详细过程,分析scp的机制

  • rsync是增量拷贝,要判断每个文件是否修改过,在小文件众多的情况下,判断次数非常多,导致rsync效率较差,而scp基本不影响系统正常使用。