保卫 OpenSSH
<<TableOfContents: execution failed [Argument "maxdepth" must be an integer value, not "[1]"] (see also the log)>>
OpenSSH(或者 Secure Shell)以经成为一个取代 telnet 协议作远程访问用的现有标准。SSH 已经令 telnet 等协议多余的,当中绝大部份原因是由于连接被加密,以及不再以纯文本公开地传送口令。
然而,缺省的 ssh 安装并非完美。当你营运一个 ssh 服务器时,有数个简单的步骤可以明显地加固你的安装。
1. 采用难猜测的口令/用户名称
如果你所营运的 ssh 是对外的,你首先会发现的事情,很可能就是骇客尝试猜测用户名称/口令的记录。骇客一般会扫描端口 22(ssh 缺省聆听的端口)来找寻执行 ssh 的机器,然后尝试强行攻击它。借着使用难猜测的口令,我们希望任何攻击在成功前会被记录底及被留意到。
盼望你已经采用了难猜测的口令。要不然,请尝试选拥有以下特征的口令:
- 最少有 8 个字符
- 同时有大写和小写字母
- 同时有字母和数目字
- 有非英数的字符(例如 ! " £ $ % ^ 等特别字符)
使用难测口令的好处并不止于 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 在 /etc/firewalld/ 内的服务档,然后更改 ssh 服务的端口:
$ cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh-custom.xml
请更改 /etc/firewalld/services/ssh-custom.xml 令端口与 ssh 配置文件内的相同:
<port protocol="tcp" port="2345"/>
最后,删除 ssh 服务,新增 ssh-custom 服务,并重启 firewalld 令改动生效:
$ firewall-cmd --permanent --remove-service='ssh' $ firewall-cmd --permanent --add-service='ssh-custom' $ firewall-cmd --reload
又或者在 CentOS 6 上新增 iptable 的规则来打开新的 ssh 端口:
$ 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 规则(CentOS 6)达至这个目的:
$ iptables -A INPUT -p tcp -s 72.232.194.162 --dport 22 -j ACCEPT
又或者采用 firwalld(CentOS 7)的加强规则局限 ssh 至特定的端口。来源地址可以是单一地址或是基本地址及位元掩码:
# 视乎已启用及现存的设置,选用 ssh 或 ssh-custom $ firewall-cmd --permanent --remove-service="ssh" $ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="72.232.194.162" service name="ssh-custom" accept' $ firewall-cmd --reload
SSH 亦对 TCP 包装函式有内置支持,因此 ssh 服务的访问权亦可同时用 host.allow 及 hosts.deny 来进行管制。
如果你不能限制来源地的 IP 地址,而必须公开 ssh 端口,那么 iptables 依然可以通过记录及拦截来自同一 IP 地址的重复登录尝试,帮助你阻止强行的攻击。例如通过 iptables:
$ 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 服务的系统(CentOS 7 或以上)可使用 firewall-cmd: # 视乎已启用及现存的设置,选用 ssh 或 ssh-custom $ firewall-cmd --permanent --remove-service="ssh" $ firewall-cmd --permanent --add-rich-rule='rule service name="ssh-custom" accept limit value="4/m" log' $ firewall-cmd --reload}}} 首个指令删除较宽松的的规则,而第二个指令创建一条每分钟只指纳 4 个连接并记录所有连接的规则。
7. 采用公钥/私钥来验证
采用加密金钥来验证提供两大好处。首先,如果你应用公钥/私钥,是方便,因为你不用再输入口令(除非你用口令来保护你的金钥)。第二,当服务器能进行金钥对的验证,你便可以完全停用口令验证,意即访问时靠赖授权的金钥 —— 因此不再有猜测口令的尝试。
创建及在你的 ssh 服务器上安装金钥对是个相对地简单的过程。
首先,在你会用来连接到服务器的客户端上创建一对金钥(你须要在每台用来连接的机器上这样做):
$ ssh-keygen -t rsa
这样做会在你的(隐藏了的)~/.ssh 目录内置立两个文件,名叫:id_rsa 及 id_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 54