为什么要做安全防护?

Linux 服务器的安全防护是一个纷繁复杂的巨大课题。无数的网站、APP、服务、甚至线下基础设施都建立在 Linux 的基石之上,这背后牵涉到巨大的经济利益和商业价值,当然也就就意味着黑灰产有巨大的攻击动力。但是这些服务是如此重要、根本不允许出现重大的安全漏洞。于是无数的运维专业人员都在安全攻防的战场上拼搏努力,这才让大家能享受到基本稳定的现代化数字生活。

现在,你拥有了一台 VPS,并且将会敞开他的数据访问渠道来达到流量转发的目标,那就相当于你已经置身于安全攻防战场的第一线、直面所有风险。但与此同时,新人由于知识和信息的不足,看待安全问题是总是难免两极分化:要么觉得轻如鸿毛和自己没有半点关系,要么觉得重于泰山甚至惶惶不可终日。

  • 对于前者,我的建议是:安全无小事,尽量多查一些安全方面的信息,免得自己真的受了损失才后悔莫及
  • 对于后者,我的建议是:不用紧张,我们的服务器仍不具有太高的价值、一般不会吸引到高水平的攻击,需要面对的基本都是一些自动化脚本的恶意扫描和登录尝试,跟着本文做一些基础的防护即可

具体的风险到底是什么

任何人只需要知道 【IP 地址】+【端口】+【用户名】+【密码】这四个要素,就能登录你的 VPS 服务器。那很显然,这四要素的安全就是我们要防护的底线。我们来逐一分析:

  1. 【IP 地址】:恶意脚本会随机尝试和扫描 IP 段,可以简单认为是公开信息、无法隐藏

  2. 【端口】:如果使用默认端口,那么【端口 = 22

  3. 【用户名】:如果使用默认用户,那么【用户名 = root

  4. 【密码】:密码不存在默认值,一定是由 VPS 后台随机生成或由你自行设置的。也就是说,如果你的服务器都是默认设置,则四要素中的三个已经是已知的,那么你整个服务器的安全,就全部寄托在一串小小的密码上了。这时有几种情况:

    • 如果你用了 VPS 管理后台随机生成密码,它一般包含随机的十几个大小写混杂的字母和符号,相对比较安全
    • 如果你为了好记、把密码改成了类似 123456这种超弱的密码,破解你的 VPS 服务器可谓不费吹灰之力
    • 如果你为了好记、把密码改成了比较复杂、但在别的地方用过的密码,其实也并不安全。你要明白黑客手里有作弊器,比如说 密码表,包含数万、数十万、数百万甚至更多曾经泄漏的真实密码)
  5. 但你要明白,没有哪个黑客真的要坐在电脑前一次一次的尝试你的密码,全部的攻击尝试都是恶意脚本自动进行的,它会 24 小时不眠不休的工作。也许每天你酣睡之时,你的服务器都在经受着一轮又一轮的冲击。

    一旦密码被成功撞破,意味着你的四要素全部被攻击者掌握,恶意脚本就会快速登录服务器、获取服务器的最高 root 控制权、安装部署它的恶意服务,然后就可以用你的服务器来 24 小时做各种坏事(比如挖矿、传播病毒、发送垃圾邮件、欺诈邮件、做 BT 中继、甚至暗网公众节点等等等等)。如果恶意脚本比较克制,其实可以做到相当的隐蔽性。而新人一般也不会去观察留意 VPS 的登录记录、进程变化、CPU 占用变化、流量变化等指标,你其实就很难发现自己被黑了。直到你的 VPS 服务商封禁你的账号、或者收到律师函为止。

  6. 别忘了,你获得 VPS 时大概率需要使用真实的支付信息,你登录各种网站、社交平台时也会留下你的 IP 地址,这些都与你的身份有直接或者间接的关系。于是,一旦这些坏事发生,它们就不可避免的与你产生了关联。

