保卫 OpenSSH

OpenSSH(或者 Secure Shell)以经成为一个取代 telnet 协议作远程访问用的现有标准。SSH 已经令 telnet 等协议多余的,当中绝大部份原因是由于连接被加密,以及不再以纯文本公开地传送口令。

然而,缺省的 ssh 安装并非完美。当你营运一个 ssh 服务器时,有数个简单的步骤可以明显地加固你的安装。

1. 采用难猜测的口令/用户名称

如果你所营运的 ssh 是对外的,你首先会发现的事情,很可能就是骇客尝试猜测用户名称/口令的记录。骇客一般会扫描端口 22(ssh 缺省聆听的端口)来找寻执行 ssh 的机器,然后尝试强行攻击它。借着使用难猜测的口令,我们希望任何攻击在成功前会被记录底及被留意到。

盼望你已经采用了难猜测的口令。要不然,请尝试选拥有以下特征的口令:

使用难测口令的好处并不止于 ssh,它更会影响到系统安全的各个范畴。有关口令的更多信息可以在 CentOS 的文档内找到:

http://www.centos.org/docs/4/html/rhel-sg-en-4/s1-wstation-pass.html

如果你完全没法阻止你的用户选用易猜测的口令,请考虑以随机产生或难猜测的符串作为用户名称。如果坏人不能猜测用户名称,他们便不能强加猜测口令。然而,这只是隐晦信息来换取安全,所以要留心用户名称通过用户发送的电邮等途径而被泄漏。

2. 停用 root 登录

SSH 服务器的设置都存储在 /etc/ssh/sshd_confg 这个文件。要停用 root 登录,请确定你有以下一行:

# 阻止 root 登录:
PermitRootLogin no

然后请重新引导 sshd 服务:

service sshd restart

你果你需要 root 的权限,请登录为一般用户,然后使用 su 这个指令。

3. 限制用户登录

SSH 登录可以局限给某些需要远程访问的用户。如果你的系统有很多用户,一个合理的做法就是局限远程访问给那真正有需要的用户,藉以减低其它用户采用易测口令的影响。在 /etc/ssh/sshd_config 内加入 AllowUsers 一行,以空格隔开用户名称。例如:

AllowUsers alice bob

接着请重新引导 sshd 服务。

4. 停用第 1 类协议

SSH 可以采用两款协议:第 1 类及第 2 类协议。较旧的第 1 类协议的安全性较低,因此它应该被停用,除非你知道你必须要使用它。请在 /etc/ssh/sshd_config 档内找寻以下一行,解除注释,并作出如下修改:

# Protocol 2,1
Protocol 2

然后请重新引导 sshd 服务。

5. 采用非标准的端口

根据缺省值,ssh 在端口 22 聆听进入的连接。一个骇客如果要断定 ssh 是否在你的机器上运行,他最大可能就是扫描端口 22。一个有效混淆他的方法就是在非标准的端口上运行 ssh。任何未被使用的端口都可行,但首选的是 1024 以上的。很多人选用 2222 作为替换的端口(它很易记),正如 8080 经常被用作 HTTP 的替换端口。正正由于这个原因令它不是个好的选择,因为任何扫描端口 22 的骇客亦不会放过端口 2222。随机地选用一个未被使用的高位端口会比较合宜。要进行改动,请在你的 /etc/ssh/sshd_config 档内加入以下一行:

# 在非标准的端口上执行 ssh:
Port 2345  #修改我

然后重新引导 sshd 服务。请勿忘记在你的路由器及相关的防火墙规则里作出任何必要的改动。譬如在 CentOS 7 你需要更改 firewalld:

$ firewall-cmd --add-port 2345/tcp
$ firewall-cmd --add-port 2345/tcp –permanent

又或者在 CentOS 6:

$ iptables -I INPUT -p tcp --dport 2345 -j ACCEPT

在 CentOS 6 及以上版本,你亦需要更新 selinux,并正确地标签所选用的端口,否则 sshd 便不能访问它。举个例说:

$ semanage port -a -t ssh_port_t -p tcp 2345 #请更改这处 

因为 ssh 不再在标准的端口上聆听连接,你须要告诉客户端要连接到哪个端口。在命令行上执行 ssh 客户端时,你可以用 -p 选项来指定端口:

$ ssh -p 2345 myserver

又或者如果你使用 konqueror 的 fish 协议,你可用:

fish://myserver:2345/remote/dir

如果你觉得每次连接时都要指定端口似乎很痛苦,你只需在你个人的 ~/.ssh/config 文件里加入一个指定端口的记录:

 # 客户端 ~/.ssh/config
Host myserver
HostName 72.232.194.162
        User bob
        Port 2345

~/.ssh/config 必须有以下访问权:

$ chmod 600 ~/.ssh/config

6. 在防火墙过滤 SSH

如果你只须由一个 IP 地址进行远程访问(例如由办工室进入家中的服务器),请考虑在你的路由器或 iptables 内加入一条防火墙的规则,将端口 22 的访问权限制到特定的 IP 地址,藉此对连接进行过滤。举个例说,在 iptables 内你可以用这类型的规则达至这个目的:

