Ssh服务安全加固
2013-03-30 20:22:44 阿炯

本文主要分析了OpenSSH本身与网络安全的分析,各登录的各个阶段有一些过程分析,文后会附上一些安全设置建议,本文基于OpenSSH8.5。

1、背景

SSH协议出现之前,在网络设备管理上广泛应用的一种方式是Telnet。Telnet协议的优势在于通过它可以远程地登录到网络设备上,对网络设备进行配置,为网络管理员异地管理网络设备提供了极大的方便。但Telnet协议存在几个致命的弱点:
1)、明文传输:数据传输采用明文方式,传输的数据没有任何机密性可言。
2)、认证机制脆弱:用户的认证信息在网络上以明文方式传输,很容易被窃听; Telnet 只支持传统的密码认证方式,很容易被攻击。
3)、“伪服务器欺骗”:客户端无法真正识别服务器的身份,攻击者很容易进行“伪服务器欺骗”。SSH协议正是为了克服Telnet协议存在的问题而诞生的。
4)、数据传输过程被篡改,无法保证传输过程数据完整性。

2、安全措施

Ssh是如何解决上述几个安全问题,我们一个个来分析。当SSH客户端连接到服务器时,每一方都向对方提供连接参数列表,它们如下(在ssh_config中有相应的关键字):
KexAlgorithms(kex): the key exchange methods that are used to generate per-connection keys(用于生成每连接密钥的密钥交换方法 )
HostkeyAlgorithms(key): the public key algorithms accepted for an SSH server to authenticate itself to an SSH client(SSH服务器接受的公钥算法,用于向SSH客户端向服务器进行自身身份验证)
Ciphers(cipher): the ciphers to encrypt the connection(加密连接的密码)
MACs: the message authentication codes used to detect traffic modification(用于检测流量篡改的消息认证码)

要成功连接,每个参数必须至少有一个相互支持的配置项,否则就会失败并可能给相应的原因。根据服务器配置,其他连接参数可能无法协商。可能会发现密码和/或MAC配置选项对于启用这些功能非常有用,可以通过下面的方式查询本机ssh支持哪些算法:
ssh -Q cipher    # List supported ciphers
ssh -Q mac    # List supported MACs
ssh -Q key    # List supported public key types
ssh -Q kex    # List supported key exchange algorithms

关于过时的选项(Legacy Options),可在OpenSSH的官方主页中查询得到。


2.1.明文传输问题
通过 在 通信双方建立“加密通道”,保证传输的数据不被窃听。并且需要有合适的手段保证通信双方秘钥的安全

2.1.1使用加密通道保证数据不被窃听

所谓加密通道,是指发送方在发送数据前,使用加密密钥对数据进行加密,然后将数据发送给对方;接收方接收到数据后,利用解密密钥从密文中获取明文。加解密算法分为两类:对称密钥算法:数据加密和解密时使用相同的密钥和相同的算法;非对称密钥算法:数据加密和解密时使用不同的密钥,常用的是公开的公钥来加密,解密为私钥持有者。

由于非对称密钥算法比较耗算力,一般多用于数字签名以及身份认证。SSH加密通道上的数据加解密使用对称密钥算法(与HTTPS类似),目前主要支持的算法有DES、3DES、AES等,这些算法都可以有效地防止交互数据被窃听,而且由于采用了初始化向量保护,可以防止类似于密码流复用等密码分析工具的攻击。

2.1.2使用密钥交换算法保证密钥本身的安全

对称密钥算法要求解密密钥和加密密钥完全一致,才能顺利从密文中解密得到明文。因此要建立加密通道,必须先在通信双方部署一致的加解密密钥。部署加解密密钥的方式有多种:手工配置和第三方机构分配等。手工配置的方式扩展性差,只适合一些小型的本地网络;使用第三方机构分配密钥的方式,需要额外的第三方服务器,而且密钥在网络中传输容易被窃听。

SSH协议使用一种安全的方式在通信双方部署密钥:密钥交换算法。利用密钥交换算法可以在通信双方动态地产生密钥,这个密钥只能被通信的双方获得,任何第三者都无法窃听,这就在源头上保证了加解密使用密钥的安全性,很好地解决了密钥分发问题。