基于上述分析,我们要做的,自然就是对【端口】、【用户名】、【密码】这三要素进行加强,来降低被攻破的风险

开始配置

1. 安装UFW防火墙

在对三要素进行加强前,你需要确认防火墙是否已经安装。若直接修改SSH端口,预置的防火墙将会拒绝你使用新端口访问

UFW(Uncomplicated Firewall)是一个用于简化防火墙配置和管理的工具,常见于基于 Debian 的 Linux 发行版,如 Ubuntu。对于这些发行版,UFW 通常已经包含在默认的包管理系统中,但不一定默认安装和启用。

  1. 检查是否已安装 UFW

你可以使用以下命令检查系统中是否已经安装了 UFW

ufw status

如果 UFW已安装且未启用,你会看到如下输出:

Status: inactive

如果未安装,你会收到类似于“command not found”的错误消息。

  1. 安装 UFW

如果 UFW未安装,可以使用以下命令进行安装:

apt update
apt install ufw
  1. 启用 UFW

安装后,可以使用以下命令启用 UFW

ufw enable
  1. 配置 UFW 规则

你可以使用以下命令来配置 UFW规则:

ufw allow 22/tcp         #放行22端口
ufw delete allow 22/tcp  #阻止22端口
  1. 禁用 UFW

如果需要禁用 UFW,可以使用以下命令:

ufw disable
  1. 检查 UFW 状态
ufw status

这会显示当前的防火墙状态以及所有的已配置规则。

2. 更改 SSH 端口

第一步,我们先来解决【端口 = 22】的问题。(注意:有些 VPS 服务商,默认的端口已经是非 22 端口,那么你可以忽略这一步,当然也可以跟着本文改成别的端口)

我们要做的第一件事,当然就是【用 nano 这个文本编辑器打开SSH远程登录程序设置】,在 Windows 下,你会【找到文件并双击】,在 Linux 下该怎么办呢?仔细看看上面的命令说明,是不是就很简单了?没错,就是:

nano /etc/ssh/sshd_config

文件打开后,你就进入了 nano 的界面,稍微观察一下,你会发现,它把重要的快捷键都显示在屏幕下方了(下图红框内),直接开卷考试、不用死记硬背,是不是很贴心呢?

我们要做的第二件事,是【在打开的文件中找到 Port 这一项,并修改它的端口】。Port 后面的数字就是 SSH 的端口,一般建议把它改成一个大于 1024小于 65535 的整数(本文以 2333 为例)。结合 nano 的快捷键,想一下该怎么操作呢?

使用 ctrl+w 进入搜索模式,然后输入 Port 22 并回车

删除 22 并改成 2333

说明:如果这一行开头有个 #,证明这一行【不生效】(被注释掉了),你可像我一样在文件最后写一个不带 #的,或者把 #删掉就好。

我们要做的第三件事,是【保存文件并退出】

如果第 3 步你有仔细观察,就会发现保存并不是常见的 ctrl+s。
正确的快捷键:保存是 ctrl+o + 回车,退出是 ctrl+x

在进行下一步前,不要忘记修改防火墙配置

ufw allow 2333/tcp comment 'SSH'   #添加2333为新端口
ufw delete allow 22/tcp            #删除22端口

再次查看 UFW 状态

ufw status

可以看到规则已进行了更新

webs11

我们最后要做的事,是【重启 SSH 服务,使变更生效】

service sshd restart

3. 使用复杂的密码

如果你想给当前的用户设置重设密码,那么可以到这个网站,生成一个复杂的密码,当作你服务器的密码。

https://1password.com/zh-cn/password-generator/

  1. 修改 root 密码
passwd

出现提示让你修改密码。然后粘贴进去就行了。

注意为了安全的考量,Linux下输入密码是没有显示的

新建普通用户

接下来,我们来解决【用户名 = root】的问题。

