转载  服务器安全加固指南

分类:websocket 2019-12-23T22:59:18    49人阅读   
对于新部署的服务器,我们都应该采取一些基本的安全措施来保护它的环境。本篇教程简单讲解了服务器安全的一些常用保护措施,教程中提到的几项安全措施相对比较独立,我们可选择其中的几种,但仍然建议按顺序全部选择。教程主要是在 CentOS 7 环境下测试,对于其它 Linux 发行版服务器也可作为参考。

一、使用强密码

常见的密码或者简短的密码都很容易被他人暴力破解,使用强密码(包含数字、大小字母;长度大于等于16;)是一项基本的安全措施。如果觉得密码太长太复杂了记不住,我们可以使用密码管理器(推荐 KeePassXC)来生成和记录密码。对于刚创建的 CentOS 系统一般只有一个 root 登录用户,我们把 root 用户的密码改为强密码。

# passwdChanging password for user root.New password:<输入密码>Retype new password:<确认密码>passwd: all authentication tokens updated successfully.

二、启用 SELinux 模块

CentOS 7 系统的内核中有一组 SELinux(Security-Enhanced Linux,安全增强式Linux)的安全模块。它会通过 MAC(Mandatory Access Control,强制访问控制)的方式来严格控制系统程序对系统资源的使用。它包含了禁用(Disable)、宽容(Permissive)和强制(Enforcing)3种模式,建议使用强制模式。我们通过 sestatus 命令查看当前模式:

# sestatusSELinux status: enabledSELinuxfs mount: /sys/fs/selinuxSELinux root directory: /etc/selinuxLoaded policy name: targetedCurrent mode: enforcingMode from config file: enforcingPolicy MLS status: enabledPolicy deny_unknown status: allowedMax kernel policy version: 31

如上所示,SELinux 处于启动状态,并且默认模式为强制模式。如果输出 Mode from config file: permissive,则表示 SELinux 默认为宽容模式;如果只输出 SELinux status: disabled,则表示 SELinux 被禁用。对于宽容模式和禁用模式的情况,我们需要通过修改 SELinux 配置文件将其切换成强制模式,修改步骤如下:

首先,打开 SELinux 配置文件

# vi /etc/selinux/config

然后找到 SELINUX 选项,将 disable 或者 permissive 修改为 enforcing,如下所示:

SELINUX=enforcing

最后,我们使用 reboot 命令重启服务器让修改生效。

在某些特殊情况下,当我们从 Disable 模式切换成 Enforcing 模式时,会出现一堆服务无法顺利启动的情况。通过下面命令解决:

# setenforce 0 # 0为宽容模式,1为强制模式,临时的# restorecon -Rv / # 重新还原 SELinux,会输出一堆的警告信息# setenforce 1 # 切换会强制模式

三、创建新管理组用户

root 用户在 Linux 系统中具有很高的管理权限,它的一些误操作很容易对系统造成毁灭性的破坏。因此,我们最好创建一个新的管理组用户对系统进行日常的操作。创建管理组用户只要简单的两个步骤:

3.1 创建新用户

首先,我们创建一个新用户,用户名自拟,这里以 demo 用户为例,当然新用户的密码我们最好也设置为强密码。

# adduser demo# passwd demoChanging password for user demo.New password:<输入密码>Retype new password:<确认密码>passwd: all authentication tokens updated successfully.

3.2 新用户加入管理组

接着我们要将 demo 用户加入到管理组中,以便 demo 用户可以通过 sudo 命令临时获取管理组权限。在 CentOS 系统中,wheel 用户组中的用户默认可以使用 sudo 命令,因此我们可以将 demo 用户加入到 wheel 用户组中

# gpasswd -a demo wheelAdding user demo to group wheel

好了,新的管理组用户创建完成。

四、SSH 安全加固

注意注意注意: 在后续的步骤中,请使用两个的 Session 进行操作,一个用于进行安全配置,另一个用于可能配置失败后的修复工作,否则可能导致我们无法再次进行 SSH 登录。