2.1.3传输数据加密算法/秘钥交换算法的配置

1).传输数据加密算法配置
支持的数据加密算法(cipher)有:
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com

可以通过关键字 “Ciphers”指定使用的算法,多个算法间,需要使用英文的逗号相隔。有三种方式指定算法:
方式一:Ciphers 关键字后接算法名称,比如:Ciphers aes256-ctr,aes192-ctr表示只使用aes256-ctr,aes192-ctr两种算法

方式二:Ciphers 关键字后接算法名称,并且算法名称前带上“+”,表示在默认算法基础上,新增“+”后的算法

方式三:Ciphers 关键字后接算法名称,并且算法名称前带上“-”,表示在默认算法基础上,裁剪“-”后的算法

2).密钥交换算法配置
支持的密钥交换算法(kex)有:
diffie-hellman-group1-sha1
diffie-hellman-group14-sha1
diffie-hellman-group14-sha256
diffie-hellman-group16-sha512
diffie-hellman-group18-sha512
diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521
curve25519-sha256
curve25519-sha256@libssh.org
sntrup761x25519-sha512@openssh.com

可以通过关键字 “KexAlgorithms”指定使用的算法,多个算法间需要使用 英文逗号相隔。

有三种方式指定算法

方式一:KexAlgorithms关键字后接算法名称,比如:KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1

表示只使用diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1

另外两种算法的书写格式:
方式二:KexAlgorithms关键字后接算法名称,并且算法名称前带上“+”,表示在默认算法基础上,新增“+”后的算法

方式三:KexAlgorithms关键字后接算法名称,并且算法名称前带上“-”,表示在默认算法基础上,裁剪“-”后的算法

2.2.认证机制脆弱问题(服务端认证客户端)

2.2.1密码认证
传统的方式,采用的是密码认证模式:用户在ssh客户端输入账号、密码,openssh完成对登录用户进行密码认证。用户的身份信息等关键数据都保存在认证服务器上。

2.2.2公钥认证
由于密码认证方式的认证强度较弱,SSH协议引入了公钥认证方式。目前openssh可以利用RSA和DSA两种主要的非对称密钥算法实现公钥认证。

公钥认证的过程分为两个部分:

1).公钥验证:客户端首先将自己本地密钥对的公钥部分,按照字符串格式发送到服务器。服务器使用本地保存的客户端公钥,与报文中携带的客户端公钥进行比较,验证客户端持有公钥的正确性。

2).数字签名验证:如果公钥验证成功,客户端继续使用自己本地密钥对的私钥部分,对特定报文进行摘要运算,将所得的结果(即数字签名)发送给服务器,向服务器证明自己的身份;服务器使用预先配置的该用户的公钥,对客户端发送过来的数字签名进行验证。

公钥验证和数字签名验证中任何一个验证失败,都会导致本次公钥认证失败。

2.2.3服务端认证客户端相关配置

2.2.3.1 配置项目

AuthenticationMethods

PubkeyAuthentication:是否使用公钥认证,默认为yes

UsePAM:该关键字只有在移植版(RHEL)中支持,PAM为“可插拔认证模块”,一种灵活的签、授权机制,在此不细讲。

PubkeyAcceptedKeyTypes公钥认证算法(key):
ssh-ed25519
ssh-ed25519-cert-v01@openssh.com
sk-ssh-ed25519@openssh.com
sk-ssh-ed25519-cert-v01@openssh.com
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
sk-ecdsa-sha2-nistp256@openssh.com
ssh-rsa-cert-v01@openssh.com
ssh-dss-cert-v01@openssh.com
ecdsa-sha2-nistp256-cert-v01@openssh.com
ecdsa-sha2-nistp384-cert-v01@openssh.com
ecdsa-sha2-nistp521-cert-v01@openssh.com
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com

公钥认证配置方法:

1). 首先在客户端生成一个对钥:ssh-keygen -t rsa
这里使用的是rsa算法,也可以使用不推荐的dsa算法:ssh-keygen -t dsa

从上面可以看到,提示输入私钥的保护密码,我们也可以不选,直接ENTER就行了(不推荐)。

现在密钥已经生成:id_rsa(私钥)、id_rsa.pub(公钥)

如果是dsa算法生成的话:id_dsa、id_dsa.pub