首先你要理解, Linux 系统中的 root,不仅仅是一个管理员账号那么简单。它是整个系统的【根基】、是系统的主宰、至高无上的神。一旦 root 账号出现安全问题,整个系统都只能任人鱼肉、无处可逃。那么就跟随我进行操作吧:

我们要做的第一件事,是【新增一个用户并设定登录密码】,名字你可以随便起,我这里以 botai为例:

adduser botai 
adduser botai 10RLvEg43Xhmt5rg1tU7

执行命令后,根据提示操作即可。请务必设置一个用户密码(别忘记设置密码时你时看不到 ****** 的)。之后系统会询问你一些用户的附加信息,这些就可以无视,一路回车即可。

webs12

我们要做的第二件事,是【安装 sudo 功能】( sudo 就是在关键时刻,让普通账户临时获得 root 的神力,战力全开拯救世界)

apt update && apt install sudo  #Debain默认没有,Ubuntu自身应该是已经有安装的

聪明的你大概已经发现,这一行命令其实是两个命令。前一半 apt update 你之前已经见过并且用过了,是去服务器刷新软件版本信息。后面的 apt install就是这一次要用到的【安装命令】。两条连接在一起,就是让系统去【刷新可用的最新软件,然后安装最新版的 sudo 程序】。 && 则是把两个命令连起来执行的意思。

我们要做的第三件事,是【把用户 botai 加入 sudo 名单里,让他有资格借用 root 的神力】

visudo

User Privilege Specification 下加入一行 botai ALL=(ALL) NOPASSWD: ALL 即可。

我要特别说明的是 NOPASSWD 这个设置,它的意思是用户临时使用 root 权限时,不用额外输入密码。这与一般的安全建议相反。我之所以如此推荐,是因为很多新人不顾危险坚持使用 root 账号就是因为用 root 时不用重复输入密码、觉得轻松。“两害相权取其轻”,我认为【直接用 root 用户的风险】大于【使用 sudo 时不用输密码的风险】,所以做了以上的建议。如果你希望遵守传统习惯、每次使用 sudo 时需要输入密码,那么这一行改成 vpsadmin ALL=(ALL:ALL) ALL 即可。

4. 禁止 root 登陆

现在你已经逐渐熟悉 Linux 了,所以这次换你思考,我们要做的第一件事是什么呢?没错,还是【用 nano 编辑器打开 SSH 远程登录程序设置】,什么,你想不起来怎么操作了?那去复习一下上面的内容再回来吧!............ 正确答案:

nano /etc/ssh/sshd_config

找到 PermitRootLogin Yes 这一项,然后把它后面的设定值改为 no即可。还记得怎么操作吗?............ 正确答案:

使用 ctrl+w 进入搜索模式,然后输入 PermitRootLogin 并回车

删除 yes 并改成 no

保存文件并退出。还记得怎么操作吗?............ 正确答案:

保存是 ctrl+o,然后 回车 确认退出是 ctrl+x
重启 ssh 服务,让变更生效。还记得............ 算了直接公布正确答案:

sudo service sshd restart

下次通过远程登录,root 用户已无法连接,

用户名就要换成 botai了!如果你用的是类似 PuTTY、FinalShell 的软件,为方便起见,我们可以把 botai设置成默认登录用户名。(别忘了保存 Session)

ssh botai@你的服务器IP -p 2333   #2333是你定义的SSH端口

5. 启用 RSA 密钥验证登录并禁止密码登陆

接下来,我们来解决【密码】可能被撞破的问题。

前面我说过,黑客并不是很蠢的用穷举法破解你的密码,而是会用一些比如“密码表”的作弊手段。除非你用的是随机生成的超长密码(比如借助 1Password,或者 macOS 的 keychain 等密码管理工具),否则很容易中招。

超长随机密码虽然安全性有所提高,但是基本上无法记忆,手动输入也十分麻烦易错。为了解决这个困境,我们可以直接弃用【密码验证】方式,改用更安全的【密钥验证】。

