为什么要使用默认站点空证书
开启HTTPS通信可以有效防范中间人攻击,是当前web安全的最佳实践之一。但是在默认情况下
通过IP直接访问443(HTTPS默认端口),nginx会认为是在访问第一个已配置的ssl server,将
请求发送至web节点,并在TLS通讯握手过程中返回该节点对应的证书信息。
这种默认行为会带来以下安全威胁:
服务器响应随意的攻击扫描请求
在公网上充斥各各种扫描攻击程序,他们会大范围的扫描IP和常用端口,对服务器发送无差别的请求。
处理这些请求可能导致额外的安全风险,以及额外的资源损耗。
泄露隐藏于站点防护之后的源站点信息
有时为了防御来自互联网的流量攻击,如DDos攻击,我们会把源站点部署在防御节点之后,即用户请求
先发送到防御服务器,web服务器处理由防御服务器转发来的请求。
这种情况下web服务器不应该直接处理任何流量,也不应该由用户直接访问。处于运维调试等目的,我们
仍然希望https端口可以访问,同时web服务器可以根据某些规则处理请求以便维护人员可以检查服务状态。
此时源站点信息应该是对外保密的,但如果证书信息泄露,可能导致攻击者绕过防御节点直接访问源站点,
造成损失。
如何解决?
通过制定nginx在处理没有制定域名(host)的请求直接返回默认http消息,可以避免信息泄露。
在http端口上的配置如下:
server {
listen 80 default_server;
server_name _;
return 444;
}
指定server_name
为空_
可以指定处理所有未匹配的server_name匹配规则的请求。http://nginx.org/en/docs/http/server_names.html
配置SSL端口也是相同的思路,但是SSL配置必须指定SSL证书私钥,因此我们需要生成一个本地的证书,
不带有任何站点信息。
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/conf.d/nginx.key -out /etc/nginx/conf.d/nginx.crt
运行后需要命令行交互输入一些参数,一直Enter使用默认值即可。生成的公钥证书为nginx.crt
,私钥证书为nginx.key
按需要将证书文件复制到nginx需要访问的位置。然后配置nginx ssl站点。
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/conf.d/nginx.crt;
ssl_certificate_key /etc/nginx/conf.d/nginx.key;
return 444;
}
可以将以上默认站点http端口和https端口配置在同一个文件中,如/etc/nginx/conf.d/default.conf
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/conf.d/nginx.crt;
ssl_certificate_key /etc/nginx/conf.d/nginx.key;
return 444;
}