2). 将公钥传到服务器的.ssh目录下
scp id_rsa.pub freeoa@hostip:/home/freeoa/.ssh/authorized_keys

3). 将/etc/ssh/sshd_config

中的rsa认证功能打开(去掉注释)
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

然后重新启动sshd就可以了,dsa算法的话同理。


2.3.对“伪服务器欺骗”的防御

2.3.1原理
用户认证机制只实现了服务器端对客户端的认证,而客户端无法认证服务器端,因此存在着“伪服务器欺骗”的安全隐患。


图 伪服务器欺骗

如上图所示,当客户端主机需要与服务器建立连接时,第三方攻击者冒充真正的服务器,与客户端进行数据交互,窃取客户端主机的安全信息,并利用这些信息去登录真正的服务器,获取服务器资源,或对服务器进行攻击。为了防止类似这样的伪服务器欺骗,SSH协议支持客户端对服务器端进行认证。服务器端在密钥交换阶段,使用自己的私钥对一段固定格式的数据进行数字签名,并将该签名发往客户端,客户端使用本地保存的服务器公钥,对签名进行鉴别,从而达到认证服务器的目的。

2.3.3相关配置

HostKey
HostKeyAlgorithms

ssh-ed25519
ssh-ed25519-cert-v01@openssh.com
sk-ssh-ed25519@openssh.com
sk-ssh-ed25519-cert-v01@openssh.com
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
sk-ecdsa-sha2-nistp256@openssh.com
ssh-rsa-cert-v01@openssh.com
ssh-dss-cert-v01@openssh.com
ecdsa-sha2-nistp256-cert-v01@openssh.com
ecdsa-sha2-nistp384-cert-v01@openssh.com
ecdsa-sha2-nistp521-cert-v01@openssh.com
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com

2.4.数据传输过程被篡改

这就需要消息认证码MAC(Message authentication code)

在密码学中,消息认证码又译为消息鉴别码、文件消息认证码、讯息鉴别码、信息认证码,是经过特定算法后产生的一小段信息,检查某段消息的完整性,以及作身份验证。它可以用来检查在消息传递过程中,其内容是否被更改过,不管更改的原因是来自意外或是蓄意攻击;同时可以作为消息来源的身份验证,确认消息的来源。消息认证码的算法中,通常会使用带密钥的散列函数(HMAC),或者块密码的带认证工作模式(如GCM,CCM)。信息认证码不能提供对信息的保密,若要同时实现保密认证,同时需要对信息进行加密。

2.4.1相关配置

Macs
支持的消息认证码(Mac)算法有:
hmac-sha1
hmac-sha1-96
hmac-sha2-256
hmac-sha2-512
hmac-md5
hmac-md5-96
umac-64@openssh.com
umac-128@openssh.com
hmac-sha1-etm@openssh.com
hmac-sha1-96-etm@openssh.com
hmac-sha2-256-etm@openssh.com
hmac-sha2-512-etm@openssh.com
hmac-md5-etm@openssh.com
hmac-md5-96-etm@openssh.com
umac-64-etm@openssh.com
umac-128-etm@openssh.com


可以通过关键字 “Macs”指定使用的算法,多个算法需要使用 英文逗号相隔。

有三种方式指定算法

方式一:Macs关键字后接算法名称,比如:KexAlgorithms hmac-sha2-256,hmac-sha2-512

表示只使用hmac-sha2-256,hmac-sha2-512这两种算法。

另外两种算法的指定格式:
方式二:Macs关键字后接算法名称,并且算法名称前带上“+”,表示在默认算法基础上,新增“+”后的算法。

方式三:Macs关键字后接算法名称,并且算法名称前带上“-”,表示在默认算法基础上,裁剪“-”后的算法。

2.5.小结

openssh通过以下4类算法,保证传输过程网络安全:
1)传输数据加密:传输加密算法(Ciphers),密钥协商算法(KexAlgorithms)
2)公钥认证算法(HostkeyAlgorithms)
3)Mac算法

查询ssh体系中的一些算法配置的方法:

-Q query_option
Queries ssh for the algorithms supported for the specified version 2.

