技术分享
💻保护你的小鸡! VPS 安全探讨分享
00 分钟
2024-8-20
2024-8-20
password
type
status
date
slug
summary
tags
category
Property
Aug 20, 2024 02:29 AM
URL
icon

前言

接触 VPS 也四年多了, 对于如何保护自己的 VPS, 也总结出一些经验, 于是写个帖子分享一下, 集思广益嘛. 做到下面的安全措施, 除非被针对性攻击, 否则服务器安全完全不是问题.
提前说一嘴, 我个人是手动管理一切, 所以 Nginx 等的配置文件都是手搓的(大家玩鸡迟早也会过渡到这一阶段). 很多新手用的宝塔, 包括我一开始也是, 方便是方便, 代价也很大. 宝塔本身权限太高, 炸个零日漏洞就是大问题, 更不用说是闭源的, 背后干啥也不知道, 会收集服务器信息上传之类的传闻也是有的. 所以逐渐熟悉 Linux 操作后我就不用了. 所以, 本文当中的命令, 建议在全新的系统中执行, 特别是新手吃不准命令的含义的时候. 当然, 如果是老手, 一看就懂啦, 我也只是总结一下.
要完全做到安全是不可能的, 绝大多数人也不是网络安全从业者, 本帖主要面向新手扫盲, 别犯会被脚本小子利用的问题就好.
以下教程涉及的命令均基于 Debian 12. 此处约定: {} 及其括起来的内容为根据你实际情况需要替换的文本内容, 括起来的内容为说明, 如 ssh {user}@{server ip} 为 ssh 连接服务器的命令, 假设用户为 root, 服务器 IP 为 114.5.1.4, 则为 ssh root@114.5.1.4

系统更新

  • 新机器到手, 应当立即进行软件包更新, 下面的教程将默认在系统所有软件包处于最新状态
apt update && apt upgrade -y && apt dist-upgrade -y && apt full-upgrade -y && apt autoremove -y
更新完成后建议重启一下: reboot
  • 仍然使用 Debian 10 或更旧版本的, 建议升级到 Debian 11 / 12. Debian 12 在我自己的 1c0.5g 的机器上也能流畅运行, 所以大可放心, 或者只升级到 Debian 11 问题不大. Debian 10 的 LTS 支持将在 June 30th, 2024 结束, 建议在此之前升级.
注意:
  • 升级大版本/更新内核是有一定机率导致 GRUB 加载失败进而启动失败的, 除非你是物理服务器, 以及没有用过奇奇怪怪定制或修改的内核的 KVM 构架的 VPS 和云主机. 切记备份重要数据!
  • OpenVZ 6 和 LXC 构架的 VPS 是无法升级的,因为没有自己独立的内核(所以, 除非灵车别碰 LXC, 老老实实买 KVM 虚拟化的机器)
  • 再强调一遍: 一定要备份重要数据!
  • 不要跨大版本升级, 一步步来, 例如从 Debian 9 升级 Debian 11, 先升级到 10, 再升级到 11, 依此类推.
完成系统更新后, 就可以下一步了.

SSH 安全篇

TL,DR: 务必配置密钥登陆, 避免使用密码登陆, 更不用说弱密码!

1. 配置密钥登陆

建议本地生成公私钥再手动上传公钥, 不要把 SSH 登陆私钥扔服务器上!
    • 下列操作在本地 Powershell 执行
    • 执行 ssh-keygen -o -a 256 -t ed25519, 此处 ed25519 是加密算法的一种, 不用理会. 提示输入将私钥保存在哪里, 默认保存在 C:\Users\{your user name}/.ssh/, 文件名 id_ed25519
  • 随后提示输入密钥密码, 最好设置一下, 输入密码后回车, 能保证私钥不泄露也可以直接回车留空. 输入密码时, 不会有显示:
  • 提示再输入一遍, 再输入一遍密码就行, 前面留空这儿也留空
  • 生成完毕, 提示公钥私钥的保存位置. 如下例子, C:\Users\Hantong/.ssh/id_ed25519.pub 就是接下来将保存到服务器的公钥, C:\Users\Hantong/.ssh/id_ed25519 就是登陆用的私钥
    • 用 Notepad 打开公钥文件 C:\Users\Hantong/.ssh/id_ed25519.pub并复制内容到剪贴板备用
    • 下列操作在 VPS 执行
  • 尝试用私钥登陆, 登陆成功证明前面的操作没问题
