SSH
SSH
SSH - secure shell,protocol,22/tcp,安全的远程登录
SSH具体的软件实现:
- OpenSSH: ssh协议的开源实现,CentOS默认安装
- dropbear:另一个开源实现
SSH协议版本:
- v1: 基于CRC-32做MAC,不安全;man-in-middle
- v2:双方主机协议选择安全的MAC方式
基于DH算法做密钥交换,基于RSA或DSA实现身份认证
Openssh软件组成
OpenSSH相关包:
- openssh
- openssh-clients
- openssh-server
centos 默认最小化安装也会安装openssh相关软件包
~]# rpm -qa "openssh*"
openssh-server-7.4p1-16.el7.x86_64
openssh-7.4p1-16.el7.x86_64
openssh-clients-7.4p1-16.el7.x86_64
相关软件包分析
~]# rpm -ql openssh-server
/usr/lib/systemd/system/sshd.service service服务
/usr/sbin/sshd 服务软件程序,对外提供服务
/etc/ssh/sshd_config 服务器端配置文件
~]# rpm -ql openssh-clients <客户端工具>
/usr/bin/ssh ssh命令
/usr/bin/scp
/etc/ssh/ssh_config 客户端配置文件
~]# rpm -ql openssh <包含服务器端和客户端的通用信息>
查看相关端口由哪个服务监听的命令:
~]# lsof -i :22
~]# ss -tnp -p选项
相关工具:基于C/S结构
- Linux Client: ssh, scp, sftp,slogin
- Windows Client:xshell, putty, securecrt, sshsecureshellclient
- Server: sshd
ssh公钥交换连接 <ssh为什么安全?>
首次连接时:
第一次连接远程主机时:
无论client是Windows和Linux,客户端和服务器端各有各的公钥和私钥
公钥所在目录:
~]#ls /etc/ssh
ssh_host_ecdsa_key.pub centos7默认使用的加密算法:ecdsa
ssh_host_rsa_key.pub centos6默认使用的加密算法:rsa
对公钥做hash之后,连接确认,如果hash值不一样,说明是不存在的主机。
怎么提取ssh_host_ecdsa_key.pub的hash值呢?
1、先将公钥取出来,其中ssh_host_ecdsa_key.pub默认不是完整的公钥,里面
有描述和换行符
2、ssh_host_ecdsa_key.pub此文件中的公钥信息默认是被base64编码过的
base64 -d 还原原本的值
3、md5sum pubkey
确认连接的主机是不是你要连接的主机
第二次连接时就不再询问<--> 连接确认yes后,在本地家目录中的.ssh目录中会
生成一个known_hosts文件。第一次连接时yes后会将server端的公钥自动传给
client端。传送server端公钥的同时还会携带会话id,连接过程如上图所示。
注意: 如果一台主机被替换时,以前ssh基于以前主机私钥链接时,应该删除对应的公钥信息(/root/.ssh/known_hosts文件中)
ssh加密通信
ssh客户端
- 客户端组件:
- ssh, 配置文件:/etc/ssh/ssh_config
Host PATTERN
StrictHostKeyChecking no 首次登录不显示检查提示
如果企业内部连接可以修改此选项自动回答yes
客户端配置文件修参数1):
企业内部是使用:这个参数一般可以需要修改
如果要批量修改此参数:脚本等等,或者自动化运维工具
echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config
追加至文件最后也行
客户端配置文件修改参数2):
企业内部考虑安全可能需要修改默认的22端口号
因此客户端配置文件可能涉及修改默认端口号
否则需要-p手动指定
-
格式:ssh [user@]host [COMMAND]
ssh [-l user] host [COMMAND] -
常见选项
-p port:远程服务器监听的端口
-b:指定连接的源IP
-v:调试模式
-C:压缩方式
-X:支持x11转发
-t:强制伪tty分配
ssh -t remoteserver1 ssh -t remoteserver2 ssh remoteserver3
可能生产中有些安全策略不能直接连接某台主机,但是可以通过其他主机作为跳板机连接:<此时使用ssh -t>选项可简化些许流程
ssh -t remotehostip1 ssh -t remotehostip2 ssh remotehostip3
只有最后一个主机无需加-t
ssh登录验证方式
1)ssh基于用户名和口令的登录验证
2)ssh基于秘钥的登录验证
基于key认证的实现
-
(1)客户端生成密钥对儿
ssh -keygen [-t type] [-f “~/.ssh/id_**”] [-p ‘’]
-t:指定加密算法<默认rsa>
-f:指定生成文件路径
-p:密钥口令默认为交互式:加上-f -P选项直接指定为非交互式命令啦~ 最简单 ssh -keygen直接回车,就生成了一个密钥对
-
(2)把公钥文件传输至远程服务器对应用户的家目录
ssh-copy-id [-i [identity_file]] [user@]hosthostip前面需要指明当前用户与host主机哪个用户连接是基于key验证 就会将刚才生成的公钥传到连接用户的家目录的.ssh目录下,并且命名 为authorized_keys (默认权限为600)
-
(3)测试
-
(4) 在SecureCRT或Xshell实现基于key验证
在SecureCRT工具—>创建公钥—>生成Identity.pub文件转化为openssh兼容格式(适合SecureCRT,Xshell不需要转化格式),并复制到需登录主机上相应文件authorized_keys中,注意权限必须为600,在需登录的ssh主机上执行:ssh-keygen -i -f Identity.pub >> .ssh/authorized_keys
基于key认证实现时需要注意:
①~/.ssh/authorized_keys 文件权限600
②私钥必须保管妥善,添加口令,防止被盗取
当私钥添加口令时,每次登陆或者切换需要输入私钥口令,也是相当麻烦
解决办法:<一旦退出又需要重新执行验证代理>
重设或者更改私钥口令:
~]# ssh-keygen –p <自动会选择~/.ssh/id_rsa 文件>
验证代理(authentication agent)保密解密后的密钥
这样口令就只需要输入一次
在GNOME中,代理被自动提供给root用户
否则运行ssh-agent bash
~]# ssh-agent bash <启用agent代理>
钥匙通过命令添加给代理
ssh-add
~]# 将秘钥口令托管给agent代理
实验一
一台主机管理多台主机时:基于key验证
实现:在管理主机上生成秘钥对,然后将生产的公钥分发至管理的主机
- ①:~]#ssh-keygen -f “/root/.ssh/id_rsa” -P ‘’
- ②:.ssh]#ssh-copy-id root@192.168.66.17
- ③:.ssh]#ssh-copy-id root@192.168.66.27
- ④:.ssh]#ssh-copy-id root@192.168.66.37
- 此时当前主机可以实现基于key验证登录17、27、37这三台主机
脚本实现:expect ==> expect最常用的实现
#!/bin/bash
ssh-keygen -f "/root/.ssh/id_rsa" -P '' &> /dev/null
rpm -q expect &> /dev/null || yum install expect -y -q
pass=*****
user=root
while read ip ;do
expect <<EOF
set timeout 20
spawn ssh-copy-id $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$pass\n" }
}
expect eof
EOF
done < /data/hostlist.txt
# /data/hostlist.txt 为需要管理的主机列表
一个集群三五台主机实现两两互联均基于key验证
实现:在其中一台主机上生成秘钥对和authorized_keys,然后拷贝.ssh目录
- ①:~]#ssh-keygen -f ‘/root/.ssh/id_rsa’ -P ‘’
- ②:~]#ssh-copy-id root@127.0.0.1 生成authorized_keys文件
- ③: ~]#scp -r /root/.ssh 192.168.66.17:/root/
- …
使用同一套公钥私钥。
实验二
在SecureCRT或Xshell实现基于key验证
实现windows使用xshell 连接Linux是基于key验证的
- ①:xshell生成自己的秘钥对
- ②:秘钥对生成完成之后:将公钥导入到对应主机对应用户家目录.ssh/authorized_keys文件中
- ③:xshell中身份验证选择基于key验证连接主机
SCP命令
由前面可知scp命令来自于openssh-clients包
~]#rpm -qf /usr/bin/scp
openssh-clients....
scp 的基本语法:
- scp [opt] SRC DEST
scp [opt] 复制源 目标
①可以实现将远程主机文件复制至本地主机
②可以实现将本地主机文件复制至远程主机
③可以实现将远程主机文件复制至另一远程主机
scp命令走的是ssh协议
若主机之间实现了基于key验证,则可以直接复制
scp命令的选项:
- -C 压缩数据流
- -r 递归复制 <用于目录>
- -p 保持原文件的属性信息
- -q 静默模式
- -P PORT 指明remote host的监听的端口
scp 命令的局限性:
不能使用scp命令实现主机与备份主机的同步
eg:host1 host2主机为host1主机的文件备份主机
因为scp命令默认是直接复制整个目录或整个目录下所有文件
①scp不会只复制host1主机目录新增文件;
②当host1主机文件删除时:host2主机不会删除对应文件
rsync命令
基于ssh和rsh服务实现高效率的远程系统之间复制文件
使用安全的shell连接做为传输方式
- rsync -av /etc server1:/tmp 复制目录和目录下文件
- rsync -av /etc/ server1:/tmp 只复制目录下文件
- 注意: 源 带/ 和 不带/ 的区别
比scp更快,只复制不同的文件
常用选项:
- -n 模拟复制过程
- -v 显示详细过程
- -r 递归复制目录树
- -p 保留权限
- -t 保留时间戳
- -g 保留组信息
- -o 保留所有者信息
- -l 将软链接文件本身进行复制(默认)
- -L 将软链接文件指向的文件复制
- -a 存档,相当于–rlptgoD,但不保留ACL(-A)和SELinux属性(-X)
rsync:可以实现文件备份同步;经常用来数据同步
但是局限是rsync同步时是以文件为单位,不能只复制文件变化的部分
目前结合计划任务可以实现数据同步,但是并不能实现实时同步
--delete 同步时一般加上此选项,可以实现源有被删除的文件,同步主机也
删除对应文件,实现数据同步选项。
实时同步:以服务方式运行rsync
sftp命令与sshfs
sftp命令是交互式文件传输工具
- 用法和传统的ftp工具相似
- 利用ssh服务实现安全的文件上传和下载
- 使用ls cd mkdir rmdir pwd get put等指令,可用?或help获取帮助信息
sshfs命令 <epel源> 可以利用ssh协议将远程主机的某个目录挂载至本机
- 示例:sshfs 192.168.66.66:/data /mnt
- 取消挂载:umount /mnt
轻量级自动化运维工具
pssh
pssh:基于python编写,可在多台服务器上执行命令的工具,也可实现文件复制,提供了基于ssh和scp的多个并行工具
项目:http://code.google.com/p/parallel-ssh/
pdsh
pdsh:Parallel remote shell program,是一个多线程远程shell客户端,可以并行执行多个远程主机上的命令。 pdsh可以使用几种不同的远程shell服务,包括标准的“rsh”,Kerberos IV和ssh
项目: https://pdsh.googlecode.com/
mussh
mussh:Multihost SSH wrapper,是一个shell脚本,允许您使用一个命令在
多个主机上通过ssh执行命令或脚本。 mussh可使用ssh-agent和RSA / DSA密
钥,以减少输入密码
项目:http://www.sourceforge.net/projects/mussh
说明:以上工具都包含在EPEL源中
以上工具可以实现数量不多的几十台主机的自动运维管理。
以pssh为例:
若经常在多个主机之间做相同的操作时:比如同时安装某个相同的服务、修改
某服务的配置文件等等
pssh:基于ssh和scp实现并行处理的工具:
~]# rpm -qi pssh
....
o ssh : pssh
o scp : pscp
o nuke : pnuke
o rsync : prsync
o slurp : pslurp
~]# rpm -ql pssh
/usr/bin/pnuke
/usr/bin/prsync
/usr/bin/pscp.pssh
/usr/bin/pslurp
/usr/bin/pssh
/usr/bin/pssh - pssh工具
pssh的使用的前提已经实现基于key验证,否则会报错,
因为pssh默认是基于key验证
-A 基于口令验证 --> 但是只有一次输入口令的机会,要求只有管理的主机密码
一致<而且要求当前主机的.ssh的主机有known_hosts 内容含有管理的主机>
否则不会给你输入yes的机会
pssh批量管理建议还是基于key验证
pssh命令选项:
- –version:查看版本
- -h:主机文件列表,内容格式”[user@]host[:port]”
- -H:主机字符串,内容格式”[user@]host[:port]”
- -A:手动输入密码模式
- -i:每个服务器内部处理信息输出
- -l:登录使用的用户名
- -p:并发的线程数<可选>
- -o:输出的文件目录<可选>
- -e:错误输出文件<可选>
- -t:TIMEOUT 超时时间设置,0无限制<可选>
- -O:SSH的选项
- -P:打印出服务器返回信息
- -v:详细模式
~]# pssh -h /data/hostlist.txt -i 'sed -i "s/SELINUX=enforcing/
SELINUX=disabled/" /etc/selinux/config'
关闭/data/hostlist.txt 列表主机的selinux;重启生效
pscp.pssh工具
- pscp.pssh功能是将本地文件批量复制到远程主机
pscp-pssh选项
- -v 显示复制过程
- -r 递归复制目录
比如:脚本部署至多个主机:pscp.pssh
~]# pscp.pssh -h hosts /data/1.sh /data/
将本机/data/1.sh 批量部署至hosts列表主机的/data目录
pslurp工具
- pslurp功能是将远程主机的文件批量复制到本地
pslurp选项
- -L 指定从远程主机下载到本机的存储的目录,local是下载到本地后的名称
- -r 递归复制目录
批量下载hosts文件中的列表主机的passwd文件至/data下,并更名为user
pslurp -h hosts /data /etc/passwd user
抓取至的主机下为避免重名会创建以ip地址为名称的目录,然后将文件存放。
data]# pslurp -h hosts -L /data/ /etc/fstab user
[root@centos7-17 data]# tree
.
├── 192.168.38.16
│ └── user
├── 192.168.38.17
│ └── user
├── 192.168.38.27
│ └── user
├── 192.168.38.37
│ └── user
├── 1.sh
└── hosts
端口转发
SSH 会自动加密和解密所有 SSH 客户端与服务端之间的网络数据。但是,SSH 还能够将其他 TCP 端口的网络数据通过 SSH 链接来转发,并且自动提供了相应的加密及解密服务。这一过程也被叫做“隧道”(tunneling),这是因为SSH 为其他 TCP 链接提供了一个安全的通道来进行传输而得名。
使用场景:在生产实际中一般企业外部进入至企业内部是不允许的,因为安全策略
现在有需求:互联网的主机也能访问企业内部的主机
使用ssh协议可以开放特定的主机给出差在外的互联网主机
或者使用ssh协议将不安全的协议封装
第一种场景:
本地端口转发
- -L localport:remotehost:remotehostport sshserver
选项:
- -f 后台启用
- -N 不打开远程shell,处于等待状态
- -g 启用网关功能
互联网主机开启端口,本地端口转发
实现:
1)配置主机C
①~]#iptables -A INPUT -s 192.168.38.27 -j REJECT
使用iptables禁止A主机直接连接
②~]# ss -tnl <默认25端口只有本机能连接>
... 127.0.0.1:25 ... 修改监听的地址范围
未修改时,该主机不能连接25端口
~]# telnet 192.168.38.17 25
Trying 192.168.38.17...
telnet: connect to address 192.168.38.17: Connection refused
vim /etc/postfix/main.cf
inet_interfaces = localhost
将localhost改为all
重启服务,生效
2)主机C上执行:
~]# ssh -L 9527:192.168.38.17:25 192.168.38.37 -fN
开启本机9527端口相当于去连接17的25端口,中间借助37主机
-fN 不加默认会连接37主机上去
~]# telnet 127.0.0.1 9527
连接本机的9527端口相当于连接17的25端口
在主机C(17)以为是跳板机主机B(37)在连接自己的25端口
此实现的前提:默认互联网可以连接本地内部的22端口;但是一般是22端口不会开
启,因此这种连接方式比较危险
第二种场景:
远程转发:
- -R sshserverport:remotehost:remotehostport sshserver
远程端口转发
企业内部一般会拒绝互联网主机连接企业内部,但是企业内部主机可以允许连接
至互联网,给出差在外的同事开启ssh隧道,然后他可以直接通过互联网连接至企
业内部,不需要更改任何的防火墙策略和开启VPN。
外网的同事只能连接开启的那一台主机
实现:
①在主机B上执行
~]# ssh -R 6666:192.168.38.17:25 192.168.38.27 -fN
此时由企业内部主机建立隧道,在A主机上会自动打开6666端口
②此时A主机连接自己的端口:
~]# telnet 127.0.0.1 6666
可以连接
在主机C上也是以为跳板机主机B在连接自己
第三种场景:
动态端口转发:<防止出去的场景>
当用firefox访问internet时,本机的1080端口做为代理服务器,firefox的访问请求被转发到sshserver上,由sshserver替之访问internet
- ssh -D 1080 root@sshserver -fNg
ssh -D 1080 root@sshserver -fNg
当在本地访问1080端口时请求就会发送给远程的跳板机,通过跳板机
再去访问对应主机 <1080并不是固定端口,本机未使用端口均可>
- 在本机浏览器配置代理,通过此浏览访问时,将请求发给本机的对应端口
ssh服务器
ssh服务器
- 服务器端:sshd, 配置文件: /etc/ssh/sshd_config
- 建议配置文件修改时先做备份
- 配置文件帮助:man sshd_config
ssh服务器常用参数:
- Port
端口:放在互联网的主机ssh的默认22端口是需要修改的
- ListenAddress ip
默认ssh监听在所有ip,可以修改指定监听的ip
ListenAddress 0.0.0.0 <所有ip>
- LoginGraceTime 2m
~]# ssh 192.168.38.37
root@192.168.38.37's password:
用户建立连接,但迟迟不输入密码连接
2min不连接就断开,免得浪费资源
- PermitRootLogin yes
PermitRootLogin:Ubuntu默认root不能直接使用xshell连接,因为此选项
PermitRootLogin prohlbit-password 禁止密码连接<但是可以基于秘钥连>
- StrictModes yes 检查.ssh/文件的所有者,权限等
StrictModes:要求.ssh/目录对应文件权限、所有者 严格检查
- MaxAuthTries 6
MaxAuthTries:口令验证尝试次数为:6/2=3
- MaxSessions 10 同一个连接最大会话
MaxSessions:一个ssh连接可开启的会话数
即xshell的复制SSH渠道可以复制10个
- PubkeyAuthentication yes
PubkeyAuthentication:基于key验证
- PermitEmptyPasswords no
- PasswordAuthentication yes
PasswordAuthentication:是否支持密码验证登录
- GatewayPorts no
- ClientAliveInterval 单位:秒
- ClientAliveCountMax 默认3
- UseDNS yes
- GSSAPIAuthentication yes 提高速度可改为no
UseDNS:将ip地址反向解析为域名
GSSAPIAuthentication:API验证平时一般不用
- MaxStartups 未认证连接最大值,默认值10
未认证的连接如下:
~]# ssh 192.168.38.37
root@192.168.38.37's password:
如果未认证的连接在10个以内不做任何处理,如果大于10个以30%的速率拒绝
连接,达到60个时,全部拒绝
限定并发连接数
- Banner /path/file
Banner:登录的提示信息
- 限制可登录用户的办法:
AllowUsers user1 user2 user3
DenyUsers
AllowGroups
DenyGroups
ssh服务的最佳实践
- 建议使用非默认端口 <尤其发布至互联网的主机,默认端口一定要修改>
- 禁止使用protocol version 1 <版本1有漏洞>
- 限制可登录用户
- 设定空闲会话超时时长
- 利用防火墙设置ssh访问策略
- 仅监听特定的IP地址
- 基于口令认证时,使用强密码策略
tr -dc A-Za-z0-9_ < /dev/urandom | head -c 12| xargs
openssl random -base64 6 - 使用基于密钥的认证
- 禁止使用空密码
- 禁止root用户直接登录
- 限制ssh的访问频度和并发在线数
- 经常分析日志
错误登录访问日志
- /var/log/btmp
~]# file /var/log/btmp
/var/log/btmp: DBase 3 index file 数据库文件
不能使用文本查看工具查看,需要使用 lastb 命令查看
~]#lastb
root ssh:notty 192.168.38.27 Wed Aug 7 06:29 - 06:29 (00:00)
root ssh:notty 192.168.38.27 Wed Aug 7 06:29 - 06:29 (00:00)
~]# lastb -f /var/log/btmp
lastb -f file
定期分析此文件/var/log/btmp:如果错误连接数在1天以内超过50次,认为
不正常访问,列入黑名单。
计划两个脚本完成:
①每天将/var/log/btmp中信息备份至一个目录,然后将此文件清零
~]# cp /var/log/btmp /data/btmp`date -d "yesterday" +%F`
文件清零
> /var/log/btmp (bash)
所有shell:cat /dev/null > /var/log/btmp
~]# cat /dev/null > /var/log/btmp
②然后对取出的文件进行处理 (错误次数>=50) 拒绝访问
lastb -f filename| awk '{ip[$3]++}END{for(i in ip){if(ip[i]\
>=50){system("iptables -A INPUT -s" i "-j REJECT")}}}'
相关命令如上,脚本略。