Nginx配置referer校验,实现简单的防盗链
1.0 背景
对增删修改类请求接口的referer做白名单校验或 在参数中增加随机,预防跨站请求伪造漏洞
2.1 Nginx Referer模块
ngx_http_referer_module模块用于阻止"Refer"头字段中具有无效值的来源非法的域名请求。使用适当的"Referer"字段值创建请求非常容易,这些伪造的"Referer"字段可能会包括一些不合法的字段。本模块的目的不是彻底阻止此类请求,而是阻止常规浏览器发送的大量非允许"Refer"请求。还需应考虑到,即使对于有效的请求,常规浏览器也不应发送"Referer"字段。
2.2 valid_referers
| Syntax: | valid_referers none | blocked | server_names | string ...; |
| -------- | ---------------------------------------------------------- |
| Default: | — |
| Context: | server, location |
none:请求头缺少Referer字段,即空Referer
blocked:请求头Referer字段不为空(即存在Referer),但是值被代理或者防火墙删除了,这些值不以“http://”或“https://”开头,通俗点说就是允许“http://”或"https//"以外的请求。
server_names:Referer请求头白名单。
arbitrary string:任意字符串,定义服务器名称或可选的URI前缀,主机名可以使用*号开头或结尾,Referer字段中的服务器端口将被忽略掉。
regular expression:正则表达式,以“~”开头,在“http://”或"https://"之后的文本匹配。
指定合法的来源'referer', 决定了内置变量$invalid_referer的值,如果referer头部包含在这个合法值里面,这个变量被设置为0,否则设置为1. 需要注意的是:这里并不区分大小写的.
2.2.1 Example Configuration
server {
listen 80;
server_name app123456.eapps.dingtalkcloud.com;
client_max_body_size 100m;
proxy_buffering off;
proxy_read_timeout 3600;
access_log /var/log/nginx/app123456.eapps.dingtalkcloud.com-access.log main;
error_log /var/log/nginx/app123456.eapps.dingtalkcloud.com.com-error.log;
if ($host != 'app123456.eapps.dingtalkcloud.com') {
return 403 ;
}
valid_referers server_names none *.test.com *.dingtalkcloud.com;
if ($invalid_referer) {
return 403;
}
add_header 'X-Permitted-Cross-Domain-Policies' 'master-only';
add_header 'X-Content-Type-Options' 'nosniff';
add_header 'X-XSS-Protection' '1; mode=block';
add_header 'X-Frame-Options' 'SAMEORIGIN';
add_header 'X-Download-Options' 'noopen';
location / {
proxy_pass https://123456-dingtalk-h5-dev.test.com;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /cb/ {
proxy_pass https://cb.test.com/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
上面配置合法的Referer为*.test.com *.dingtalkcloud.com 和 无Referer(none)(浏览器直接访问,就没有Referer) ; 其他非法Referer请求过来时, $invalid_referer 值为1 , 就return 403
2.2.1 验证效果
[root@10-80-15-202 ~]# curl -sI --referer "https://appxxx.eapps.dingtalkcloud.com" http://app123456.eapps.dingtalkcloud.com/self-serve
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 08 Mar 2023 07:12:49 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9316
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Encoding
Access-Control-Allow-Headers: accept,os,accesstoken,content-Type,X-Requested-With,Authorization,apptype,appkey,devid,token,uid,versioncode,versionname,mfg,x-request-id,x-request-uid
Access-Control-Max-Age: 2592000
Access-Control-Allow-Methods: GET, PUT, OPTIONS, POST, DELETE
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Permitted-Cross-Domain-Policies: master-only
X-Frame-Options: SAMEORIGIN
X-Download-Options: noopen
[root@10-80-15-202 ~]# curl -sI http://app123456.eapps.dingtalkcloud.com/self-serve
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 08 Mar 2023 07:12:49 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9316
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Encoding
Access-Control-Allow-Headers: accept,os,accesstoken,content-Type,X-Requested-With,Authorization,apptype,appkey,devid,token,uid,versioncode,versionname,mfg,x-request-id,x-request-uid
Access-Control-Max-Age: 2592000
Access-Control-Allow-Methods: GET, PUT, OPTIONS, POST, DELETE
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Permitted-Cross-Domain-Policies: master-only
X-Frame-Options: SAMEORIGIN
X-Download-Options: noopen
[root@10-80-15-202 ~]# curl -sI --referer "https://baidu.com" http://app123456.eapps.dingtalkcloud.com/self-serve
HTTP/1.1 403 Forbidden
Server: nginx
Date: Wed, 08 Mar 2023 07:10:41 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 146
Connection: keep-alive
Vary: Accept-Encoding