Powershell 执行 ssh -i "{/entire/path/to/your/privkey/with/filename}" {user}@{server ip}, 按提示来就行, 提示保存到 known_host 就 yes, 前面给私钥设置了密码提示输密码就输密码.
  • 配置 sshd_config
此处命令配置 sshd_config, 新机器无脑照搬就行, 有自定义设置的就别直接执行, cat <<'TEXT' > /etc/ssh/sshd_configTEXT 前的内容为 sshd_config 的内容, 自行手动编辑就行. 编辑前建议备份一下原来的.
到这 SSH 就非常安全啦~ 也有人建议用 fail2ban, 其实没啥必要, 密钥登陆除非服务器早已经被攻陷或者私钥泄露在量子计算机成熟前不可能被破解哈哈哈. 下一步, 我们配置防火墙~

防火墙篇

腾讯云等大厂的服务器都带有安全组, 主机就基本不用另外安装防火墙了, 其余商家默认认为没有安全组, 需要我们自己在 VPS 上配置防火墙, Debian 系列使用 ufw.
  • 基本命令(新机到手执行):
    • 常用命令参考(更多此处没列出的命令请直接执行 ufw, ufw 会告诉你用法, 或者 Google 一下)
    • 启用 UFW: ufw enable
    • 禁用 UFW: ufw disable
    • 列出当前活动规则(详细地): ufw status verbose
    • 列出当前活动规则(带序号): ufw status numbered # 此处序号标识了此条规则
    • 允许某 CIDR 访问本机所有端口: ufw allow from {CIDR}
    • 阻止某 CIDR 访问本机所有端口: ufw deny from {CIDR}
    • 允许访问某端口: ufw allow {PORT}
      • 对某一 CIDR 暴露某端口: ufw allow from {CIDR} to any port {PORT}
    • 阻止访问某端口: ufw deny {PORT}
      • 对某一 CIDR 阻止访问某端口: ufw deny from {CIDR} to any port {PORT}
    • 删除某规则: ufw delete {RULE}|{NUM}
      • 可以是你原来执行的命令 RULE, 如原来执行了 ufw allow 443, 要删除此规则, 就是 ufw delete allow 443, 其他依此类推
      • 还可以是前面提到的规则序号 NUM
    • 将规则 RULE 插入规则列表位置 NUM: ufw insert {NUM} {RULE}, 如 ufw insert 1 allow 443 表示将规则 allow 443 插入到规则列表第一位
      • 注意: 此处的规则列表位置 NUM 应当区分于前面提到的 序号, 因为 ufw 规则包括 v6 规则, 而使用 ufw status numbered 列出规则列表时, v6 的规则的规则是接着 v4 的继续列下去的.
    • 更多地
    • 建站用途, 且使用 Cloudflare CDN, 完全可以不暴露 HTTPS 端口, 服务器只对外暴露个 SSH 端口, 安全得一批, 具体参见后面将要提到的 Cloudflared.
    • 服务器只对少数人提供服务, 不面向公网, 或者部分服务不希望暴露到公网, 可使用虚拟内网方案, 参见后面.
Docker 干预 iptables 导致异常暴露端口的问题 评论区 #10 提到
安装 Docker 后, 务必编辑 /etc/docker/daemon.json(没有就新建一个), 设置 ip127.0.0.1, 防止 docker 自己修改了 iptable 导致 ufw 失效. 修改完毕后执行 systemctl daemon-reload && systemctl restart docker 重启 Docker 服务.
注意, /etc/docker/daemon.json 应当是有效的 json. 下面是个参考(更多地: 开启了 IPv6 支持, 配置了 DNS. 国外服务器自行替换为 1.1.1.1, 8.8.8.8):
注意: 亲测不能修改 /lib/systemd/system/docker.service 加上 --iptables=false, 否则 Docker 无法启动. 修改 /etc/docker/daemon.json 加上 { "iptables" : false } 本质一样.