所谓的【密钥验证】,就是生成【一对】相关联的密钥文件(公钥和私钥),然后把【公钥】上传到 VPS 备用。每次登录时,SSH 会将【公钥】和【私钥】进行匹配,若验证是正确的【密钥对】,则验证通过。(换言之,你无需记忆和输入复杂的密码,只要保护好【私钥】这个文件不外泄即可)

本文以 RSA 密钥举例,是因为 RSA 密钥在各种设备、各种 SSH 客户端中有广泛悠久的支持历史,且目前依然能提供够用的安全性。但它绝非唯一选择。

其他的常见密钥还有:

  • DSA - 已经从数学层面被证明不安全,所以永远不要用它
  • ECDSA - 密钥小安全性高,但其算法被指留有 NSA 的后门,如果你的 VPS 上有值得 NSA 关注的东西就不要用它
  • Ed25519 - 这是一个与 ECDSA 十分类似的算法,故具有相似的性能优势。同时其文档全部公开,所以普遍认为无后门

所以,如果你的设备和软件都支持的话,我建议优先选择 Ed25519 密钥。

当你使用 ssh-keygen 命令生成 SSH 密钥对时,并不会自动将公钥添加到远程服务器的 authorized_keys 文件中。这个文件通常位于远程服务器上的 ~/.ssh/authorized_keys

添加 SSH 公钥到远程服务器的 authorized_keys 文件

要将你生成的 SSH 公钥添加到远程服务器的 authorized_keys 文件中,需要执行以下步骤:

  1. 生成 SSH 密钥对

    在本地计算机上使用 ssh-keygen 命令生成 SSH 密钥对:

    ssh-keygen -t rsa -b 4096 -C "myvps"
    

    webs15

    这将生成 id_rsa(私钥)和 id_rsa.pub(公钥)文件,默认存储在 ~/.ssh/ 目录中。

  2. 连接到远程服务器

    使用 SSH 连接到你的远程服务器,确保你有权限访问服务器:

    ssh botai@你的服务器IP -p 2333
    
  3. 创建 authorized_keys 文件

    mkdir -p ~/.ssh
    touch ~/.ssh/authorized_keys
    
  4. 添加公钥到 authorized_keys 文件

    在本地执行:

    ssh-copy-id -i ~/.ssh/id_rsa.pub -p 2333 [email protected]
    
  5. 设置正确的文件权限

    确保 ~/.ssh/ 目录和 authorized_keys 文件的权限设置正确,通常应该是:

    chmod 600 ~/.ssh/authorized_keys
    

    这样可以确保只有你的用户可以读取这些文件。

  6. 编辑 SSH 配置文件

    sudo nano /etc/ssh/sshd_config
    

    搜索 PasswordAuthentication,把 yes 改成 no
    19

    重启 SSH 服务。(啰嗦君:别忘了现在需要使用 sudo 来获得权限)

    sudo systemctl restart ssh
    

    用另一个没有秘钥的服务器测试一下,可以看到已经无法连接了截屏2024-06-13 23.14.19

  7. 测试 SSH 登录

    现在,你可以尝试使用新生成的密钥对进行 SSH 登录:

    ssh -i ~/.ssh/id_rsa username@remote_host  
    ssh [email protected] -p 2333      #这两个都可以,我通常用下面这个
    

    这里的 -i 选项指定使用 id_rsa 私钥文件进行认证,username 是你在远程服务器上的用户名,remote_host 是远程服务器的 IP 地址或域名。

    18

    成功!现在全世界也只有这台机子能连上我的服务器了!!!

注意事项

  • 备份私钥:私钥 (id_rsa) 是你在本地计算机上的身份证明,请确保它的安全存储和备份。
  • 公钥传输:在添加公钥到服务器之前,请确保你在本地生成的公钥的内容是正确的。
  • 权限设置:确保 ~/.ssh/ 目录和 authorized_keys 文件的权限设置正确,以避免安全问题。

