Debian 12 默认的 LAMP 环境安装脚本跑完后,系统其实处于一个相当脆弱的状态。PHP 的默认配置允许执行远程文件、Apache 暴露了详细的版本信息、MySQL 的 root 用户默认使用 auth_socket 插件导致运维人员为了方便直接改成弱密码——这些都不是危言耸听,而是每次渗透测试中高频出现的问题。我们直接动手,从操作系统内核参数到应用层配置,逐层加固。
内核级 TCP 协议栈加固应用层防护做得再好,如果 SYN Flood 攻击直接把服务器半连接队列打满,服务照样不可用。编辑 /etc/sysctl.conf 或创建 /etc/sysctl.d/99-security.conf,加入以下参数:
# 开启 SYN Cookie,防止 SYN Flood net.ipv4.tcp_syncookies = 1 # 忽略所有 ICMP 回显请求(禁止 ping) net.ipv4.icmp_echo_ignore_all = 1 # 忽略广播 ICMP net.ipv4.icmp_echo_ignore_broadcasts = 1 # 记录有伪造源地址的数据包 net.ipv4.conf.all.log_martians = 1 # 禁止源路由 net.ipv4.conf.all.accept_source_route = 0 # 启用反向路径过滤,防止 IP 欺骗 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 # 减少 TIME_WAIT 连接的最大数量,缓解 DDoS net.ipv4.tcp_max_tw_buckets = 5000 # 加快 TCP 连接回收 net.ipv4.tcp_tw_reuse = 1
保存后执行 sysctl -p 使其生效。这些参数能有效缓解基于 TCP 协议的常见拒绝服务攻击,同时减少 IP 欺骗的风险。特别注意 rp_filter 参数,在多网卡服务器上如果做了非对称路由可能需要根据实际情况调整,但对于典型的单网卡 LAMP 服务器,开启反向路径过滤是最佳实践。
Apache 信息泄露防护与访问控制默认安装的 Apache 会向客户端发送详细的服务器版本信息和操作系统类型,这为攻击者提供了精准的漏洞利用信息。编辑 Apache 主配置文件 /etc/apache2/conf-available/security.conf,修改或添加以下指令:
ServerTokens Prod ServerSignature Off TraceEnable Off
ServerTokens Prod 让 Apache 仅返回 "Apache",不暴露版本号和操作系统。ServerSignature Off 关闭错误页面底部的服务器签名。TraceEnable Off 禁用 HTTP TRACE 方法,防止跨站追踪攻击。启用这些模块和配置:
a2enmod headers a2enmod rewrite systemctl restart apache2
接下来配置安全头。在虚拟主机配置或 .htaccess 中添加:
Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "DENY" Header always set X-XSS-Protection "1; mode=block" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
这些 HTTP 响应头分别防止 MIME 类型嗅探、点击劫持、反射型 XSS、Referer 泄露和不必要的浏览器功能调用。对于生产环境,还应该配置 Content-Security-Policy,但 CSP 策略需要根据实际加载的资源定制,错误的 CSP 规则会导致页面功能异常,建议先在测试环境调试。
PHP 运行时安全加固PHP 是 LAMP 栈中最容易出问题的环节。编辑 /etc/php/8.2/apache2/php.ini(路径根据 PHP 版本调整),逐项检查并修改以下关键参数:
# 禁止远程文件包含 allow_url_fopen = Off allow_url_include = Off # 隐藏 PHP 版本信息 expose_php = Off # 禁用危险的函数 disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source # 限制文件上传大小,防止资源耗尽 upload_max_filesize = 10M post_max_size = 12M max_execution_time = 30 max_input_time = 60 # 严格限制可访问目录 open_basedir = "/var/www/html:/tmp" # 会话安全 session.cookie_httponly = 1 session.cookie_secure = 1 session.cookie_samesite = "Strict" session.use_strict_mode = 1
disable_functions 列表需要谨慎处理。如果网站程序依赖 ImageMagick 或某些需要 exec 功能的插件,盲目禁用会导致业务中断。建议先在 staging 环境测试,或使用白名单方式逐步收紧。open_basedir 是防止 PHP 跨目录访问的有效手段,但如果有多个虚拟主机,需要把各自的目录都加进去,用冒号分隔。session.cookie_secure 要求网站必须启用 HTTPS,如果还没有配置 SSL 证书,这个选项会导致会话 Cookie 无法传输,务必先完成 HTTPS 部署。
MySQL 权限最小化与审计很多人安装完 MySQL 后直接用 root 账户连接应用程序,这是极其危险的做法。先运行 mysql_secure_installation 脚本,它会引导你设置 root 密码、删除匿名用户、禁止 root 远程登录、删除测试数据库。然后为每个应用创建独立的数据库用户,并严格限制权限:
CREATE USER 'appuser'@'localhost' IDENTIFIED BY '强密码'; GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'localhost'; FLUSH PRIVILEGES;
除非应用程序确实需要 ALTER、DROP、CREATE 等 DDL 权限,否则只授予基本的 CRUD 权限。对于需要执行备份的脚本,单独创建一个只读用户:
CREATE USER 'backup'@'localhost' IDENTIFIED BY '另一组强密码'; GRANT SELECT, LOCK TABLES ON appdb.* TO 'backup'@'localhost';
MySQL 8.0 引入了密码过期策略和密码复杂度验证组件,建议启用:
INSTALL COMPONENT 'file://component_validate_password'; SET GLOBAL validate_password.policy = STRONG; SET GLOBAL validate_password.length = 14;
这要求密码至少 14 位,包含大小写字母、数字和特殊字符。对于已有的弱密码账户,用 ALTER USER 语句强制更新。
文件系统权限与 SUID/SGID 审计Web 目录的权限设置直接决定了攻击者拿到 Webshell 后能造成多大破坏。核心原则:Web 服务器进程(www-data)只对需要写入的目录拥有写权限,其他目录全部只读。典型的权限设置:
# 设置所有文件所有者为部署用户,组为 www-data
chown -R deploy:www-data /var/www/html
# 目录权限 755,文件权限 644
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# 仅对需要上传的目录授予写权限
chmod 770 /var/www/html/uploads
全系统范围内查找并清理不必要的 SUID 和 SGID 文件:
find / -perm -4000 -type f 2>/dev/null find / -perm -2000 -type f 2>/dev/null
常见的可移除 SUID 位文件包括 /usr/bin/chage、/usr/bin/gpasswd、/usr/bin/wall 等,如果系统不需要普通用户修改密码,可以考虑去除这些文件的 SUID 位。但 /bin/su、/usr/bin/sudo 等核心工具不能动,否则会导致系统管理功能异常。
ModSecurity WAF 部署与 OWASP 规则应用层防火墙是拦截 SQL 注入、XSS、文件包含等攻击的最后一道防线。在 Debian 上安装 ModSecurity:
apt install libapache2-mod-security2 cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
编辑 /etc/modsecurity/modsecurity.conf,将 SecRuleEngine 从 DetectionOnly 改为 On:
SecRuleEngine On SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072
下载 OWASP 核心规则集:
apt install modsecurity-crs
规则集安装在 /usr/share/modsecurity-crs/ 目录下。需要手动创建包含文件,在 /etc/apache2/mods-enabled/security2.conf 中添加:
Include /usr/share/modsecurity-crs/crs-setup.conf Include /usr/share/modsecurity-crs/rules/*.conf
CRS 默认是偏严格的,部署后一定会产生误报。关键是要花时间根据业务日志调整规则排除项,而不是直接关掉整个模块。可以通过调整规则阈值(Paranoia Level)来平衡安全性和可用性,生产环境建议从 PL 1 开始,逐步提升。
Fail2Ban 暴力破解防御SSH、MySQL、Apache 认证页面都是暴力破解的目标。安装 Fail2Ban 并配置监控规则:
apt install fail2ban
创建 /etc/fail2ban/jail.local,不要直接修改 jail.conf,因为后者会在包更新时被覆盖:
[DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true mode = aggressive [apache-auth] enabled = true [apache-badbots] enabled = true [mysqld-auth] enabled = true port = 3306 logpath = /var/log/mysql/error.log
重启 Fail2Ban 后,任何在 10 分钟内失败 5 次的 IP 将被封禁 1 小时。对于 SSH,建议改用密钥认证并禁用密码登录,这样 Fail2Ban 的 SSH 规则就变成了辅助手段而非主要防线。修改 /etc/ssh/sshd_config:
PasswordAuthentication no PubkeyAuthentication yes PermitRootLogin prohibit-password日志监控与入侵检测
加固完成后的工作不是结束,而是持续监控的开始。配置 logrotate 确保日志不会撑满磁盘,同时部署 AIDE 进行文件完整性校验:
apt install aide aideinit cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
创建定时任务每天检查文件变更:
0 3 * * * /usr/bin/aide --check | mail -s "AIDE Report" admin@example.com
对于 MySQL,启用慢查询日志和错误日志,并定期分析:
SET GLOBAL slow_query_log = 1; SET GLOBAL log_queries_not_using_indexes = 1;
Apache 的访问日志中重点关注 404 和 500 错误激增的时段,这通常是扫描器在探测漏洞。可以使用简单的 awk 命令统计每分钟请求量,异常波动直接触发告警。
自动更新策略与测试流程Debian 的 unattended-upgrades 可以自动安装安全更新,但直接在生产环境启用有风险——更新后服务可能启动失败。推荐的做法是启用安全更新的自动下载和通知,但手动执行安装:
apt install unattended-upgrades apt-listchanges dpkg-reconfigure unattended-upgrades
在配置中选择仅自动安装安全更新,并配置邮件通知。对于 PHP 和 MySQL 的小版本升级,通常向后兼容性很好,可以放心自动更新。但大版本升级(如 PHP 8.2 到 8.3)必须在测试环境完整回归后再操作。
整个加固过程不是一次性工作。每次部署新代码、安装新插件、调整架构后,都需要重新审视安全配置是否依然有效。建议把这些加固步骤写成 Ansible Playbook 或 Shell 脚本,纳入服务器的初始化流程,确保每一台新上线的 LAMP 服务器都达到相同的安全基线。安全是一个持续的过程,今天的加固方案可能在明天的新漏洞面前就不够用了,保持对安全公告的关注和快速响应能力,才是长期运维的核心竞争力。
