目录
- 前言
- 1、使用 SSL/TLS 证书
- 2、使用安全密钥交换机制
- 3、禁用旧的 SSL/TLS 协议
- 4、禁用 SSL/TLS 弱密码套件
- 5、禁用不需要的 HTTP 方法
- 6、防止缓冲区溢出攻击
- 7、防止 CSP、XSS 攻击
- 8、防止 Click-jacking 劫持
- 9、禁用内容嗅探
- 10、图片防盗链
- 11、启用 HSTS 功能
- 12、仅允许通过域名访问
- 13、禁止自动用户代理
- 14、防止服务器信息泄露
- 15、升级 Nginx 版本
- 附件
前言
作为混迹于 IT 行业的一员,相信大家都接触过 Nginx Web 服务,不管是开发、运维、测试、还是算法都离不开 Nginx,而且大家对于 Nginx 的部署也是得心应手。但有的时候我们只局限于部署应用层面,没有考虑其运行在 Internet 上的安全问题,接下来将总结常用也是生产环境上有必要配置的一些安全策略。
1、使用 SSL/TLS 证书
传统的 HTTP 是一种以明文形式在端到端的超文本传输协议,在数据传输上存在很大的安全问题,如:窃听、篡改、冒充等安全问题。因此我们需要采用 SSL/TLS 证书来实现数据加密,SSL/TLS 证书是一种加密数字证书,用于对客户端(Web 浏览器)和服务器之间的流量进行加密
。通过这样做,加密是安全的,并且可以防止攻击者使用中间人攻击来窃听和窃取机密信息,例如用户名、密码和信用卡信息等
。
如何在 Nginx 服务器上配置?
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/bundle.pem;
ssl_certificate_key /etc/nginx/ssl/mytechnix.com.key;
}
# 当然,在我们实际应用中,不同的云厂商会提供相应的参考配置
2、使用安全密钥交换机制
DH 参数的目的是允许交换一个秘密,该秘密将用于加密会话中的消息副本。临时 DH 提供前向安全性,这意味着会话密钥在会话终止时被删除。因此,攻击者无法检索超过上一个会话的两方之间交换的消息。
使用 OpenSSL 生成至少 2048 位的唯一 DH 组:
openssl dhparam -out /etc/ssl/dhparam.pem 2048
- 1
如何在 Nginx 服务器上配置?
ssl_dhparam /etc/ssl/dhparam.pem;
3、禁用旧的 SSL/TLS 协议
较弱的 SSL/TLS 协议(SSLv2.0、SSL v3.0、TLSv1.0 和 TLSv1.1)可能容易受到攻击并导致诸如 BEAST(针对 SSL/TLS 的浏览器漏洞利用)、POODLE(在降级的旧版上填充 Oracle )等攻击。因此建议使用更新和安全的 SSL/TLS 协议。
如何在 Nginx 服务器上配置?
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/bundle.pem;
ssl_certificate_key /etc/nginx/ssl/mytechnix.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
}
4、禁用 SSL/TLS 弱密码套件
较弱且旧的密码套件配置可能会很容易使你的网站受到攻击,比如攻击者可能会拦截或修改传输中的数据。因此,你可以更具你不同的 Nginx 版本和 SSL/TLS 版本来选择更佳的密码套件,大家可以通过该网站来评估出最佳方案 —> 传送门。输入 nginx 和 SSL/TLS 版本后,会为你自动生成最佳配置文件,比如我输入的 Nginx 版本为 1.18.0、SSL/TLS 版本为 1.1.1,则会生成如下结果:
# generated 2022-04-27, Mozilla Guideline v5.6, nginx 1.18.0, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1k&guideline=5.6
server {
listen 80 default_server;
listen [::]:80 default_server;
location / <span >{<!-- --></span>
<span >return</span> <span >301</span> https://<span >$host</span><span >$request_uri</span><span >;</span>
<span >}</span>
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /path/to/signed_cert_plus_intermediates<span >;</span>
ssl_certificate_key /path/to/private_key<span >;</span>
ssl_session_timeout 1d<span >;</span>
ssl_session_cache shared:MozSSL:10m<span >;</span> <span ># about 40000 sessions</span>
ssl_session_tickets off<span >;</span>
<span ># curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam</span>
ssl_dhparam /path/to/dhparam<span >;</span>
<span ># intermediate configuration</span>
ssl_protocols TLSv1.2 TLSv1.3<span >;</span>
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384<span >;</span>
ssl_prefer_server_ciphers off<span >;</span> <span ># 需要使用的时候改为on即可</span>
<span ># HSTS (ngx_http_headers_module is required) (63072000 seconds)</span>
add_header Strict-Transport-Security <span >"max-age=63072000"</span> always<span >;</span>
<span ># OCSP stapling</span>
ssl_stapling on<span >;</span>
ssl_stapling_verify on<span >;</span>
<span ># verify chain of trust of OCSP response using Root CA and Intermediate certs</span>
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates<span >;</span>
<span ># replace with the IP address of your resolver</span>
resolver <span >127.0</span>.0.1<span >;</span>
}
location / <span >{<!-- --></span>
<span >return</span> <span >301</span> https://<span >$host</span><span >$request_uri</span><span >;</span>
<span >}</span>
ssl_certificate /path/to/signed_cert_plus_intermediates<span >;</span>
ssl_certificate_key /path/to/private_key<span >;</span>
ssl_session_timeout 1d<span >;</span>
ssl_session_cache shared:MozSSL:10m<span >;</span> <span ># about 40000 sessions</span>
ssl_session_tickets off<span >;</span>
<span ># curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam</span>
ssl_dhparam /path/to/dhparam<span >;</span>
<span ># intermediate configuration</span>
ssl_protocols TLSv1.2 TLSv1.3<span >;</span>
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384<span >;</span>
ssl_prefer_server_ciphers off<span >;</span> <span ># 需要使用的时候改为on即可</span>
<span ># HSTS (ngx_http_headers_module is required) (63072000 seconds)</span>
add_header Strict-Transport-Security <span >"max-age=63072000"</span> always<span >;</span>
<span ># OCSP stapling</span>
ssl_stapling on<span >;</span>
ssl_stapling_verify on<span >;</span>
<span ># verify chain of trust of OCSP response using Root CA and Intermediate certs</span>
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates<span >;</span>
<span ># replace with the IP address of your resolver</span>
resolver <span >127.0</span>.0.1<span >;</span>
5、禁用不需要的 HTTP 方法
常用的 HTTP 方法是 GET 和 POST,如果允许其他方法如 TRACE、DELETE、PUT 和 OPTIONS 是有风险的,因为这可能允许攻击者发起跨站点跟踪攻击
并从您的网站窃取 cookie
信息,因此建议禁用不需要的和未使用的 HTTP 方法。
如何在 Nginx 服务器上配置?
# 配置方式1:此时,服务器将只允许 GET、HEAD 和 POST 方法。
location / {
limit_except GET HEAD POST { deny all; }
}
# 配置方式2:效果同1
# 服务器只允许 GET、HEAD 和 POST 方法,并通过发出 444 No Response 状态代码过滤掉任何其他 HTTP 方法。
if (\(request_method</span> <span >!</span>~ ^<span >(</span>GET<span >|</span>HEAD<span >|</span>POST<span >)</span>\) )
{
return 444;
}
6、防止缓冲区溢出攻击
缓冲区是系统内存中的一个小型存储位置,当数据开始从一个内存位置传输到另一个内存位置时,它可以暂时容纳数据。当数据大小超过缓冲区大小的容量时,就会发生缓冲区溢出。因此,攻击者可以利用此漏洞注入可以危害系统的恶意代码。
如何在 Nginx 服务器上配置?
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
7、防止 CSP、XSS 攻击
CSP(内容安全策略)是额外的安全层,有助于缓解某些攻击,如 XSS 跨站脚本攻击。通过添加 CSP 标头,可以告诉浏览器它只能从你明确允许的域下载内容,包括 Javascript 和 CSS 文件。
如何在 Nginx 服务器上配置?
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
针对 XSS 跨站脚本攻击,可做以下参数配置:
add_header X-XSS-Protection "1; mode=block";
8、防止 Click-jacking 劫持
Click-jacking(即点击劫持)是一种 Web 应用程序漏洞,攻击者利用该漏洞强制用户在未经用户同意的情况下点击,导致重定向到未知网站。HTTP 响应标头中的 X-Frame -Option 可用于指示 Web 浏览器是否应在框架或 iframe 中加载页面。因此,在 nginx.conf 文件的 HTTP 标头中附加 X-Frame-Options,这将指示浏览器仅从同一来源加载资源。
如何在 Nginx 服务器上配置?
add_header X-Frame-Options "SAMEORIGIN";
9、禁用内容嗅探
内容嗅探,也称为 MIME(Multipurpose Internet Mail Extensions)
嗅探,即多用途网络邮件扩展
嗅探,是一种用于检查字节流内容以确定其中数据的文件格式的技术。这也可能导致安全漏洞,因为攻击者可以利用 MIME 嗅探来发送 XSS 跨站点脚本攻击。
例如,如果你的网站允许用户上传图片等媒体内容,攻击者可能会上传包含一些 JavaScript 代码的恶意图片文件。当浏览器进行内容嗅探时,可能会被诱骗执行该恶意文件。为了防止内容嗅探攻击,可将 X-Content-Type-Options
响应标头设置为 nosniff
,这告诉浏览器避免猜测响应类型并仅依赖 Content-Type
头。
如何在 Nginx 服务器上配置?
add_header X-Content-Type-Options nosniff;
10、图片防盗链
“图片防盗链”顾名思义就是防止别人盗用你的图片链接,这可能会导致你的带宽使用量增加,尤其是在现的服务器带宽使用策略中基本上都是按量付费的,因此这可能会间接性造成你们公司经济损失。
例如,假设在你 web 服务器根目录中有一个名为 images 的目录,其中存储了你在站点中使用的所有图像。为了防止其他方使用你的图像,你需要在 Nginx web 服务器上做如下配置。
如何在 Nginx 服务器上配置?
location /images/ {
valid_referers none blocked www.hello.com hello.com;
if ($invalid_referer) {
return 403;
}
}
11、启用 HSTS 功能
HSTS 功能只允许客户端(Web 浏览器)使用 HTTPS 进行通信,这 return 和 rewrite 方法的概念不同。当浏览器接收到 HSTS 标头时,它不会在指定的时间内以 HTTP 的形式与 web 服务端通信,保证了 HTTPS 严格安全传输问题。
如何在 Nginx 服务器上配置?
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
12、仅允许通过域名访问
上线过 web 应用的同志都知道,上线完成后 IP 或域名形式我们都可以访问,如果你不想允许使用 IP 地址的请求,那只需要在 Nginx 做以下配置即可。
if ($host !~ ^(mytechnix.com|www.mytechnix.com)$ ) {
return 301 https://mytechnix.com$request_uri;
}
13、禁止自动用户代理
为了保护你的服务器免受机器人、脚本和其他自动网页检索方法的侵害,请明确拒绝这些用户代理。
例如,像 wget 这样的应用程序可以检索整个文档根目录结构,使它们成为有用的 DoS 攻击者或只是访问网站上的受保护文件。
如何在 Nginx 服务器上配置?
if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
return 403;
}
14、防止服务器信息泄露
什么意思呢?Nginx 服务器的默认配置 server_tokens 指令在所有自动生成的错误页面以及 HTTP 响应标头上会显示 Nginx 版本号,我在之前做的一个项目中就存在这个问题,当时客户的安全工程师用工具扫出了这个问题。这可能会导致 web 服务器信息泄露,攻击者可以获得有关 Nginx 版本的信息,从而缩小攻击范围。因此,我们必须禁止在客户端(浏览器)显示 Nginx 版本号等相关信息。
如何在 Nginx 服务器上配置?
server_tokens off;
15、升级 Nginx 版本
建议将您的 Nginx 服务器更新到最新和稳定的版本,因为有很多性能改进、安全修复和新功能实现。
附件
通过上面的基础配置,现整合出完整的配置
#==========全局配置文件============
# 避免 Nginx 版本信息泄露
server_tokens off;
# 防止 Click-jacking 点击劫持
add_header X-Frame-Options SAMEORIGIN;
# 禁用内容嗅探,防止 XSS 跨站脚本攻击
add_header X-Content-Type-Options nosniff;
# CSP 内容安全策略,告诉浏览器它只能从你明确允许的域下载内容,防止 XSS 跨站脚本攻击
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# 启用 HSTS 功能,只允许客户端(Web 浏览器)使用 HTTPS 进行通信,保证了 HTTPS 严格安全传输问题。
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 防止缓冲区溢出攻击,免密攻击者恶意代码注入
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
#虚拟主机配置==
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name hello.com;
return 301 https://\(host</span><span >\)request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name hello.com;
<span ># SSL/TLS 证书/密钥</span>
ssl_certificate /etc/nginx/ssl/bundle.pem<span >;</span>
ssl_certificate_key /etc/nginx/ssl/hello.com.key<span >;</span>
<span ># DH 密钥交换机制,会话密钥在会话终止时被删除,攻击者无法检索双方之间交换的消息。</span>
ssl_dhparam /etc/nginx/ssl/dhparam.pem<span >;</span>
ssl_prefer_server_ciphers on<span >;</span>
<span ># 禁用旧的 SSL/TLS 协议</span>
ssl_protocols TLSv1.2 TLSv1.3<span >;</span>
<span ># 禁用 SSL/TLS 弱密码套件</span>
ssl_ciphers <span >'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'</span><span >;</span>+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'<span >;</span>
<span ># 禁用不需要的 HTTP 方法</span>
<span >if</span> <span >(</span><span >$request_method</span> <span >!</span>~ ^<span >(</span>GET<span >|</span>HEAD<span >|</span>POST<span >)</span>$ <span >)</span><span >{<!-- --></span>
<span >return</span> <span >444</span><span >;</span>
<span >}</span>
<span ># 图片防盗链</span>
location /images/ <span >{<!-- --></span>
valid_referers none blocked www.hello.com hello.com<span >;</span>
<span >if</span> <span >(</span><span >$invalid_referer</span><span >)</span> <span >{<!-- --></span>
<span >return</span> <span >403</span><span >;</span>
<span >}</span>
<span >}</span>
<span ># 仅允许通过域名形式访问 web 服务器</span>
<span >if</span> <span >(</span><span >$host</span> <span >!</span>~ ^<span >(</span>hello.com<span >|</span>www.hello.com<span >)</span>$ <span >)</span> <span >{<!-- --></span>
<span >return</span> <span >301</span> https://hello.com<span >$request_uri</span><span >;</span>
<span >}</span>
<span ># 禁止自动用户代理,防止 Dos 攻击</span>
<span >if</span> <span >(</span><span >$http_user_agent</span> ~* LWP::Simple<span >|</span>BBBike<span >|</span><span >wget</span><span >)</span> <span >{<!-- --></span>
<span >return</span> <span >403</span><span >;</span>
<span >}</span>
}
<span ># SSL/TLS 证书/密钥</span>
ssl_certificate /etc/nginx/ssl/bundle.pem<span >;</span>
ssl_certificate_key /etc/nginx/ssl/hello.com.key<span >;</span>
<span ># DH 密钥交换机制,会话密钥在会话终止时被删除,攻击者无法检索双方之间交换的消息。</span>
ssl_dhparam /etc/nginx/ssl/dhparam.pem<span >;</span>
ssl_prefer_server_ciphers on<span >;</span>
<span ># 禁用旧的 SSL/TLS 协议</span>
ssl_protocols TLSv1.2 TLSv1.3<span >;</span>
<span ># 禁用 SSL/TLS 弱密码套件</span>
ssl_ciphers <span >'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'</span><span >;</span>+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'<span >;</span>
<span ># 禁用不需要的 HTTP 方法</span>
<span >if</span> <span >(</span><span >$request_method</span> <span >!</span>~ ^<span >(</span>GET<span >|</span>HEAD<span >|</span>POST<span >)</span>$ <span >)</span><span >{<!-- --></span>
<span >return</span> <span >444</span><span >;</span>
<span >}</span>
<span ># 图片防盗链</span>
location /images/ <span >{<!-- --></span>
valid_referers none blocked www.hello.com hello.com<span >;</span>
<span >if</span> <span >(</span><span >$invalid_referer</span><span >)</span> <span >{<!-- --></span>
<span >return</span> <span >403</span><span >;</span>
<span >}</span>
<span >}</span>
<span ># 仅允许通过域名形式访问 web 服务器</span>
<span >if</span> <span >(</span><span >$host</span> <span >!</span>~ ^<span >(</span>hello.com<span >|</span>www.hello.com<span >)</span>$ <span >)</span> <span >{<!-- --></span>
<span >return</span> <span >301</span> https://hello.com<span >$request_uri</span><span >;</span>
<span >}</span>
<span ># 禁止自动用户代理,防止 Dos 攻击</span>
<span >if</span> <span >(</span><span >$http_user_agent</span> ~* LWP::Simple<span >|</span>BBBike<span >|</span><span >wget</span><span >)</span> <span >{<!-- --></span>
<span >return</span> <span >403</span><span >;</span>
<span >}</span>