Nginx 篇

Nginx 泄露源站证书, 导致源站暴露是相当常见问题了. 自 1.19.4 起, Nginx 支持 ssl_reject_handshake 参数, 设置为 on, 当客户端传过来的 SNI 与已配置的 server name 都不匹配时, 会拒绝 SSL 握手, 进而避免证书泄露.
以下示例基于 Nginx 1.25.1, 配置文件保存在 /etc/nginx/conf.d 目录下, 这也是通过 apt 安装 nginx 的默认位置. cat <<'TEXT' > nxdomain.confTEXT 前即为配置文件内容. 使用非正常途径安装的 nginx 请自行找配置文件目录, 新建个 nxdomain.conf 文件把内容贴进去就行.
注意, 在此之前在别的配置文件配置了 default_server 的, 记得去删掉, 虽然没删掉 nginx 也启动不了.
使用旧于 1.19.4 的 nginx, 自签证书吧, 此处按下不表 (虽然我也在配置文件里体现了)

DNS 及 SSL 篇

TL,DR: 不要设置 DNS 直接指向源站, 使用泛域名证书
帮助好几个 UP 排查源站泄露的原因, DNS 泄露是个相当常见的原因. 所以, 不要设置 DNS 直接指向源站! 就算后面改为 CNAME 到 CDN 的域名, DNS 记录是可以查历史的!
其次, 子域名爆破是查源站常用方法了, 有个非常好用的查子域名的方法是 crt.sh, 原理是查 SSL 证书颁发记录, 所以, 推荐使用泛域名证书.
还有 RDNS, 不过一般没人会将自己服务器 IP 的 RDNS 配置为自己的域名, 许多商家也没提供这个功能, 此处按下不表.

后面的两个解决方案是我个人觉得比较好的, 但是每个人情况不一样, 仅供参考, 欢迎大家分享自己的方法~

虚拟内网篇(Zerotier)

本处只介绍 Zerotier 组建虚拟内网, tailscale 等其他虚拟内网方案我没用过.
为什么要虚拟内网? 原因很简单, 搭建非公开的服务, 如个人的 emby 媒体库服务只给认识的人用, 还有自己管理的服务器间通过 socks5 等非加密代理协议访问对方, 使用虚拟内网服务器无需暴露相应端口, 大大降低安全风险. 好处多多可以说了. 使用虚拟内网后, 服务器只需要暴露 9993 端口(zerotier), SSH 都不用暴露在公网, 除非 zerotier 出了致命零日漏洞, 否则安全的很.
当然, 多提一嘴, 由于国内 v4 普遍为 NAT4, P2P 不可能打洞, 导致客户端间互联只能 relay 模式通过国外服务器中转, 速度可想而知. 同时, zerotier 等虚拟内网方案普遍走 UDP (有 TCP 的欢迎踢我一脚我看看), 部分运营商对 UDP 的 QoS 相当严重, 或者服务器线路差, 虚拟内网连接质量也会很差, 所以也非万金油方案. 值得高兴的是, v6 的普及让 NAT4 的影响没那么大了, 只要双方有 v6, 通过 zerotier 轻松 P2P 直连. 这就是题外话了.
回归正题, 如何组建 zerotier 内网? 此处仅介绍一般流程, 自建 moon / planet 等高级用法不做介绍.
  • 点击 Create A Network, 下面就会出现一个 network, 点进去
    • Basics 设置
      • Network ID 网络 ID, 等下会用
      • Name 网络名称, 你可以设置为自己喜欢的名字
      • Access Control 配置网络是私有的还是公开的, 我们组自用的虚拟内网当然是 Private 啦
    • Advanced 设置
      • IPv4 Auto-Assign 建议选择和家里内网错开的内网网址段, 别用 192.168.** 这种用烂了的.
      • IPv6 Auto-Assign 没必要, 不用管
  • Windows 管理员权限打开 Powershell, Linux 用 root 登陆 SSH, 然后执行 zerotier-cli join {Network ID}, Network ID 就是前面提到的网络 ID.
  • 打开管理控制台 https://my.zerotier.com/network/{Network ID}, 在 Members 处你会看到刚刚加入的设备, 勾上 Auth 栏的复选框, 这个设备就正式成功加入这个虚拟内网中了~ VPS 侧执行一下 ifconfig 就能看到分配的 IP 了, 当然你也可以自己在控制台手动分配一个.
  • 防火墙记得允许 9993 端口进出站: ufw allow 9993