iptables -A INPUT -p tcp -s 72.232.194.162 --dport 22 -j ACCEPT

SSH 亦对 TCP 包装函式有内置支持,因此 ssh 服务的访问权亦可同时用 host.allow 及 hosts.deny 来进行管制。

如果你不能限制来源地的 IP 地址,而必须公开 ssh 端口,那么 iptables 依然可以通过记录及拦截来自同一 IP 地址的重复登录尝试,帮助你阻止强行的攻击。例如:

iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name ssh --rsource
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent ! --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j ACCEPT

第一条规则利用 recent 模块来记录每个访问端口 22 的新尝试。第二条规则检查这个 IP 地址在过去 60 秒内有否尝试 4 次或以上的连接,若然没有更接纳封包。注意这个规则须要输入链采用 DROP 的缺省政策。

如果你在非标准的端口上执行 ssh,请不要忘记对端口作出相应修改。情况许可的话,利用防火墙进行过滤是一个非常有效的方法来保卫 ssh 服务器。

采用 FirewallD 服务的系统,可执行下列 firewall-cmd:

firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT_direct 0 -p tcp --dport 22 -m state --state NEW -m recent --set
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT_direct 1 -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 30 --hitcount 4 -j REJECT --reject-with tcp-reset
firewall-cmd --reload 

7. 采用公钥/私钥来验证

采用加密金钥来验证提供两大好处。首先,如果你应用公钥/私钥,是方便,因为你不用再输入口令(除非你用口令来保护你的金钥)。第二,当服务器能进行金钥对的验证,你便可以完全停用口令验证,意即访问时靠赖授权的金钥 —— 因此不再有猜测口令的尝试。

创建及在你的 ssh 服务器上安装金钥对是个相对地简单的过程。

首先,在你会用来连接到服务器的客户端上创建一对金钥(你须要在每台用来连接的机器上这样做):

$ ssh-keygen -t rsa

这样做会在你的(隐藏了的)~/.ssh 目录内置立两个文件,名叫:id_rsaid_rsa.pub。第一个文件:id_rsa 是你的私钥,而另一个:id_rsa.pub 是你的公钥。

如果你不想每次连接时都被问及密码(它是用来解开特定的公钥),在创建金钥对的时候,你只须按 enter 作为密码。创建金钥对时,是否以密码加密纯粹是你的决定。如何你不将金钥加密,任何人夺得你的本地机器后,便自动拥有远程服务器的 ssh 访问权。此外,本地机器上的 root 能够访问你的金钥:但假若你不能信任 root(或者 root 已被攻占),你已经大祸临头。将金钥加密舍弃了不用密码的 ssh 服务器,来换取额外的安全,得来的就是输入密码来使用这条金钥。你可利用 ssh_agent 这个程序进一步简化这个程序。

现在为你的私钥设置权限:

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/id_rsa 

请将公钥(id_rsa.pub)复制到服务器上,然后安装它在 authorized_keys 清单内:

$ cat id_rsa.pub >> ~/.ssh/authorized_keys

注:一旦你输入了公钥,你可以在服务器上删除它。

最后,设置服务器上的文件权限:

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

如果 /etc/ssh/sshd_config 内的 StrictModes 被启用(缺省值),以上的权限是必须的

请确保你已设置正确的 SELinux 脉络:

$ restorecon -Rv ~/.ssh 

现在当你登录服务器的时候,你便不用再输入口令(除非你在创建金钥对的时候输入了一个口令)。ssh 缺省是会先利用金钥进行验证。如何它找不到金钥,或验证失败,ssh 会回落到平常的口令验证。

一旦你检查过可以用金钥对来登录服务器,你可以在你的 /etc/ssh/sshd_conf 档内加入以下设置来停用口令验证:

# 停用口令验证,强制使用金钥
PasswordAuthentication no

8. 常见问题(FAQ)

问:CentOS 采用 X 版的 OpenSSH,而最新版本是 Y 版。X 版藏有一个严重的安全性漏洞,我应否升级?

答:不应该。上游供应者有一个政策,会将最新版本的安全性修正反向移植到现有的发行版本内。只要你拥有最新的更新,你的 CentOS 发行版本已经得到全面修正。有关反向移植安全性修正的详情,请参阅这里:

http://www.redhat.com/advice/speaks_backport.html

问:我如何令 ssh 容让以 NFS 共享用户主目录的机器采用无密码的验证?

答:SELinux 预设拦阻 root 存取以 NFS 共享、非公用的目录及档案,因此 ssh 无法读取 ~/.ssh 内的用户金钥档。若要批准存取权,请用以下指令更改 use_nfs_home_dirs 的设定值:

setsebool -P use_nfs_home_dirs 1 

https://www.centos.org/forums/viewtopic.php?t=49194

9. 连结

http://www.centos.org/docs/5/html/Deployment_Guide-en-US/ch-openssh.html

http://www.dragonresearchgroup.org/insight/sshpwauth-tac.html

Translation of revision 51

zh/HowTos/Network/SecuringSSH (last edited 2017-11-07 08:48:46 by TimothyLee)