ssh 服务(Secure Shell,安全外壳协议)是我们连接到远程服务器最常用的方式,因此,对 ssh 服务进行一些安全配置就显得很有必要。

4.1 限制登录用户

在前面的教程中,我们成功创建了一个新的管理组用户,这里我们通过禁止 root 用户登录,同时只允许 demo 用户远程登录的方式来加强系统安全。

首先,打开 ssh 配置文件

# vi /etc/ssh/sshd_config

接着,找到 PermitRootLogin 选项,去掉前面的 # 注释,并设置选项为 no 。然后在它的下一行加上 AllowUsers demo, 如下所示:

# 禁止 root 用户登录PermitRootLogin no# 允许 demo 用户登录AllowUsers demo

修改配置后,我们需要重启 ssh 服务,让配置生效

# systemctl reload sshd

最后,我们可以通过分别登录 root  demo 用户进行测试。当我们使用 root 用户远程登录时,服务器正常会返回 Access denied 拒绝访问的提示,而使用 demo 用户则可以正常登录。接下来的步骤我们都会使用 demo 用户进行操作

4.2 修改默认端口

在未修改默认端口之前,每次登录系统后,我们在系统欢迎界面上总会看到 There was xxx failed login attempt since the last successful login. 的提示,有时一天内的失败次数甚至多达千位数。在网络世界中,总是存在着一些(很多)不怀好意者,他们经常利用一些系统漏洞搞破坏活动,比如非法操控他人系统,由于 ssh 服务的默认端口为 22,这就给这些人进行系统入侵提供了一定的方便。通过修改 ssh 服务的默认端口,系统就可以在很大程度上过滤掉这些人。

1. 修改 ssh 服务配置文件

打开 ssh 服务配置文件

$ sudo vi /etc/ssh/sshd_config

找到 Port 选项,去掉前面的 # 注释,将选项设置为其它的数值,如下所示:

# 修改 ssh 服务端口,这里以21478为例Port 21478

2. 修改 SElinux

改完 ssh 服务配置文件中的端口后,当我们重启 ssh 服务时,可能会发现重启失败了,如下所示:

$ sudo systemctl restart sshdJob for sshd.service failed because the control process exited with error code. See "systemctl status sshd.service" and "journalctl -xe" for details.

我们通过 journalctl -xe 命令查看 ssh 服务日志

$ journalctl -xe...Nov 25 10:27:44 localhost.localdomain sshd[10789]: error: Bind to port 21478 on 0.0.0.0 failed: Permission denied.Nov 25 10:27:44 localhost.localdomain sshd[10789]: error: Bind to port 21478 on :: failed: Permission denied....

主要原因如上所示,发现是 ssh 服务端口绑定的问题。其实这是因为系统中的 SELinux 模块限制了 ssh 服务对端口资源的使用,我们通过 semanage 命令解决。

CentOS 系统默认没有 semanage 命令,我们通过以下命令安装:

$ sudo yum install policycoreutils-python

接着我们在 SELinux 中给 ssh 服务添加一条端口记录,然后重启 ssh 服务看看

$ sudo semanage port -a -t ssh_port_t -p tcp 21478$ sudo systemctl restart sshd$ systemctl is-active sshdactive

如上所示,ssh 服务处于 active 启动状态,这表示 ssh 服务能够正常启动了。

3. 修改 firewall

由于我们修改了 ssh 服务的默认端口,又因为 firewall 防火墙所关联的 ssh 服务端口是还是原先默认的 22,所以接下来我们需要对 firewall 服务进行相应的规则修改,否则将导致下次无法通过 ssh 服务远程登录。我们通过以下两种方式进行修改:

第一种方式是将 firewall 服务默认关联的 ssh 服务端口修改为新的端口。

我们先从 firewall 服务预先定义的配置文件中复制一份 ssh 服务的默认模板

$ sudo cp /lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml

接着打开 ssh.xml 文件

$ sudo vi /etc/firewalld/services/ssh.xml

将文件中的“”修改为“”,请注意这里的 port 对应着 /etc/ssh/sshd_config 中的 port,也就是新的 ssh 服务端口。