到这里为止,你的 VPS 已经完成了【端口】、【用户名】、【密码】这三要素的基本安全保障,虽然远称不上固若金汤,但一般的恶意脚本应该已经无法对你造成伤害了!

还没完成!让我们继续加固我们的”防线“

6. 禁止 Ping

禁止 ICMP echo 请求(ping)到服务器可以有以下几个理由:

  1. 减少暴露
    禁止 ping 可以防止潜在攻击者轻易发现你的服务器存在。ping 请求是网络扫描工具中最常用的方法之一,通过禁止 ping,可以在一定程度上隐藏服务器的存在,增加被发现的难度。
  2. 防止 DDoS 攻击
    ICMP echo 请求可以被滥用于 DDoS 攻击(如 Ping Flood )。通过禁止 ping,可以减少这种类型的攻击对服务器的影响。
  3. 减少不必要的流量
    在高流量环境中,ping 请求可能会消耗一定的带宽和服务器资源。虽然单个 ping 请求的资源占用很小,但如果有大量的 ping 请求,可能会影响服务器性能。
  4. 更严格的管理策略
    禁止 ping 可以作为网络策略的一部分,确保只有经过身份验证的用户或设备才能与服务器通信。这有助于网络管理员更好地管理和监控网络流量。

尽管如此,禁止 ping 也有其缺点,特别是在网络诊断和故障排除时。如果决定禁止 ping,需要权衡安全性与便利性之间的利弊。可以选择在某些环境中禁用 ping,而在受控环境或内部网络中保持 ping 的可用性,以便于管理和诊断。

sudo nano /etc/ufw/before.rules

搜索:echo-request,把 ACCEPT改成 DROP

ping1

重新加载 UFW 规则:

sudo ufw disable
sudo ufw enable

重新启用 ping

如果你需要重新启用 ping 请求,只需将之前修改的 DROP 改回 ACCEPT

-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT

7. 安装 Fail2ban 禁止暴力破解

  1. 安装
sudo apt update && sudo apt install fail2ban
  1. 进入 Fail2ban 目录
cd /etc/fail2ban
  1. 复制一份配置文件
sudo cp jail.conf jail.local
  1. 检查一下
ls

ban1

  1. 编辑配置文件
sudo nano fail2ban.local

[sshd] 的位置添加以下内容,具体数值可以根据自己实际情况自行设置

[sshd]

enable = true
port    = 2333
filter = sshd
logpath = %(sshd_log)s
backend = %(sshd_backend)s

maxretry = 5  #最大尝试次数
bantime = -1  #按秒算 -1则为永久

应该还记得怎么保存吧?(忘了的话向上翻翻)

  1. 启动和启用 Fail2ban 服务
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
  1. 查看一下状态
systemctl status fail2ban

ban3

如果你的 Fail2ban 启动失败(系统使用 Debian12),原因可能是找不到日志文件,你可以尝试安装:

sudo apt install rsyslog
sudo apt install iptables

然后重新启动并查看状态

sudo systemctl restart fail2ban
systemctl status fail2ban
  1. 其他命令
sudo fail2ban-client status sshd #查看sshd的详细状态
sudo fail2ban-client set sshd unbanip 0.0.0.0 #解禁指定IP

现在我们终于有了一个安全的系统基础,下一章,我们就可以开始逐步配置需要的基础设施了!(什么基础设施呢?一个网页,一张证书)

参考资料

https://techguides.yt/guides/secure-linux-server/

https://xtls.github.io/document/level-0/ch04-security.html#_4-7-%E4%BD%BF%E7%94%A8-rsa-%E5%AF%86%E9%92%A5%E7%99%BB%E5%BD%95%E5%B9%B6%E7%A6%81%E7%94%A8%E5%AF%86%E7%A0%81%E7%99%BB%E5%BD%95