配置 HSTS(HTTP Strict-Transport-Security头缺失或不安全)
HSTS是一种安全策略,即— HTTP Strict Transport Security,HTTP严格传输安全。假设TLS连接没有错误,兼容的浏览器将会在 max-age 参数指定的保留期内激活HSTS。它告诉浏览器:“只能用HTTPS来访问我的网站,不要用HTTP哦!”这样,即使有人尝试用不安全的方式(HTTP)来访问网站,浏览器也会自动切换到安全的方式(HTTPS)。
一旦站点启用了HSTS,用户的后续访问就会直接进入443端口,然而你还需要确保那些访问到80端口的用户能被重定向到正确的地址。为了支持这个重定向,而且由于在明文响应中HSTS响应头是不被允许的。
需要配置重定向
HTTP响应中包含 Strict-Transport-Security 头实现网站HSTS,像下面这样配置,就实现了HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Nginx配置HSTS的示例代码:
server {
listen 80;
server_name example.com;
# 重定向所有HTTP请求到HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
# SSL证书和其他SSL配置...
# 添加HSTS头部
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always ;
# 其他配置...
}
要注意 add_header 这个指令的继承方式,如果一个子配置块中设置了add_header 指令,那么在上层配置块中的 add_header 指令是不会被继承的。如果你需要在子配置中添加额外的add_header 指令,那么有关HSTS那部分要复制到子配置中。
https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header
这个配置做了什么呢?
- 重定向HTTP请求到HTTPS:在第一个server块中,我们监听HTTP 80端口,然后使用return 301 指令将所有HTTP请求重定向到HTTPS。
- 添加HSTS头部:在第二个server块中,我们监听HTTPS 443端口,并使用add_header指令添加一个名为Strict-Transport-Security的头部。这个头部告诉浏览器:“在接下来的31536000秒(也就是1年)内,只能用HTTPS来访问这个网站,而且也包括它的所有子域名。另外,如果你支持的话,请把这个策略预加载到你的缓存里。”
Strict-Transport-Security头部的参数解释:
max-age=31536000
:表示这个HSTS策略的有效期是31536000(单位是秒,31536000/3600*24 = 365天 =1年)。在这段时间内,浏览器会自动使用HTTPS来访问网站。includeSubDomains
:表示这个HSTS策略也适用于网站的所有子域名。preload
:是一个可选的参数,是一个为了解决第一次访问的用户,无法预先得知HSTS设置而创建的。它告诉浏览器:“如果你支持的话,请把这个HSTS策略预加载到你的缓存里。”这样,即使用户第一次访问网站时没有用HTTPS,浏览器也会知道应该使用HTTPS。always
:表示无论哪种请求都将HSTS的头发送给客户端,也包括错误响应。默认情况404等是不发送HSTS头的。
配置 CSP(Content-Security-Policy)
HTTP
Content-Security-Policy
响应头允许网站运营者能够控制遵循CSP的用户代理(通常是浏览器)可以为特定页面加载的资源,通过控制要启用哪些功能,以及从哪里下载内容,可以减少网站的***面。除了少数例外,策略主要涉及指定服务器来源和脚本终端节点。这有助于防范跨站点脚本G击 ( Cross-site_scripting )。
CSP的主要目的是,用于检测并削弱某些特定类型的G击,包括跨站脚本(cross-ste scripting,XSS)和数据注入G击等。无论是数据盗取、网站内容污染还是恶*软件分发,这些G击都是主要的手段。例如,CSP可以完全禁止内联的JavaScript,并且控制外部代码从哪里加载。它也可以禁止动态代码执行。禁用了所有的这些源,XSS变得更加困难。一个网站通过设置 Content-Security-Policy 响应头启用所需的CSP策略。
为使 CSP 可用,你需要配置你的网络服务器返回 Content-Security-Policy HTTP 标头(有时你会看到
X-Content-Security-Policy
标头,但那是旧版本,并且你无须再如此指定它)。
句法
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy
Content-Security-Policy: <policy-directive>; <policy-directive>
其中<policy-directive>
由以下部分组成: <directive> <value>
没有内部标点符号。
Fetch directives 通过获取指令来控制某些可能被加载的确切的资源类型的位置。
具体指令:
default-src:
默认策略script-src:
限制 JavaScript 的源地址。style-src:
样式,限制层叠样式表文件源。img-src:
限制图片和图标的源地址。connect-src:
链接,限制能通过脚本接口加载的 URL。font-src:
字体,设置允许通过 @font-face 加载的字体源地址。object-src:
插件<object>, <embed> 或者<applet>等media-src:
多媒体<audio>,<video>之类frame-src:
设置允许通过类似 <frame> 和 <iframe> 标签加载的内嵌内容的源地址。sandbox:
类似 <iframe> sandbox 属性,为请求的资源启用沙盒。Referrer-Policy:
用来指定会离开当前页面的跳转链接的 referer header 信息。
可取值与含义:
*:
任意来源none:
任何来源的都不加载self:
同源,与请求同源的资源可以加载https:
要求来源是https协议的https://xxx.com:
要求来源是https协议的某个站点css.test.com:
要求来源是某个站点*.test.com:
要求来源是某个站点及其所有的子站点blob:
允许加载 Blob 资源,通常用于 Web 应用的文件处理或视频流。data:
允许使用data:
协议加载数据 URI(如内嵌图片或字体)。但这也可能被用于 XSS G击,通常建议限制使用。unsafe-inline:
行内代码可以执行'unsafe-eval':允许动态代码执行,例如 JavaScript的 eval()方法unsafe-eval:
控制多种脚本执行方法,这些方法可根据字符串创建代码。
CSP 被设计成完全向后兼容(除 CSP2 在向后兼容有明确提及的不一致; 更多细节查看这里 章节 1.1)。不支持 CSP 的浏览器也能与实现了 CSP 的服务器正常工作,反之亦然:不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 标头,浏览器也使用标准的同源策略。
Nginx配置CSP的示例代码
这里 script-src 放开了允许内联js 'unsafe-inline'
,其实这里并不是很安全,但公司项目的前端架构已经成型改动代码工作量太大,先跟着指定的ip或域名访问这样配置着。后面有时间在出动态生成 nonce属性值的文档。
#使用 CSP
add_header Content-Security-Policy "default-src 'self' *.demo.com(该地址按需修改); script-src 'self' 'unsafe-inline' 'unsafe-eval' *.demo.com(该地址按需修改); img-src * data: blob:; style-src 'self' 'unsafe-inline' 'unsafe-eval' *.demo.com(该地址按需修改) https:; frame-ancestors 'self'; font-src * https: data:";
页面结果:
参考文献:
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
- https://www.w3.org/TR/CSP2/#directive-frame-ancestors
更多Nginx配置安全策略总结
“X-Content-Type-Options”头缺失或不安全
# 禁止服务器自动解析资源类型,防止浏览器对内容类型进行猜测,提升安全性
add_header X-Content-Type-Options nosniff;
nosniff 是禁止嗅探 ,服务器提示客户端一定按照 Content-Type 首部中的 MIME 类型来解析,而不能对其进行修改。
禁用了客户端的 MIME 类型嗅探行为,防止**代码的注入。开启 X-Content-Type-Options 要注意,要保证所传输的内容都要有正确 Content-Type 属性,要是没有这个属性,可能会造成加载不成功和无法运行;因为关闭了浏览器自动识别这一项。有些浏览器 如 IE9 ,IE11 在无法获得类型时,就不加载内容。
“X-XSS-Protection”头缺失或不安全
# 防止XSS跨站脚本G击
add_header X-Xss-Protection "1; mode=block";
XSS***:跨站脚本***:
X-Xss-Protection:4个选项值:
- 0: 不开启XSS保护
- 1: 开启保护(浏览器中一般默认),检测到跨站点脚本***,浏览器将删除不安全的部分。
- 1; mode=block 检测到***,浏览器将阻止页面的呈现
- 1; report=<reporting-uri> 检测到跨站点脚本***,浏览器将清理页面并报告违规行为。这使用CSP report-uri功能发送报告;只有chrome支持发送报告。
X-Frame-Options响应头防点击劫持
点击劫持(ClickJacking)是一种视觉上的欺骗手段。G击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。
HTTP 响应头信息中的X-Frame-Options,可以指示浏览器是否应该加载一个 iframe 中的页面。如果服务器响应头信息中没有X-Frame-Options,则该网站存在ClickJacking攻J风险。网站可以通过设置 X-Frame-Options 阻止站点内的页面被其他页面嵌入从而防止点击劫持。
# 防止嵌入 到frame 中;避免点击劫持***
add_header X-Frame-Options "SAMEORIGIN";
点击劫持,是在某个自身不安全站点的某个页面上有一个iframe加载了你的网站的某个页面,***者可以篡改这个iframe,诱使用户去点击,所以最好还是禁止iframe去加载你的页面;或者是同源和个别指定站点可以以frame形式加载你的页面。
X-Frame-Options 3个选项值:
- DENY: 拒绝一个页以frame方式加载(不能被嵌入到任何iframe或者frame中)。
- SAMEORIGIN: 同源域名下的页面,可以用frame方式加载(页面只能被本站页面嵌入到iframe或者frame中)。
- ALLOW-FROM URL: 允许指定的域名以frame形式加载。
检测到目标Referrer-Policy响应头缺失
当用户在浏览器上点击一个链接时,会产生一个 HTTP 请求,用于获取新的页面内容,而在该请求的报头中,会包含一个 Referrer,用以指定该请求是从哪个页面跳转页来的,常被用于分析用户来源等信息。但是也成为了一个不安全的因素,所以就有了 Referrer-Policy,用于过滤 Referrer 报头内容,其可选的项有: no-referrer no-referrer-when-downgrade origin origin-when-cross-origin same-origin strict-origin strict-origin-when-cross-origin unsafe-url
# 增加响应头配置
add_header Referrer-Policy "origin" always;
Referrer-Policy头信息是一种安全策略,用于控制浏览器在发送Referer HTTP头信息时包含哪些信息。当Referrer-Policy的值为"origin"时,浏览器会在HTTP请求头信息中包含当前请求的页面来源的完整URL,但不包括具体的路径和查询参数。例如,如果当前请求的页面URL为https://example.com/path/to/page,那么浏览器会在Referer HTTP头信息中包含https://example.com,但不包括路径和查询参数。
使用Referrer-Policy头信息可以提高Web应用程序的安全性,防止恶意站点通过Referer HTTP头信息获取用户的敏感信息。将Referrer-Policy的值设置为"origin"可以在一定程度上保护用户的隐私,同时又不影响Web应用程序的正常功能。
添加"always"参数可以确保该头信息始终向客户端发送,无论响应状态码是什么。
检测到目标X-Permitted-Cross-Domain-Policies响应头缺失
当一些在线的 Web Flash 需要加载其他域的内容时,很多 Web 会通过设置一个 crossdomain.xml 文件的方式来控制其跨域方式。很有可能有些开发者并没有修改 crossdomain.xml 文件的权限,但是又有和跨域的 Flash 共享数据的需求,这时候可以通过设置 X-Permitted-Cross-Domain-Policies 头的方式来替代 crossdomain.xml 文件,其可选的值有: none master-only by-content-type by-ftp-filename all
# 增加响应头配置
add_header X-Permitted-Cross-Domain-Policies "master-only" always;
X-Permitted-Cross-Domain-Policies头信息是一种安全策略,用于控制其他域名可以如何使用当前域名的资源。当浏览器收到包含X-Permitted-Cross-Domain-Policies头信息的HTTP响应时,会根据该头信息的值来限制其他域名对当前域名资源的访问。
配置值释义
none: 这是最严格的策略值,表示不允许任何跨域请求。这意味着浏览器不会处理任何来自其他域的请求,即使它们是有效的。
master-only: 这个策略值表示只允许来自主域的请求。主域是指与当前网页完全相同的域。
by-content-type: 这个策略值允许跨域请求,但只有当内容类型(Content-Type)与当前网页相同时才会被允许。这可以用于某些特定情况下的灵活配置。
by-ftp-filename: 这个策略值指定了只有通过FTP传输的请求才会被允许。这通常用于处理FTP服务器上的内容。
all: 这是最宽松的策略值,表示允许任何跨域请求。这将导致浏览器在处理跨域请求时不进行限制。
检测到目标X-Download-Options响应头缺失
未设置 "X-Download-Options" 响应头可能会导致安全问题,特别是在Internet Explorer浏览器中。这个响应头主要用于控制在IE浏览器中下载文件时的行为,以提高文件下载的安全性。以下是原理和修复方式:
# 增加响应头配置
add_header X-Download-Options "noopen" always;
"X-Download-Options" 是一个HTTP响应头,通常用于Internet Explorer浏览器。它的目的是控制浏览器是否允许文件下载和执行,以减少潜在的安全风险。
可用的策略值包括:
noopen:阻止IE浏览器自动打开下载的文件。
nosniff:防止IE浏览器尝试根据内容类型来解释文件,从而防止潜在的MIME类型混淆G击。
发现可高速缓存的SSL页面
# “Cache-Control: no-store”和“Pragma: no-cache”或“Cache-Control: no-cache”
add_header Cache-Control max-age=3600;
检测到SHA-1密码套件
ssl_ciphers ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE:!SHA-1;
ssl_prefer_server_ciphers on;
检测到隐藏目录
location ^~ /(html|static|img) {
deny all;
}
location ^~ /地址名称/对应的目录/ {
deny all;
}
error_page 403 =404 /404.html;
检测到支持较老的TLS版本
# TLSv1.2 以上版本即可
ssl_protocols TLSv1.2 TLSv1.3;
未实施加密
set $open_http 0;
if ($scheme = http) {
set $open_http "${open_http}1";
}
if ($scheme = https) {
set $open_http "${open_http}0";
}
if ($request_uri ~* "/地址名称/ajax/libs/") {
set $open_http "${open_http}0";
}
if ($request_uri ~* "/地址名称/js/") {
set $open_http "${open_http}0";
}
if ($open_http = "010") {
return 403;
}
启用了不安全的“OPTIONS”HTTP 方法
server {
...
# 如果我们在服务器环境中,最好使用这样的结构:
add_header Allow "GET, HEAD, POST" always;
if ($request_method !~ ^(GET|HEAD|POST)$) {
# 您还可以在“if”上下文中使用“add_header”:
# add_header Allow "GET, HEAD, POST" always;
return 405;
}
...
}
Nginx安全加固配置示例
http{
# ...
client_max_body_size 300M;
#安全加固
keepalive_timeout 55;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
limit_conn ops 20;
limit_conn_zone $binary_remote_addr zone=ops:10m;
autoindex off;
dav_methods off;
server_tokens off;
client_body_buffer_size 1K;
client_header_buffer_size 1k;
large_client_header_buffers 2 1k;
add_header Content-Security-Policy "default-src 'self' *.demo.com 'unsafe-inline' 'unsafe-eval' blob: data:;";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Permitted-Cross-Domain-Policies "master-only";
add_header Referrer-Policy "origin";
add_header X-Download-Options "noopen" always;
#add_header Clear-Site-Data: "*";
add_header Clear-Site-Data "storage";
add_header Cross-Origin-Embedder-Policy require-corp;
add_header Cross-Origin-Opener-Policy same-site;
add_header Cross-Origin-Resource-Policy same-site;
add_header Permissions-Policy "interest-cohort=()";
#防止XSS
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
#配置重定向404页面
proxy_intercept_errors on;
error_page 404 https://X.X.X.X/404;
# ...
server{
# ...
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE:ECDH:AES:HIGH:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:!NULL:!aNULL:!eNULL:!EXPORT:!PSK:!ADH:!DH:!DES:!MD5:!RC4;
ssl_prefer_server_ciphers on;
# ssl会话复用超时时间以及会话复用缓存大小
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
#强匹配,禁止访问某个页面,比如接口调用说明,不影响该地址后面加其他参数的访问
if ($request_uri = "/api/JBXQ_DLST/")
{
return 403;
}
#防止恶意域名解析和盗链
if ( $host !~* 'a.cn' )
{
return 403;
}
#请求方法限制
if ($request_method !~ ^(GET|HEAD|POST)$ )
{
return 501;
}
#封杀各种user-agent
if ($http_user_agent ~* "java|python|perl|ruby|curl|bash|echo|uname|base64|decode|md5sum|select|concat|httprequest|httpclient|nmap|scan|nessus|wvs" ) {
return 403;
}
#if ($http_user_agent ~* "" ) {
# return 403;
#}
#封杀特定的文件扩展名比如.bak以及目录;
location ~* \.(bak|swp|save|sh|sql|mdb|svn|git|old)$ {
rewrite ^/(.*)$ $host permanent;
}
location /(admin|phpadmin|status) {
deny all;
}
}
}