很多站长在给网站做完HTTPS之后,就以为安全工作已经到位了,实际上用Mozilla Observatory跑一次检测,往往会得到一个不太好看的分数,甚至只有F级。Observatory是Mozilla推出的免费安全评分工具,它会从内容安全策略、传输加密、响应头防护等多个维度对站点进行打分。对于使用Nginx作为Web服务器的站点来说,绝大多数扣分项都可以通过修改nginx.conf来解决,不需要改动业务代码。本文将结合实际配置,讲解如何一步步把安全评分提升到A+级别。

Observatory评分机制与常见扣分项
Observatory的评分基于 Mozilla 提供的一套安全评分规范,测试项目包括Content Security Policy(内容安全策略)、HTTP Strict Transport Security(严格传输安全)、X-Frame-Options(点击劫持防护)、X-Content-Type-Options(MIME嗅探防护)、Referrer-Policy(引用策略)、Cookie安全属性以及TLS配置等。每一项都有对应的权重,比如CSP和HSTS占比较高,一旦缺失,分数会直接掉到及格线以下。
在实际检测中,Nginx默认安装几乎不携带任何安全响应头,所以裸配置的站点通常只有0分到20分左右,等级为F。常见的扣分点集中在三处:一是没有配置HSTS,浏览器不知道该站点必须走HTTPS;二是缺少CSP策略,页面容易被注入外部脚本;三是Cookie没有加HttpOnly和Secure标记,存在会话劫持风险。把这三类问题解决后,分数一般能到A级,再补充子资源完整性等策略可以冲击A+。
检测方式很简单,访问 Observatory 官网输入域名即可,也可以使用官方提供的命令行工具,方便在CI流程中集成自动检测:
# 使用npm安装Observatory命令行工具 npm install -g observatory-cli # 对目标站点进行安全评分检测 observatory --scan example.ipipp.com
Nginx安全响应头完整配置
安全响应头的添加通过add_header指令实现,建议统一放在http块或者server块中,避免在每个location里重复写。需要注意的是,Nginx的add_header有一个继承特性:如果某个location块内部出现了自己的add_header指令,那么父级配置中的所有add_header都不会被继承,这是很多人配置后不生效的根本原因。
下面是一份经过验证的完整配置,可以直接放入server块中使用:
server {
listen 443 ssl http2;
server_name example.ipipp.com;
# HSTS:强制浏览器在两年内使用HTTPS,包含子域名
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# 点击劫持防护:禁止页面被iframe嵌套
add_header X-Frame-Options "DENY" always;
# 禁止浏览器嗅探MIME类型
add_header X-Content-Type-Options "nosniff" always;
# 控制Referrer信息泄露
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 权限策略:禁用摄像头、地理位置等敏感API
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# 内容安全策略:限制脚本与样式来源,防止XSS
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'" always;
}关于CSP策略要特别说明一点:上面的配置采用了相对严格的白名单模式,只允许同源资源。unsafe-inline出现在style-src里是因为很多站点存在内联样式,如果直接去掉会导致页面样式错乱。正确的做法是先开启CSP的report-only模式观察一段时间,用Content-Security-Policy-Report-Only响应头收集违规报告,确认没有误伤后再切换为强制模式。另外frame-ancestors 'none'与X-Frame-Options功能类似,属于CSP的标准写法,两者同时配置可以兼顾新旧浏览器。
每个add_header末尾的always参数也很重要,它保证在返回404、500等错误状态码时,安全响应头依然会发送,不加这个参数的话,错误页面是不带头部返回的,扫描工具会判定配置缺失。
TLS协议优化与Cookie安全加固
除了响应头,Observatory还会检测TLS层配置。Nginx默认配置可能仍然允许TLS 1.0和TLS 1.1这类已被废弃的协议,需要手动限制为TLS 1.2和1.3,并启用前向保密相关的加密套件:
server {
# 只允许TLS 1.2及以上版本
ssl_protocols TLSv1.2 TLSv1.3;
# 优先使用服务端加密套件,启用OCSP装订
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
# 使用支持前向保密的高强度套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
# 会话缓存,减少握手开销
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
}Cookie安全方面,如果站点使用PHP-FPM,可以在php.ini中全局开启session.cookie_httponly和session.cookie_secure,这样所有会话Cookie都会带上HttpOnly和Secure属性,前者防止JavaScript读取会话标识,后者确保Cookie只在HTTPS连接中传输。应用层也可以在设置Cookie时显式声明:
<?php
// 设置一个带完整安全属性的会话Cookie
setcookie('session_id', $sessionId, [
'expires' => time() + 3600,
'path' => '/',
'secure' => true, // 仅HTTPS传输
'httponly' => true, // 禁止JS读取
'samesite' => 'Strict' // 防御CSRF
]);
?>验证评分与持续维护建议
配置修改完成后,先执行nginx -t检查语法,再用nginx -s reload平滑重载,随后用curl查看响应头是否生效:
# 检查配置语法 nginx -t # 平滑重载配置 nginx -s reload # 查看安全响应头是否正确返回 curl -sI https://example.ipipp.com | grep -iE "strict|content-security|x-frame"
确认响应头输出正常后,重新跑一次Observatory扫描,正常情况下能达到A级或A+级。需要注意的是,评分工具的规则会随安全形势演进,比如CSP的推荐策略就在不断收紧,建议把扫描命令接入部署流水线,每次发版自动检测,分数低于阈值就阻断发布,这样安全配置才能长期保持在一个较高水准,而不是一次性达标后逐渐劣化。