对服务器安全的个人见解 👻

服务器安全一直是个挺重要的事儿,但对于我们这些小站长来说,专业能力不如运维人员,对 Linux 操作系统也没那么熟悉,更别说去读取分析日志提前填补问题了。在个人精力与专业能力之间势必有个选择,总结了目前对服务器安全所做的努力,尽可能防止因为个人原因导致的漏洞问题。

当然我毕竟不是专业人员,所提出的观点也仅仅代表我的个人观点,此篇分类是为 杂谈

一、云服务商

这里以腾讯云举例,当你在云服务商购买了服务器/轻量服务器后,除开操作系统本身,服务商的控制台能够提供这几项关键能力:①重置账户密码;②密钥的绑定;③防火墙控制。

① 重置账户密码

重置密码是必须的,毕竟执行 sudo 类命令时,或需要输入当前用户的密码,密码这里建议在常用密码基础上进行个别位的变形,比如将服务器地域和常用密码掺和在一起输入,当然其实这个意义不是很大。

② 密钥的绑定

原则上密钥不应该共用,实际上共用同一套密钥方便很多。所以实际点的建议是在 创建密钥 时输入安全密码,以及加密算法使用 ed25519,如果是 RSA 算法则需要为 4096 位。

③ 防火墙控制

正所谓做的越多,错的越多,所以尽可能的减少端口的开放,比如我自己的服务器只开放了两个端口:用来 Https 访问的 443 端口和用来进行终端连接的 SSH 端口,像 80 端口这类不加密访问的还是趁早埋了吧。

同时防火墙除了能做端口限制外,还可以用来屏蔽指定地址的访问:比如 Censys 的扫描,直接将它的 IP 段屏蔽,拒绝连接:Can I opt out of Censys scans;再比如,如果你像我一样毫不在意境外的访问流量,而当你在日志里找到了有个 138.246.56.96 的 IP 在对你的服务器做扫描时,可以直接拒绝它整个范围的连接:138.246.0.0/16(德国 慕尼黑大学网段)。

二、应用控制

如上文所说,我对外开通了用于 SSH 和 Https 的端口,所以就是围绕着这两个对外开放的端口,尽可能的减少对方的入侵渠道,越少越难越好。

① SSH 应用

相较来说,此点最好解决,核心是 禁止密码登录、只允许密钥登录、更换默认端口,这三点可以在配置文件中完成,注:Ubuntu 默认不允许 root 用户的密码登录,但是可以用密钥去登。

/etc/ssh/sshd_config
# 禁止密码登录
PasswordAuthentication no

# 允许密钥登录
PubkeyAuthentication yes

# 修改端口
Port 2022

② Web 应用

监听 443 端口的为 Nginx,涉及了从域名到地址、再到各类响应状态等的处理。

(1)DNS 阶段

首先我们的理想状态是你通过域名找不到我服务器的真实 IP,备案的话可以使用国内的 CDN 服务,没备案时可以使用 Cloudflare 的代理服务,这两者都可以达到隐藏真实服务器地址的目的。

如果你依旧像我一样没心没肺毫不在乎访问体验,那么 DNS 阶段可以设置成仅解析境内服务。以 DNSPod 举例,如果你购买了专业版,可以单独新增一条解析线路为云厂商(阿里云、华为云、京东云、青云、亚马逊云等),地址为 127.0.0.1 的解析,让那些请求自个儿玩去吧。

(2)直接访问

2.1 拒绝默认域名访问

假设对方知道了你的 IP,但是不知道这个服务器部署了什么网站。如果没有设置默认站点,对方可以通过一个垃圾域名落到你某个站点上,所以第一步拒绝默认域名访问:

server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
index index.html;
root /www/sites/default.website/index;
access_log /www/sites/default.website/log/access.log;
error_log /www/sites/default.website/log/error.log;
ssl_reject_handshake on;