另一种方法是直接在 firewall 服务中加上一条新的端口规则

$ sudo firewall-cmd --permanent --remove-service ssh # 这里相当于移除了22/tcp端口success$ sudo firewall-cmd --permanent --add-port 21478/tcpsuccess

完成上面其中一种方式后,我们通过重启 firewall 服务让修改生效

$ sudo systemctl enable firewalld # 开机自启$ sudo systemctl restart firewalld

最后,我们使用 22 端口进行登录测试,正常情况是当我们通过默认的 22 端口登录时会出现 Connection timed out 连接超时的提示,而我们使用新的端口则能够正常登录连接。

4.3 Fail2Ban 工具

Fail2Ban 是一款入侵防御工具,可以有效地保护服务器免受暴力攻击。它主要根据我们给出的预先配置,然后通过扫描服务器的一些 auth 日志文件,更新防火墙规则。比如配置阻止密码错误过多的 IP 继续尝试登录服务器等等。

首先,我们需要安装 fail2ban 服务

$ sudo yum install epel-release # 添加 epel 源$ sudo yum install fail2ban

接着,对 fail2ban 服务进行配置

$ sudo vi /etc/fail2ban/jail.local

复制下面内容到 jail.local 配置文件中

[DEFAULT]# 忽略的IP,可防止自己的本地系统的 IP 被禁止ignoreip = 127.0.0.1/8,192.168.76.132# 禁止登录时长(秒)bantime = 86400# 在 fildtime (秒)时间窗口内,允许尝试登录的次数findtime = 600maxretry = 5# 使用 firewall 控制防火墙规则banaction = firewallcmd-ipset[sshd]enabled = truefilter = sshd# 这里的 port 对应着 ssh 配置里的portport = 21478# 在这里指定监听的 ssh 登录日志路径logpath = /var/log/secure

开启 fail2ban 服务

$ sudo systemctl enable fail2ban # 开机自启$ sudo systemctl start fail2ban

我们可以使用 root 用户登录测试(记住使用新端口)。由于我们之前已经禁止了 root 用户的远程登录,因此此次登录会失败,通过下面的命令检验:

$ sudo fail2ban-client status sshdStatus for the jail: sshd|- Filter| |- Currently failed: 1| |- Total failed: 1| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd`- Actions|- Currently banned: 0|- Total banned: 0`- Banned IP list:

如上所示,fail2ban 服务检测到了无效的远程登录。

在前面配置 fail2ban 服务时,如果我们没有将自己本地系统 IP 加入 ignoreip 选项参数中,从而导致本地系统 IP 被禁止,那么可以通过下面命令解禁:

$ sudo fail2ban-client set sshd unbanip <你的本地系统 IP>

4.4 间断 SSH 服务

我们可以通过定时任务命令 crontab 控制 ssh 服务状态,让 ssh 服务间断性地开启和关闭。这能降低他人扫描到 ssh 服务端口的概率,当然,也会不可避免的给我们自己带来一定的不便。

编辑定时任务

$ sudo crontab -e

添加下面的内容

# 间隔分钟开关 sshd 服务*/2 * * * * systemctl stop sshd*/1 * * * * systemctl start sshd

之后我们通过 ssh 服务远程登录时,如果出现 Connection refused 拒绝连接的提示,那就等5秒或10秒再试一次,几次尝试后就能登录成功。

4.5 登录认证方式

如果我们觉得使用密码认证登录不够安全,那么我们还能通过密钥认证、2FA 认证(Two-factor authentication,双重认证) 认证或者它们的组合进行 ssh 服务的登录认证。

4.5.1 密钥认证

密钥认证主要是通过生成公钥/私钥对,在连接过程中,由公钥进行加密,私钥进行解密进去身份认证。私钥就像我们家门的钥匙,有了它就可能登录到对应的服务器上,因此私钥我们要安全地存放起来。此外,我们可以为密钥加上一层密码来加强密钥认证的安全。