P.S. Zerotier 官方版限制最多 25 设备, 如果设备非常多, 只能自建 zerotier, 此处不涉及, 一般也用不到.
假设 VPS 是虚拟内网 IP 是 10.10.0.1, 8000 端口建了个 Alist, 试试访问 10.10.0.1:8000? 能打开就是成功啦. SSH 也试试?

Cloudflare ZeroTrust Tunnel 篇

只能说, Cloudflare 是最伟大的 CDN 厂商 (暴论!) 免费扛 DDoS, 一堆免费好用的功能, 除了国内访问速度慢点而已...
此处介绍通过 Cloudflare ZeroTrust 里面的 Tunnel 功能做到服务器不暴露 HTTPS 端口建站, 安全性 UP 一大截. 我们后面默认你已经注册并用过了 Cloudflare.
  • 打开 Cloudflare 仪表板, 左侧找到进入 ZeroTrust 控制台, 左侧依次点击 Access -> Tunnel, 点击 Create a tunnel 创建 Tunnel
    • Tunnel name 填个名字, 下一步
    • Choose an operating system, 点击 Debian, 复制右下方 If you already have cloudflared installed on your machine: 处的命令 sudo cloudflared service install *** 到 VPS 终端执行. 连接成功后下面的 Connectors 就会显示出来, 下一步
    • 填写 Subdomain, 我个人按照 国家-地区-VPS商家-cf-tunnel 来规范命名, 如 cn-hk-ali-cf-tunnel; Type 选择 HTTP 或者 HTTPS (用 Cloudflare Tunnel 连接源站也没啥必要 SSL 了, 直接用 HTTP 没问题, HTTPS 还有证书问题挺麻烦的), Url 按实际情况填, 如 127.0.0.1:80127.0.0.1:443. 使用 HTTPS 时, 源站若使用自签证书务必在下面 TLS 处把 No TLS Verify 勾上, 顺带也可以开个 HTTP2: HTTP2 connection
    • 特殊地, 若服务器为 v6 only, 需要编辑 /etc/systemd/system/cloudflared.service 文件, 找到 ExecStart=/usr/bin/cloudflared --no-autoupdate tunnel run --token *** 这行, /usr/bin/cloudflared 后面加个参数 --edge-ip-version 6, 即: ExecStart=/usr/bin/cloudflared --edge-ip-version 6 --no-autoupdate tunnel run --token ***

结语

内容有点多, 可能有疏漏, 欢迎大家评论区批评指正交流讨论补充嗷, 觉得有帮助赏个鸡腿也行哒
V1.0.3
Last Updated: Docker 干预 iptables 导致异常暴露端口的问题的解决方案
@Hantong #11
两种方案:
第一:
看得懂吧,在docker的daemon.json配置文件里加"iptables": false,让它无法控制防火墙
缺点:有些容器无法连接网络
第二:
自己创建一个bridge桥接网络,命名为net(随意),设置ip段和网关:
然后部署一个容器时加上环境变量:
来固定它的ip,不然多容器一重启就乱了,导致反向代理失效或乱窜。
缺点:麻烦
我是胡说八道,楼下正解
不过,非公开的东西。直接把IP和域名隐藏好就行了。反正是自己用。不知道地址也打不了
公开的网站,现阶段只有抱住CF的大腿,似乎没有其他办法。
上一篇
2022-02 铜官窑旅行
下一篇
记录一次web攻击 - Pboot:if

评论
Loading...