服务器主机安全基线配置的核心,不是装个杀毒软件或者改个端口那么简单。真正有效的基线,是把“默认不安全”的状态,通过一组可执行、可验证的配置项,收敛到“即使被打,也进不来、拿不走、跑不掉”的程度。很多人把安全基线等同于“等保 checklist”,一条条打勾,结果配置完还是被提权、被挂马、被拖库。问题出在两点:一是基线项只覆盖了操作系统层,没覆盖网站应用和中间件;二是配置完不做验证,基线成了纸面合规。

一、先确定基线的范围:三层四面

网站服务器的主机安全基线,至少要覆盖三个层面:操作系统层、Web中间件层、数据库与运行环境层。四面是:账户与认证、文件与权限、网络与服务、日志与审计。只做系统层,应用层一个弱口令或者一个解析漏洞就能绕过全部系统防护。所以基线配置的第一件事,是把范围划清楚。以 Linux + Nginx + PHP + MySQL 这套常见架构为例,系统层要管 SSH、防火墙、内核参数、文件权限;中间件层要管 Nginx 的解析、目录浏览、Header 泄露、PHP 的危险函数;数据库层要管远程访问、默认账户、权限分离。每一层都有对应的配置文件和命令,基线就是把这些配置项固化下来。

二、账户与认证基线:先堵住最容易被爆破的口子

SSH 是 Linux 服务器被入侵的第一入口。基线配置至少包含:禁用 root 直接登录、修改默认 22 端口、仅允许密钥认证、限制登录用户组、设置登录失败锁定。修改端口不是安全手段,只是降低自动化扫描的命中率,真正有效的是禁用密码登录。配置 /etc/ssh/sshd_config 时,PermitRootLogin no、PasswordAuthentication no、PubkeyAuthentication yes、AllowGroups sshusers 这几项必须明确写出来。很多运维改完配置不重启 sshd 服务,或者用 systemctl reload 而不是 restart,导致旧连接仍然有效,新配置不生效。改完要用 sshd -t 检查语法,再重启服务,并保留一个已建立连接的会话用于回滚。

系统账户方面,要检查 /etc/passwd 中可登录账户,删除或锁定不必要的账户。用 awk -F: '$7 != "/sbin/nologin" && $7 != "/bin/false" {print $1}' 列出可登录用户,逐个确认。同时检查空密码账户和 UID 为 0 的账户,awk -F: '($2 == "" || $3 == 0) {print $1}'。密码策略用 PAM 的 pam_pwquality.so 模块,设置 minlen=12、dcredit=-1、ucredit=-1、ocredit=-1、lcredit=-1,强制复杂度。登录失败锁定用 pam_faillock.so,deny=5、unlock_time=600,防止在线爆破。

三、文件与权限基线:让攻击者拿到 shell 也动不了关键文件

网站目录的权限是最容易出问题的地方。很多运维为了省事,直接 chmod -R 777 /var/www,或者把网站目录属主设为 www-data 且权限为 755,结果攻击者通过上传漏洞写入 webshell 后,可以任意修改网站文件。正确的基线是:网站文件属主为 root 或专用部署用户,属组为 www-data,目录权限 750,文件权限 640,只有需要写入的目录(如上传目录、缓存目录)才给 www-data 写权限,且这些目录要单独设置,禁止执行 PHP。用 find /var/www -type f -exec chmod 640 {} \; 和 find /var/www -type d -exec chmod 750 {} \; 批量设置,再对 upload、cache、logs 等目录单独 chown www-data:www-data 并 chmod 770。

系统关键文件要设置不可变属性。chattr +i /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/ssh/sshd_config,防止攻击者添加账户或修改 SSH 配置。但要注意,chattr +i 之后,正常运维修改这些文件前要先 chattr -i,改完再加回去。很多安全事件中,攻击者拿到 root 权限后第一件事就是 echo "evil::0:0::/root:/bin/bash" >> /etc/passwd 添加特权账户,chattr +i 能有效阻断这一步。另外,/tmp 目录要挂载为 noexec、nosuid、nodev,防止攻击者在 /tmp 下编译执行提权脚本。修改 /etc/fstab,在 /tmp 挂载项加上这些选项,然后 mount -o remount /tmp 生效。

四、网络与服务基线:最小化暴露面,关闭一切不需要的端口

服务器上每多开一个服务,就多一个攻击面。基线要求:只保留业务必需的端口,其他全部关闭。用 ss -tlnp 查看当前监听端口,逐个确认用途。数据库端口 3306、Redis 6379、Memcached 11211 这类服务,如果不需要对外提供服务,必须绑定到 127.0.0.1,禁止监听 0.0.0.0。很多 Redis 被入侵就是因为默认配置 bind 0.0.0.0 且没有密码,攻击者直接写入 SSH 公钥或者计划任务。Redis 基线配置:bind 127.0.0.1、requirepass 强密码、rename-command CONFIG ""、rename-command FLUSHALL ""、rename-command FLUSHDB ""、rename-command EVAL "",禁用危险命令。

防火墙用 iptables 或 firewalld 配置白名单策略,默认 DROP 所有入站流量,只放行 80、443 和修改后的 SSH 端口。出站流量也要限制,防止攻击者反弹 shell。很多服务器只配了入站规则,出站全放行,攻击者拿到 webshell 后可以随意连接外部服务器下载工具或反弹连接。出站基线:允许 DNS 查询(UDP 53)、允许 HTTP/HTTPS 出站(用于系统更新和业务调用),其他全部 DROP。如果业务不需要服务器主动访问外部,出站也可以全部关闭。iptables 规则要持久化,用 iptables-save > /etc/iptables/rules.v4 保存,避免重启后丢失。