首先,在本地系统中(这里用的是Win10 的 Git Bash)我们通过 ssh-keygen 命令生成一个密钥对,默认情况下,ssh-keygen 命令会通过 RSA 算法生成一个2048位的密钥对,这里我们会使用更快更安全的 Ed25519 加密算法来生成。

$ ssh-keygen -t ed25519Generating public/private ed25519 key pair.Enter file in which to save the key (/c/Users/xxx/.ssh/id_ed25519):<直接回车,默认存放路径就行>Enter passphrase (empty for no passphrase):<输入密钥密码(强密码)>Enter same passphrase again:<确认密码>Your identification has been saved in /c/Users/xxx/.ssh/id_ed25519.Your public key has been saved in /c/Users/xxx/.ssh/id_ed25519.pub.The key fingerprint is:SHA256:LZdIXr9Il1LIPlTRIoKodB9Z4TfKYuCnZ4e3efnq7ak 76405@DESKTOP-T4FF24FThe key's randomart image is:+--[ED25519 256]--+| . +o. oo || . o +....o. . || . o.. .o.B... || .. ..+ O = . || . + S O + || + o + = . || . + o ... || o o oo. . || ooE== |+----[SHA256]-----+

如上所示,新生成的密钥对将存放到 /c/Users/xxx/.ssh 路径下。接着我们把它的公钥(.pub 后缀的那个)复制到服务器上,这主要有两种方式:

1. 使用 ssh-copy-id 命令上传方式

在本地系统中使用 ssh-copy-id 命令将指定公钥上传到服务器(示例中的服务器 IP:192.168.76.131,ssh 服务端口:21478,这些要换成你自己的)。

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub demo@192.168.76.131 -p 21478/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/c/Users/xxx/.ssh/id_ed25519.pub"The authenticity of host '[192.168.76.131]:21478 ([192.168.76.131]:21478)' can't be established.ECDSA key fingerprint is SHA256:Ur+zL3l4bAUnpztoyxkKvvpjjGSsKJehtNjV9wWagZo.Are you sure you want to continue connecting (yes/no)? <输入“yes”>/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keysdemo@192.168.76.131's password:<输入 demo 用户密码>Number of key(s) added: 1Now try logging into the machine, with: "ssh -p '21478' 'demo@192.168.76.131'" and check to make sure that only the key(s) you wanted were added.

正常情况下,公钥会成功保存在服务器用户主目录下的 .ssh/authorized_keys 文件中。通过命令查看验证:

$ cat ~/.ssh/authorized_keysssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ0f7PfrkrKjpWSymjRTi+u48NWwVuOtlTDkRFjLq9rD

2. 手动创建方式
我们也可以在服务器上使用 demo 用户手动创建 .ssh/authorized_keys 文件,步骤依次如下:

首先在主目录创建 .ssh 目录

$ mkdir ~/.ssh

然后新建打开 authorized_keys 文件

$ vi ~/.ssh/authorized_keys

复制本地系统的公钥内容到上面的文件中,最后执行下面命令来设置目录、文件的权限

$ chmod 700 ~/.ssh # 关闭非 demo 用户的所有权限$ chmod 400 ~/.ssh/authorized_keys # demo 用户只读,其它用户无任何权限$ sudo chattr +i ~/.ssh/authorized_keys # 防止文件被修改$ sudo chattr +i ~/.ssh # 防止目录被修改

公钥现在已经上传到了服务器上,有了密钥认证,我们就可以禁用掉密码认证。

打开 ssh 服务配置文件

$ sudo vi /etc/ssh/sshd_config

找到 PasswordAuthentication 选项,并设置为 no,如下所示:

# To disable tunneled clear text passwords, change to no here!#PasswordAuthentication yes#PermitEmptyPasswords noPasswordAuthentication no

重启 ssh 服务使修改生效

$ sudo systemctl restart sshd

最后我们新建一个 Session 连接,远程登录 demo 用户。

如果出现 Connection refused 的提示,那么可能是 间断 SSH 服务的原因,稍后再试就行。