# 设置默认内容类型
default_type application/octet-stream;

# 捕获并处理所有请求,返回444
location / {
return 444;
}

# 捕获并处理所有未定义的协议请求
location ~* ^.*$ {
return 444;
}

return 444;
}

2.2 搭配 Fail2Ban 进行屏蔽

创建 Nginx 过滤器,创建文件 /etc/fail2ban/filter.d/nginx-444.conf 并添加以下内容:

[Definition]
# 仅匹配返回444状态码的正则表达式
failregex = <HOST>.*HTTP/.*".*" 444
ignoreregex =
  • 配置解释:

    • failregex 定义了匹配日志文件中返回444的正则表达式。
    • ignoreregex 留空,表示不过滤任何日志条目。

配置 Fail2Ban 监狱(Jail),编辑 Fail2Ban 的配置文件 /etc/fail2ban/jail.local,添加以下内容:

[nginx-444]
enabled = true
filter = nginx-444
logpath = /www/sites/default.website/log/access.log
bantime = 600 # 初次封禁时间(10分钟)
findtime = 600 # 监控时间段(10分钟)
maxretry = 1 # 单次触发条件

[recidive]
enabled = true
logpath = /var/log/nginx-444.log
bantime = -1 # 永久封禁
findtime = -1 # 累积时间段(不限)
maxretry = 3 # 触发条件次数

1Panel 的默认站点日志文件的实际位置是:

/opt/1panel/apps/openresty/openresty/www/sites/default.website/log/access.log

  • 配置解释:

    • Nginx 监狱:监控 Nginx 访问日志中的返回444状态码,初次触发封禁时间为10分钟。
    • Recidive 监狱:监控 Fail2Ban 日志,如果 IP 地址在任意时间段内被封禁超过3次,则该 IP 地址将被永久封禁。这意味着触发多次短期封禁后,IP地址将永久被拒绝访问。

创建日志:

sudo touch /var/log/nginx-444.log
sudo chmod 640 /var/log/nginx-444.log
sudo chown root:adm /var/log/nginx-444.log

2.2 拒绝非 CDN 请求访问

如果对方即知道 IP 又知道域名,可以做到直接通过本地 hosts 绕过 CDN 进行访问。我们可以在 CDN 面板中的回源设置里添加一个只有你知道的请求头和值,然后在网站配置中对其判断,不符合就返回 444。

只有携带这个请求头才放行
# 私有请求头校验 X-Check
if ($http_x-check != 'helloworld') {
return 444;
}

(3)避免抛出错误信息

避免直接把错误信息展现给用户,不知道的永远是最好的,可以在网站的配置中重定向 5XX 错误。

4,5XX,444 有请
# 捕获所有4XX和5XX错误并重定向到返回444的位置
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 = @return_444;

location @return_444 {
return 444;
}

(4)对关键地址进行加密

比如 Typecho 博客的后台登录页,直接利用面板的访问限制功能,对 /admin/ 路径简单加密,授权通过访问打开页面,否则 401 Unauthorized。

(5)部署 Web 防火墙

无论你是使用面板的防火墙还是 ModSecurity 防火墙,请务必开启一个。

(6)拉黑无意义的 UA

具体情况具体分析,我的拉黑比较激进,包含下列内容的 User-Agent 均被我拉黑了:

一概拉黑
*nmap*|*NMAP*|*HTTrack*|*sqlmap*|*Java*|*zgrab*
*Python*|*python*|*curl*l*Curl*|*wget|*Wget*
*MJ12bot*|*a Palo Alto*|*ltx71*|*censys*
*Go-http-client*|*CensysInspect*
*toutiao*|*Barkrowler*|*AhrefsBot*

三、其他

面板

事实上我少开放了一个用于访面板的端口,因为直接用 Nginx 反代访问啦。

数据库

没有必要开放数据库端口,使用 SSH 隧道访问,保持数据库本地连接即可。

评论