五、Web 中间件基线:从源头阻断攻击链

Nginx 的默认配置存在多个信息泄露点。server_tokens off 隐藏版本号,避免攻击者针对特定版本漏洞发起攻击。在 http 块中设置 server_tokens off、client_body_buffer_size 10K、client_header_buffer_size 1k、large_client_header_buffers 2 1k,限制请求头大小,防止缓冲区溢出攻击。限制请求体大小 client_max_body_size 10m,防止上传大文件耗尽磁盘。设置 limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s 和 limit_req zone=one burst=20 nodelay,对单个 IP 限速,缓解 CC 攻击。

PHP 解析漏洞是 Nginx + PHP 架构的经典问题。配置 location ~ \.php$ 时,必须用 try_files $uri =404 先检查文件是否存在,再转发给 PHP-FPM,否则攻击者构造 /uploads/evil.jpg/x.php 这样的路径,Nginx 会把 evil.jpg 当作 PHP 执行。同时,在 location ~* \.(jpg|jpeg|png|gif|css|js|txt|pdf)$ 中,明确禁止执行 PHP,加上 fastcgi_pass off 或者直接不匹配 PHP 规则。PHP-FPM 的 www.conf 中,security.limit_extensions = .php 只允许 .php 扩展名执行,php_admin_value[disable_functions] 禁用 exec、system、passthru、shell_exec、proc_open、popen、curl_exec、curl_multi_exec 等危险函数。php.ini 中 expose_php = Off、display_errors = Off、log_errors = On、allow_url_fopen = Off、allow_url_include = Off、open_basedir 限制为网站根目录和临时目录。

六、数据库与运行环境基线:防止拖库和横向渗透

MySQL 基线配置:删除匿名账户、删除测试数据库、禁用远程 root 登录。执行 DELETE FROM mysql.user WHERE User=''; DROP DATABASE IF EXISTS test; DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; 然后 FLUSH PRIVILEGES。root 账户只允许从 localhost 登录,业务账户按最小权限原则分配,只授予业务库的 SELECT、INSERT、UPDATE、DELETE 权限,不授予 FILE、PROCESS、SUPER、SHUTDOWN 等管理权限。配置文件中设置 skip-symbolic-links、local-infile=0、secure-file-priv=/tmp,禁止 LOAD DATA INFILE 读取任意文件。开启 general_log 和 slow_query_log,记录所有 SQL 操作,便于事后溯源。

PHP 运行环境方面,如果使用 PHP-FPM,每个网站使用独立的 FPM 池,每个池使用独立的用户和组,不同网站之间文件权限隔离。这样即使一个网站被拿下,攻击者也无法读取其他网站的文件。FPM 池配置中,user = site1、group = site1、listen.owner = www-data、listen.group = www-data、listen.mode = 0660,通过 Unix Socket 通信,不监听 TCP 端口。同时设置 pm.max_children 为合理值,防止进程数过多导致内存耗尽。

七、日志与审计基线:让入侵行为有迹可循

日志是安全基线的最后一道防线。rsyslog 配置中,将 auth、authpriv、cron、kern、mail、daemon 等日志分别记录到独立文件,并设置日志轮转。在 /etc/rsyslog.conf 或 /etc/rsyslog.d/50-default.conf 中,确保 auth.log 记录所有认证事件,包括成功和失败。用 logrotate 配置日志保留至少 30 天,压缩归档。同时,将关键日志同步到远程日志服务器,防止攻击者删除本地日志。如果条件不允许远程日志,至少用 chattr +a 给日志文件加只追加属性,chattr +a /var/log/auth.log,这样攻击者无法直接覆盖或删除日志,只能追加。

文件完整性监控用 AIDE 或 Tripwire,对 /etc、/usr/bin、/usr/sbin、/var/www 等关键目录建立基线数据库,定期检查文件变化。AIDE 配置中,对 /etc 目录监控权限、属主、内容变化,对 /var/www 监控新增和删除文件。每天通过 cron 执行 aide --check,发现变化立即告警。很多入侵事件中,攻击者替换系统命令(如 ps、netstat、ls)来隐藏进程和文件,AIDE 能及时发现这些替换行为。

八、基线验证与持续维护:配置完不等于安全

基线配置完成后,必须进行验证。用 lynis audit system 或 CIS-CAT 等工具对系统进行自动化审计,检查基线项是否全部生效。手动验证关键项:用 ssh -o PreferredAuthentications=password 测试密码登录是否被拒绝;用 curl -I 检查 Nginx 是否泄露版本号;用 mysql -u root -p 从远程主机测试 root 是否禁止远程登录;用 find /var/www -type f -perm /o+w 检查是否有文件对其他人可写。验证过程中发现的任何不符合项,都要回填到基线配置中。

安全基线不是一次性配置,而是持续维护的过程。每次系统更新、应用发布、配置变更后,都要重新检查基线是否被破坏。建议将基线配置写成脚本或使用配置管理工具(如 Ansible、Puppet),每次变更后自动执行基线检查。同时,定期关注安全公告,及时更新基线项。例如,某个中间件版本被发现新漏洞,基线中就要增加对应的加固项。只有把基线当成一个动态的、持续演进的体系,而不是静态的 checklist,才能真正守住服务器的安全底线。