接手一台运行Ubuntu的服务器,Apache服务默认配置跑起来后,最容易被忽视的就是它暴露在外的服务器信息。攻击者扫描时,只要看到Server头返回Apache/2.4.52 (Ubuntu),就能立刻锁定你的操作系统版本和Web服务器版本,进而查找对应版本的已知漏洞。第一步要做的,就是隐藏这些版本信息。编辑主配置文件,通常位于/etc/apache2/conf-available/security.conf,找到ServerTokens和ServerSignature这两个指令。ServerTokens默认值是Full,会返回完整的版本号和操作系统信息,将其修改为Prod,这样Apache只返回Server: Apache,不再透露具体版本。ServerSignature默认是On,会在错误页面底部显示服务器信息,直接设为Off。改完重启服务,用curl -I 你的域名测试一下,响应头里就干净多了。
关闭危险的目录浏览功能很多开发者在测试环境为了方便,会开启目录浏览,也就是Options指令里的Indexes参数。如果这个配置被带到生产环境,攻击者访问一个没有索引文件的目录时,就能直接看到整个目录结构,下载源代码、配置文件甚至数据库备份。检查所有虚拟主机配置和.htaccess文件,把Options Indexes FollowSymLinks改成Options -Indexes +FollowSymLinks,明确禁止目录浏览。更彻底的做法是,在全局配置里直接禁用,然后只对需要目录浏览的特定目录单独开启。修改完记得用apache2ctl -t做语法检查,确认无误后再重载配置。
限制HTTP请求方法,堵死不必要的入口一个标准的Web应用,前端请求基本只用GET和POST,后台管理可能用到PUT或DELETE,但绝大多数站点根本不需要TRACE、OPTIONS、HEAD之外的TRACK等方法。TRACE方法尤其危险,它允许跨站追踪攻击,能窃取用户的Cookie信息。在虚拟主机配置或.htaccess中,用LimitExcept指令白名单化允许的方法。举个例子,如果只允许GET、POST、HEAD,就这样写:
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
这样任何不在白名单里的HTTP方法请求,Apache直接返回403 Forbidden。对于OPTIONS方法,虽然某些跨域请求会用到,但如果你的API不需要处理预检请求,也可以一并禁用。用nmap扫一下自己的站点,确认这些危险方法确实被封堵了。
升级到TLS 1.2/1.3并禁用老旧加密协议SSL/TLS配置是Apache安全加固里最容易被拖延的一项。很多服务器还在支持TLS 1.0甚至SSLv3,这些协议早已被证实存在POODLE、BEAST等严重漏洞。编辑SSL模块配置文件,强制启用TLS 1.2和1.3,关闭所有旧版本。同时要精细调整加密套件,禁用那些使用RC4、3DES、MD5的弱算法。一个强健的配置示例如下:
SSLProtocol -all +TLSv1.2 +TLSv1.3 SSLCipherSuite HIGH:!aNULL:!MD5:!3DES:!RC4 SSLHonorCipherOrder on
这里SSLHonorCipherOrder on让服务器决定加密套件的优先级,而不是客户端,能有效防止降级攻击。配置完成后,用openssl s_client -connect 你的域名:443 -tls1_1测试旧协议是否被拒绝,再用SSL Labs的检测工具验证得分,目标是拿到A+评级。别忘了同时启用HSTS响应头,强制浏览器始终通过HTTPS访问,杜绝中间人攻击的可能性。
用mod_evasive和mod_security构建应用层防火墙网络层的防火墙管不到HTTP洪水攻击和SQL注入这类应用层威胁,这时候需要Apache自己的防护模块。mod_evasive专门应对DoS和暴力破解,它监控单个IP对同一页面的请求频率,超过阈值就临时封禁。安装后配置/etc/apache2/mods-available/evasive.conf,设定页面请求间隔、站点请求间隔和封禁时间:
DOSPageCount 5 DOSSiteCount 100 DOSPageInterval 1 DOSSiteInterval 1 DOSBlockingPeriod 600
这表示一个IP在1秒内请求同一页面超过5次,或者1秒内向整个站点发送超过100个请求,就会被封禁600秒。mod_security则是一个完整的Web应用防火墙,带有一套核心规则集,能拦截SQL注入、跨站脚本、文件包含等常见攻击。Ubuntu下安装libapache2-mod-security2后,需要把默认的配置文件从modsecurity.conf-recommended重命名为modsecurity.conf,并把SecRuleEngine从DetectionOnly改为On,这样规则才会真正拦截攻击,而不是仅仅记录日志。初期建议先用DetectionOnly模式跑几天,分析日志排除误报,确认业务正常后再开启拦截模式。
以最小权限运行Apache进程Ubuntu通过apt安装的Apache,默认会用www-data用户和组运行工作进程,这本身是低权限账户,但很多运维人员为了方便,把网站目录的所有者改成www-data,甚至给目录775或777权限。正确的做法是,网站文件的所有者应该是普通用户,比如deploy,所属组可以是www-data,目录权限设置为750,文件权限设置为640。这样即使Apache进程被攻破,攻击者也无法修改网站文件,只能读取。对于需要写入的目录,比如上传目录或缓存目录,单独设置权限,并且一定要在这些目录里放一个.htaccess文件,禁止执行PHP或其他脚本。用下面这个配置彻底阻断上传目录的脚本执行:
php_flag engine off RemoveHandler .php .phtml .php3 .php4 .php5 RemoveType .php .phtml .php3 .php4 .php5
另外,检查Apache主配置文件,确保Options指令里没有FollowSymLinks,除非你明确需要符号链接功能。如果必须使用,加上SymLinksIfOwnerMatch,这样Apache只跟踪目标文件所有者与链接所有者相同的符号链接,防止攻击者利用符号链接访问无权访问的系统文件。
隔离虚拟主机,防止跨站攻击一台服务器上跑多个网站很常见,如果一个站点被拿下,攻击者很可能通过Apache的权限蔓延到其他站点。用suexec或mpm-itk模块可以让每个虚拟主机以独立的用户身份运行,实现进程级别的隔离。mpm-itk配置简单,直接在虚拟主机配置里指定用户和组:
<IfModule mpm_itk_module>
AssignUserId site1_user site1_group
</IfModule>
这样site1的Apache进程只以site1_user身份运行,即使这个站点有漏洞被利用,攻击者也拿不到site2的文件。不过mpm-itk性能开销较大,不适合高并发场景。更轻量的方案是用php-fpm池,每个站点配置独立的fpm池,监听不同的Unix socket或端口,再通过Apache的ProxyPassMatch或SetHandler把PHP请求转发过去。每个fpm池可以指定独立的用户、php.ini和资源限制,隔离性和性能都很好。无论用哪种方案,都要确保每个站点的文件权限设置正确,用户之间无法互相读取。
日志监控与异常告警安全加固不是一次性工作,持续的监控才能发现潜在威胁。Apache默认的访问日志和错误日志路径在/var/log/apache2/下面,但默认的LogFormat信息量不够。建议自定义日志格式,把请求耗时、Referer、User-Agent、请求体大小都记录下来,特别是要记录请求的Host头,这对识别针对IP的直接扫描很有用。一个信息全面的日志格式可以这样定义:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %I %O" detailed
然后用fail2ban这个工具实时分析日志,自动封禁恶意IP。创建一个针对Apache的jail配置,监控404错误频率、可疑的User-Agent、对敏感路径的扫描行为。比如监控对/wp-admin、/phpmyadmin、/.env这类路径的访问,一旦触发规则,直接调用iptables封禁IP。fail2ban的过滤器支持正则表达式,可以灵活定义规则。同时,把Apache日志集中发送到日志分析平台,设置异常流量告警,比如短时间内来自同一IP的大量请求、非正常时间段的访问高峰、大量5xx错误等,这些往往是攻击前兆。
定期更新与自动化漏洞扫描Ubuntu的apt包管理器让更新变得简单,但很多服务器管理员不敢轻易升级,怕影响业务。实际上,安全更新和主版本升级应该分开处理。配置unattended-upgrades,让它只自动安装安全更新,这样既能及时修补已知漏洞,又不会引入不兼容的版本变更。安装后编辑/etc/apt/apt.conf.d/50unattended-upgrades,只勾选安全更新源。同时,把Apache和PHP的版本信息从错误页面和响应头里去掉,这个前面已经说过,但更重要的是,定期用漏洞扫描器检查整个Web应用,包括Apache本身、PHP版本、使用的开源框架和库。把扫描任务写进crontab,每周跑一次,结果发送到邮箱,这样能在攻击者利用之前发现并修补漏洞。
强化PHP配置,切断代码执行链Apache和PHP通常一起部署,PHP配置不当会让前面的加固措施功亏一篑。检查php.ini,把allow_url_fopen和allow_url_include都设为Off,这两个选项如果开启,攻击者可以通过远程文件包含漏洞直接执行外部服务器上的恶意代码。disable_functions要配置一个黑名单,把exec、system、passthru、shell_exec、popen、proc_open这些能执行系统命令的函数全部禁用。如果业务代码用不到这些函数,禁掉它们能极大增加攻击者的利用难度。open_basedir限制PHP能访问的文件路径,只允许读取网站根目录和临时目录,这样即使有文件包含漏洞,攻击者也读不到系统配置文件。每个虚拟主机应该有独立的php.ini或fpm池配置,根据业务需求最小化开启的功能模块。