The available features are:
    cipher (supported symmetric ciphers), cipher-auth (supported symmetric ciphers that support authenticated encryption), help (supported query terms for use with the -Q flag), mac (supported message integrity codes), kex (key exchange algorithms), kex-gss (GSSAPI key exchange algorithms), key (key types),key-cert (certificate key types), key-plain (non-certificate key types), key-sig (all key types and signature algorithms), protocol-version (supported SSH protocol versions), and sig (supported signature algorithms).
    
Alternatively, any keyword from ssh_config(5) or sshd_config(5) that takes an algorithm list may be used as an alias for the corresponding query_option.

Help:
cipher
cipher-auth
compression
kex
key
key-cert
key-plain
key-sig
mac
protocol-version
sig


3、另外的一些加固方法

3.1.使用防火墙来控制

可以使用防火墙来允许一个(段)ip地址来访问,基本的规则为:
拒绝所有ip的访问,先允许可信任的ip访问。
Accept incoming SSH connections from a trusted address.
Drop all other connections.

Iptables firewall 指令如下:
# All connectsion from address 1.2.3.4 to SSH (port 22)
iptables -A INPUT -p tcp -m state --state NEW --source 1.2.3.4 --dport 22 -j ACCEPT

# Deny all other SSH connections
iptables -A INPUT -p tcp --dport 22 -j DROP

3.2.使用'tcpwrappers'来控制
如果不想使用防火墙来控制,可以设定'tcpwrappers'从tcp连接层面上来控制ip地址的访问。前提是ssh要支持这种模式,在绝大多数系统上,几乎所有的网络应用都支持(compiled with tcpwrappers support)(不过新的Linux发行版本中不再提供此功能了)。

这需要对如下的两个文件进行修改:
/etc/hosts.allow
/etc/hosts.deny

第一个文件指定了允许本地的哪个服务允许哪些ip(段)的访问,第二个文件则相反。
示例如下:
定义了服务及可以连通的ip段
# /etc/hosts.allow
sshd: 1.2.3.0/255.255.255.0
sshd: 192.168.0.0/255.255.255.0

定义了所有ip都不允许访问sshd服务
# /etc/hosts.deny
sshd: ALL

3.3.配置sshd本身
针对不同的登录来源ip使用不同的验证方法,可以通过使用'match'指令字来实现。

PasswordAuthentication No
Match Address 192.168.1.0/24
PasswordAuthentication yes

You can restrict this to a few users (who you trust not to choose terrible passwords), for better security.
同样可在上面的基础上增加想要指定的用户,这样更安全可控些。
PasswordAuthentication No
Match Address 192.168.1.0/24 User joe,bob
PasswordAuthentication yes

ssh 服务器也有一些指令可以来配置以加强安全设置,主配置文件'/etc/ssh/sshd_config',在此可指定特定的用户可以登录。

只允许'bob'与'chris'能登录
AllowUsers bob chris

在重启ssh服务器后即可生效,如果其它用户即使密码正确也不能登录了。

只拒绝用户'badness'与'paula'登录
DenyUsers badness paula

拒绝'root'用户登录
PermitRootLogin no

这样'root'用户就不能从远程进行登录了。

通常加入这三个选项:
# Authentication:
LoginGraceTime 600
PermitRootLogin no
StrictModes yes

开启日志记录以备后查
# Logging
SyslogFacility AUTH
LogLevel INFO

3.4.堡垒机
堡垒主是专门设计用于阻止来自网络的恶意流量和攻击的安全网关。堡垒在公共网络上公开的安全代理和审计服务,通过堡垒机和限制和审计用户操作,记录用户操作,可以对可疑操作进行告警或者直接阻断从而减少对主机威胁。当两个通道建立SSH连接时,设置堡垒主机可能有助于提高安全性并保护系统。堡垒机是个非常重要的安全设备,但是同时它本身也是风险点和单点,如果堡垒机由于漏洞或者其他因素被人攻陷或者出现故障,会造成重大问题。所以保障堡垒机安全和高可用至关重要。

3.5.双因子认证(2FA)
在双因子认证的体系中,系统需要两种不同形式的身份验证才能获得访问权限。最常见的双因子验证是用户登陆时候除了输入用户名和密码外,还要通过手机短信验证码才能通登陆系统。虽然发送到移动设备的一次性密码会受到中间人 (MITM) 攻击 ,但使用第二个因子总比没有第二个因子要好。更安全的双因子认证还有硬件是安全校验卡YubiKey和Apple TouchID等。开源方法有基于google-authenticator和FreeOPT的方式以及基于freeipa的方式。

