服务器返回的响应头里如果还带着Server: Apache/2.4.6或者X-Powered-By: PHP/5.6这类字段,等于把技术栈版本直接告诉扫描器。攻击者拿着版本号去比对已知漏洞库,一打一个准。修改方式取决于运行环境,Nginx在http区块里加server_tokens off;,Apache在配置文件里设置ServerTokens Prod和ServerSignature Off。改完记得重启服务并验证响应头确实不再暴露版本。

目录浏览与文件权限的默认陷阱

很多站点部署完源码后,uploads、backup、log这些目录直接就能通过URL列出文件清单。检查方法很简单,浏览器访问https://你的域名/uploads/,如果看到一排文件名而不是403或404,就是开了目录浏览。Nginx配置里autoindex off;,Apache用Options -Indexes。文件权限方面,PHP文件建议644,目录755,配置文件比如.env、config.php如果权限是666或777,等于把数据库密码写在门口。Linux下用find /网站根目录 -type f -name "*.env" -perm /o+w能快速找出可被外部写入的敏感文件。

HTTPS强制跳转与HSTS的配置细节

证书部署了不代表安全,如果HTTP还能正常访问,中间人依然可以在用户第一次访问时劫持。Nginx里对80端口做301跳转,同时加上Strict-Transport-Security响应头。完整配置参考:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

HSTS的max-age建议至少半年,includeSubDomains表示子域名也强制HTTPS。但注意,如果子域名还没上HTTPS,加了includeSubDomains会导致那些子域名无法访问,所以上线前先确认全站证书覆盖情况。

跨站脚本攻击的响应头加固

X-Content-Type-Options: nosniff能防止浏览器把脚本文件当样式表执行,这个头几乎没有任何副作用,建议全站开启。X-Frame-Options: SAMEORIGIN或者用Content-Security-Policy的frame-ancestors指令,可以防止站点被iframe嵌入做点击劫持。Referrer-Policy建议设为strict-origin-when-cross-origin,既保护用户隐私又不影响正常的流量统计。这些响应头在Nginx里统一写到server区块,Apache写到.htaccess或虚拟主机配置。

会话Cookie的安全属性配置

登录态的Cookie必须加上HttpOnly和Secure两个属性。HttpOnly让JavaScript读不到Cookie,即使存在XSS漏洞也拿不到会话ID;Secure确保Cookie只在HTTPS连接中传输。如果站点同时跑HTTP和HTTPS,Secure属性会导致HTTP下无法登录,所以这个配置必须和HTTPS强制跳转同步进行。SameSite属性建议设为Lax,能挡住大部分CSRF攻击,又不会影响从外部链接点进来的正常会话。PHP里用session_set_cookie_params设置,Java里在web.xml或代码里配置Cookie对象的setHttpOnly和setSecure。

文件上传功能的过滤与隔离

文件上传是重灾区,只检查扩展名远远不够。攻击者可以把PHP代码写进.jpg文件,配合解析漏洞执行。核心原则是:上传目录与代码执行目录物理隔离,上传文件一律不直接通过Web服务器解析。Nginx可以对uploads目录单独配置:

location /uploads/ {
    location ~ \.(php|php5|phtml)$ {
        deny all;
    }
}

同时后端要做MIME类型检测、文件头验证、重命名存储。文件名不要用用户原始输入,用随机字符串加服务端生成的后缀。图片可以用ImageMagick或GD库重新生成,彻底抹掉可能嵌入的恶意代码。

数据库连接与错误回显的收敛

生产环境必须关闭详细的错误回显。PHP的display_errors设为Off,log_errors设为On,把错误写进日志而不是输出到页面。数据库连接失败时不要直接把mysqli_connect_error()打印给用户,那里面可能包含主机名、用户名甚至部分SQL语句。框架的debug模式上线前必须关闭,Laravel的APP_DEBUG=false,ThinkPHP的app_debug=false。数据库账号遵循最小权限原则,Web应用只给SELECT、INSERT、UPDATE、DELETE,DDL权限全部收回。

后台路径与登录接口的访问控制

后台地址不要用常见的/admin、/manage、/system,改成无规律的路径能挡住大部分自动化扫描。但仅靠改路径不够,还要做IP白名单或至少做登录失败次数限制。Nginx层可以做基础认证:

location /后台路径 {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    allow 你的办公IP;
    deny all;
}

应用层登录接口加验证码、失败次数锁定、登录日志记录。验证码不要用简单的四位数字,用图形扭曲加干扰线,或者接入行为验证服务。连续失败5次锁定账号15分钟,同时记录IP和User-Agent。

第三方组件与依赖的版本管理

很多站点被入侵不是因为自己的代码写得差,而是引用的jQuery、ueditor、phpMyAdmin、WordPress插件存在已知漏洞。维护一份组件清单,包括名称、版本、来源、更新时间。定期用漏洞扫描工具比对CVE库,发现高危漏洞24小时内处理。不要直接从网上下载来路不明的插件或主题,优先使用官方源。废弃的插件和测试文件及时删除,phpinfo.php、test.php、info.php这类文件上线前必须清理。

备份文件与版本控制目录的泄露防护

编辑器和版本控制工具会在目录下留下隐藏文件,比如.svn、.git、.DS_Store、.idea。这些文件被访问时可能泄露源码结构甚至完整代码。Nginx统一禁止访问隐藏文件:

location ~ /\.(?!well-known) {
    deny all;
}

备份文件也是重灾区,index.php.bak、config.php.old、数据库.sql这类文件经常被搜索引擎收录。服务器上不要存放任何.bak、.old、.sql、.tar.gz格式的备份,备份文件下载到本地或存到独立的备份服务器。

安全参数优化的持续监测机制

配置加固不是一次性工作,每次上线新功能、更新框架、调整服务器都可能引入新的暴露面。建议建立月度安全检查清单,包括:响应头是否完整、目录浏览是否关闭、上传目录是否隔离、Cookie属性是否齐全、后台登录是否有限制、组件版本是否有更新。同时用脚本定期抓取站点响应头和关键路径状态,发现异常自动告警。安全配置的优化是动态过程,攻击手段在进化,防御参数也要跟着调整。