正常情况下,如果在前面生成密钥对的时候,密钥密码设置为空,则会直接密钥登录,否则在登录时会提示输入密钥密码,提示如下所示:

$ ssh demo@192.168.76.131 -p 21478Passphrase for OpenSSH private key:<输入密钥密码>

输入正确的密钥密码后,密钥认证登录成功。

4.5.2 2FA 认证

2FA 认证使用两种不同的验证方式,合并在一起,来确认使用者的身份。例如接下来要讲的在前面密钥认证的基础上,再加上一个 TOTP 密码(Time-Based One Time Password,基于时间的一次性密码)进行认证。

我们主要需要用到2样东西:Google 身份验证器服务端组件以及一个支持 TOTP 算法的客户端(前面推荐的 KeePassXC 正好也支持 TOTP 算法).

1. 安装和配置 Google 身份验证器服务端组件

首先,我们来安装 Google 身份验证器服务端组件( 组件位于 epel 软件库,因为 epel 源前面安装过了,这里就不必安装了)

$ sudo yum install google-authenticator

接着,开始配置 google-authenticator 及生成验证密钥

$ google-authenticatorDo you want authentication tokens to be time-based (y/n) <输入"y">

之后会输出几样东西:

  1. 指向一个二维码的 Google 链接
  2. 二维码
  3. TOTP 密钥(secret key)
  4. 验证码(verification code)应该是当前时间的 TOTP 密码,没什么用
  5. 备用密码(emergency scratch codes)

其中1、2、3都是 TOTP 密钥,而5一般用来预防 TOTP 客户端不能使用时,作为一次性的备用密码登录服务器,建议安全地保存起来。现在我们使用 TOTP 客户端扫描二维码或直接复制 TOTP 密钥来设置 TOTP,如果你使用的是 KeePassXC 密码管理器,则添加步骤如下:

  1. 点击新建项目添加新项目,或者找到之前记录demo 用户密码的项目
  2. 右键项目,选择 Time-base time-on password 选项
  3. 选择设置 TOTP 密码,在密钥框内填入上面的 TOTP 密钥
  4. 点击 ok

现在我们再右键项目,选择 Time-base time on password 选项,会多出 复制 TOTP 密码  显示 TOTP 密码 的选项。

设置完客户端后,我们接着完成服务器的设置

Do you want me to update your "/home/demo/.google_authenticator" file? (y/n) <是否更新“.google_authenticator”文件,输入“y”>Do you want to disallow multiple uses of the same authenticationtoken? This restricts you to one login about every 30s, but it increasesyour chances to notice or even prevent man-in-the-middle attacks (y/n) <是否禁止同一密码被多次使用,输入“y”,可加强防御中间人攻击>By default, a new token is generated every 30 seconds by the mobile app.In order to compensate for possible time-skew between the client and the server,we allow an extra token before and after the current time. This allows for atime skew of up to 30 seconds between authentication server and client. If youexperience problems with poor time synchronization, you can increase the windowfrom its default size of 3 permitted codes (one previous code, the currentcode, the next code) to 17 permitted codes (the 8 previous codes, the currentcode, and the 8 next codes). This will permit for a time skew of up to 4 minutesbetween client and server.Do you want to do so? (y/n) <是否开启时间容错机制,密码通常是30s生成一次,输入“y”,可防止客户端和服务器之间时间偏差导致的认证失败>If the computer that you are logging into isn't hardened against brute-forcelogin attempts, you can enable rate-limiting for the authentication module.By default, this limits attackers to no more than 3 login attempts every 30s.Do you want to enable rate-limiting? (y/n) <是否开启暴力破解防护,输入“y”,每30s至多能够尝试登录3次>

配置完成后,系统会在 demo 用户的主目录下生成 .google_authenticator 配置文件

$ cat ~/.google_authenticatorNJXGKESETNBRL64QZ6K5P5DNYI" RATE_LIMIT 3 30" WINDOW_SIZE 17" DISALLOW_REUSE" TOTP_AUTH3354865589468080239487052112689420821495

2. 配置 SSH 服务

打开 PAM 配置文件:

$ sudo vi /etc/pam.d/sshd

在文件最后一行加上下面内容:

auth required pam_google_authenticator.so

如果文件中有 auth substack password-auth 这一行,需要在它的前面添加 # 注释,否则登录的时候会要求输入用户密码。

接着,打开 ssh 服务配置文件

$ sudo vi /etc/ssh/sshd_config

选项修改如下所示:

ChallengeResponseAuthentication yesUsePAM yes# 中间逗号表示且,如果是空格表示或AuthenticationMethods publickey,keyboard-interactive:pam

重启 ssh 服务让修改生效

$ sudo systemctl restart sshd

最后我们通过新建 Session 连接检验,正常情况如下所示:

$ ssh demo@192.168.76.131 -p 21478 -i ~/.ssh/id_ed25519Enter passphrase for key '/c/Users/xxx/.ssh/id_ed25519':<输入密钥密码>Verification code:<输入 TOTP 密码>

4.6 其它

下面是一些 ssh 服务配置建议清单:

# 修改 SSH 服务端口,自拟Port 21478# 仅用 IPv4ListenAddress inet# 使用 SSH v2 协议版本Protocol 2# 指定支持的数据加密算法Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr# 指定支持的消息摘要算法,用于数据校验MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com# 指定支持的密钥交换算法KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256# 服务器主机私钥存放的位置#HostKey /etc/ssh/ssh_host_dsa_key#HostKey /etc/ssh/ssh_host_ecdsa_keyHostKey /etc/ssh/ssh_host_rsa_keyHostKey /etc/ssh/ssh_host_ed25519_key# 登录时,用户必须在1分钟内输入正确密码,否则断开连接LoginGraceTime 60# 禁止 root 用户登录PermitRootLogin no# 允许 demo 用户登录AllowUsers demo# 登录前需对用户主目录和相关文件的权限和所有权进行检查# 例如:如果 authorized_keys 文件权限为777,就不能进行密钥认证。StrictModes yes# 每次连接最大允许失败登录的次数MaxAuthTries 2# 同一地址最大允许的 Session 连接数MaxSessions 3# 禁止空密码用户登录PermitEmptyPasswords no# 允许密钥认证PubkeyAuthentication yes# 如果未使用 2FA 认证,就都设置为 noChallengeResponseAuthentication yesUsePAM yes# 密钥认证,2FA 认证同时使用,中间逗号表示且,空格表示或AuthenticationMethods publickey,keyboard-interactive:pam# 禁用未使用的认证方式PasswordAuthentication noRSAAuthentication noRhostsRSAAuthentication noKerberosAuthentication noGSSAPIAuthentication noHostbasedAuthentication noIgnoreUserKnownHosts yesIgnoreRhosts yes# 禁止代理转发、端口转发和 X11 转发AllowAgentForwarding noAllowTcpForwarding noX11Forwarding no# 权限分离,防止通过有缺陷的子进程提升权限UsePrivilegeSeparation sandbox# 禁止处理 ~/.ssh/environment 以及 ~/.ssh/authorized_keys 中# 的“environment=”选项。如果设置为 yes,可能导致用户有机会使用某# 些机制(比如 LD_PRELOAD)绕过访问控制,造成安全漏洞PermitUserEnvironment no# 禁止对客户端地址进行反向解析,虽然降低一定的安全性,但提高认证了速度UseDNS no

五、总结

这篇教程中介绍了几种加强服务器安全的措施,包括了使用强密码、启用 SELinux 模块、使用新的管理组用户进行日常操作,以及通过修改 ssh 服务配置、firewall、fail2ban 和多种登录认证方式来加固 ssh 服务。当然,除了以上这些,还有很多其它没有提及的安全措施,日常及时更新软件修复漏洞,尽量关闭不使用的服务减少端口暴露等等。最后一句话:没有绝对的安全,但安全意识还是要有的。


知识共享许可协议
版权声明:知识共享署名-非商业用途 4.0 国际许可协议
原文链接:https://liamlin.me/2018/11/27/security-hardening-guide-on-centos-7

分享到: