1 问题描述

直接报错"检测到Access-Control-Allow-Origin头的许可权太多"

  • 漏洞名称: CORS 跨域
  • 漏洞等级: 中危
  • 漏洞证明: Origin从任何域名都可成功访问,未做任何限制。
  • 漏洞危害: 因为同源策略的存在,不同源的客户端脚本不能访问目标站点的资源,如果目标站点并配置不当,没有对请求源的域做严格限制,导致任意源都可以访问时,就能在 CORS 跨域漏洞问题,CORS 漏洞一般用于窃取用户敏感数据,如果用户点击触发了而已页面,就会被盗取数据。
  • 解决建议: 修复方法是合理配置 CORS,判断 Origin 是否合法。具体说就是请求头不要配置 Access-Control-Allow-Origin 为 * 或 null。

2 问题复现

2.1 环境准备

1、nginx配置
server{
    listen       8081;
    #基础管理页面:WEB-UI
    location / {
        root   /data/nginx;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

2、添加页面
echo "hello world" >> /data/nginx/a.html

2.2 使用postman

Nginx配置origin限制,修复CORS跨域漏洞_请求头

2.3 使用curl

curl -H "Origin: http://bogus.hc1.com" -v http://192.168.137.111:8081/a.html

Nginx配置origin限制,修复CORS跨域漏洞_跨域_02

3 解决办法

3.1 问题分析

  1. 需要一个正确的域名或者正则匹配域名告诉nginx怎么筛选
  2. 对于错误的请求头,处理办法
  3. 对于没有请求头的也需要考虑放行

3.2 添加请求头(无效)

location / {
    add_header Access-Control-Allow-Origin 'http://192.168.137.111:8081';
    add_header Access-Control-Allow-Methods GET, POST, OPTIONS;
    add_header Access-Control-Allow-Headers Content-Type;
}
发现即使添加了请求头配置,当origin为其他域名时仍能正常访问。
这个办法并不管用

3.3 http下配置map指令(可行)

3.3.1 配置规则

注意:在Nginx中,map指令通常用于定义一个变量映射,它只能放在http块内
1、在http中定义一个通过map指令,定义跨域规则并返回是否合法
http {
    # 说明:一般使用http_origin来进行跨域控制,当不传递origin头的时候,就为这个里面的默认值
    # 当传递有值得时候,才会走下面得正则匹配
    map $http_origin $allow_cors {
        default 1;
        #以下为提供参考的正则表达式
        "~^https?://.*?\.qingchen\.com.*$" 1;
        "~^(https?://(dmp.xxxxxx.cn)?)$" 1;
        "~http://192.168.137.111.*" 1;
        "~http://192.168.137.112.*" 1;
        "~*" 0;
    }
    ........
    server {
        location \ {
            if ($allow_cors = 0){
                return 403;
            }
        }
    }
}

2、如果想配置请求头部(非必选)
server {
    #指定允许其他域名访问        
    add_header Access-Control-Allow-Origin $http_origin;
    #允许的请求类型
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
    #许的请求头字段
    add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
}

3、解释
上述规则中,
a.当不传递origin头的时候,就为这个里面的默认值为1,
b.如果orgin的值为https://dmp.xxxxxx.cn或者含"qingchen"的,或者包含具体http://IP的,我们认为是合法的请求,返回数值1,如果是其它值,返回数值0

3.3.2 postman进行测试

Nginx配置origin限制,修复CORS跨域漏洞_请求头_03

3.3.3 curl测试

Nginx配置origin限制,修复CORS跨域漏洞_跨域_04

3.4 server下判断http_origin(可行)

3.4.1 配置规则

Nginx if语法不支持if条件的逻辑与&&逻辑或|| 运算 ,而且不支持if的嵌套语法。
1、需要借助变量来实现嵌套语法或多条件判断
server{
    listen       8081;
    #如果存在Origin头且Origin头不匹配指定的IP地址模式,那么返回403错误。
    set $flag 0;
    ##Origin有值的情况下。flag为01
    if ($http_origin) {
        set $flag "${flag}1";
    }
    ##Origin有值且不符合以下判断,flag为012
    if ($http_origin !~ "192.168.137.*") {
        set $flag "${flag}2";
    }
    if ($flag = "012") {
        return 403;
    }
...
}

2、解释
首先,根据给出的Nginx配置代码,我们来分析各部分的逻辑:
$flag 初始值为0。
如果 $http_origin 有值,则 $flag 加上 “1”。
如果 $http_origin 的值不匹配正则表达式 “19.166.2.54.*”,则 $flag 加上 “2”。
最后,如果 $flag 的值为 “012”,则返回403。

3.4.2 postman测试

Nginx配置origin限制,修复CORS跨域漏洞_请求头_05

3.4.3 curl测试

Nginx配置origin限制,修复CORS跨域漏洞_Access_06

Nginx配置origin限制,修复CORS跨域漏洞_跨域_07