通过启用双因子验证功能,系统管理员可确保任何通过SSH登录远程系统的用户都必须使用多个容易被盗的凭据进行身份验证,可保证比单独使用密码或SSH密钥更安全。另外在国家网络安全等级保护标准中,在网络、主机等部分密码要求都明确要求了双因子认证。

3.6.公钥和SSH Certificate-based 验证
尽管基于SSH密钥身份验证是密认证的更好替代方案,可以增强远程登录过程的安全性,但它也有其潜在的障碍。例如,用户必须将私钥存储在其设备上,其设备有可能是被盗或者因为攻陷导致泄密。而且SSH证书实际上只是另一个名称的密码,私钥也可以泄露,被人利用。

为了防止私钥泄露,在生成证书时候可以设置密码保护是个很好的做法,另外将私钥保存在非常用的~/.ssh/目录也可以一定程度上避免泄露。

基于CA签发证书的SSH Certificate-based身份验证是一个更好的选择。SSH证书通过使用CA公钥来保护登录过程,同时还提供证书来验证每个密钥的身份。

通过使用这种身份验证方法,无需每次去服务器上添加用户公钥,只需在sshd_config添加一CA 的公钥信任既可以:
TrustedUserCAKeys /etc/ssh/user_ca_key.pub

同时在签发证书时候可以对签发的公钥进行用户名、时间、源地址等限制。配置成功后,访问ssh就是基于用户私钥(userss)和CA签发的cert证书(user-cert.pub)认证:
ssh -p2012 -o CertificateFile = user-cert.pub -i userss user@192.168.1.22

为了方便可以配置ssh_config简化访问时候选项设置:
Host freeoaip
HostName 192.168.1.22
Port 2012

User user
CertificateFile ~/.ssh/user-cert.pub
IdentityFile ~/.ssh/users

然后就可以使用:ssh freeoaip便可以访问了。

SSH Certificate-based身份验证提供了一种对任何计算环境进行身份验证的安全且可扩展的方法。


3.7.一些常规的SSH安全加固
使用强密码(Use a strong password),一般16位随机密码。

更改默认的侦听端口(Change the SSH default port),开放高于50000的端口,(配置文件中的"Port 22"选项改为其它值),一定记得在防火墙中开放相关端口。

只使用第二版的ssh协议(Always use protocol version 2),即配置文件中的"Protocol 2"选项(新版本中已经不存在此选项了,因为程序内已经没有了第一版协议了)。

禁止root用户登录(Disable the root login),这个大家都知道吧,即配置文件中启用"PermitRootLogin no"。

限制指定的用户能登录(Limit user access),这个要暴力破解的话也还要知道用户名(早期的版本会有对存在与不存在用户在失败登录时有不同提示的缺陷)。在配置文件中设置"AllowUsers myho freeoa"

使用key来加强验证(Use key-based for authentication),只要key的强度够高和不外泄,几乎无攻破可能。使用指令:ssh-keygen -t rsa -b 4096
具体可以参考:ssh自动登录配置

禁用密码登陆
密码认证虽然方便但是最容易被暴力攻击,也容易导致账号泄露,这可能是系统被黑的最常见的原因(root 建议密码)。应禁止使用基于密码的SSH身份验证并选择至少使用SSH密钥。禁止密码登陆方法是修改/etc/ssh/sshd_config文件,在最后增加一行:
PasswordAuthentication no

利用”AllowUsers”来限制访问
默认情况下,所有系统用户都可以使用他们的密码或公钥登录SSH,这也带来潜在安全隐患。并非所有系统用户都需要通过SSH远程登录。同限制特定用户对SSH访问极大地增强了安全性。可以通过/etc/ssh/sshd_config文件中配置来设置可以访问SSH的白名单:
AllowUsers user1 user2 freeoa

这样系统中就只能有user1 user2 freeoa三个用户可以SSH登陆。对应还有:
AllowGroups 用户组白名单
DenyUsers 用户黑名单
DenyGroups用户组黑名单