CORS跨域漏洞修复方案-渗透
前言
线上系统在等保测评的时候被扫出来了CORS跨域问题,但是根据网上大多数人用的方法之后,发现,还是能被扫出来问题,被这个问题困扰了很久,才找到了问题的解决方案,亲测有效!!!
CORS工作原理:
简单来说,CORS是一种访问机制,英文全称是Cross-Origin Resource Sharing,即我们常说的跨域资源共享,通过在服务器端设置响应头,把发起跨域的原始域名添加到Access-Control-Allow-Origin 即可。
CORS实现跨域访问并不是一蹴而就的,需要借助浏览器的支持,从原理题图我们可以清楚看到,简单的请求(通常指GET/POST/HEAD方式,并没有去增加额外的请求头信息)直接创建了跨域请求的XHR对象,而复杂的请求则要求先发送一个”预检”请求,待服务器批准后才能真正发起跨域访问请求。
根据官方文档 W3C规范-CORS 的描述,目前CORS使用了如下头部信息:
注:请求头信息由浏览器检测到跨域自动添加,无需过多干预,重点放在Response headers,它可以帮助我们在服务器进行跨域授权,例如允许哪些原始域可放行,是否需要携带Cookie信息等。
Request Headers(请求头)
- Origin
表示跨域请求的原始域。 - Access-Control-Request-Method
表示跨域请求的方式。(如GET/POST) - Access-Control-Request-Headers
表示跨域请求的请求头信息
Response headers(响应头 )
- Access-Control-Allow-Origin
表示允许哪些原始域进行跨域访问。(字符数组) - Access-Control-Allow-Credentials
表示是否允许客户端获取用户凭据。(布尔类型)
使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。 2.服务器端:设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。正确姿势如下: - Access-Control-Allow-Methods
表示跨域请求的方式的允许范围。(例如只授权GET/POST) - Access-Control-Allow-Headers
表示跨域请求的头部的允许范围。 - Access-Control-Expose-Headers
表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息) -
- Access-Control-Max-Age
表示预检请求 [Preflight Request] 的最大缓存时间。
使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。 2.服务器端:设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。正确姿势如下:
- Access-Control-Max-Age
- Access-Control-Allow-Methods
表示跨域请求的方式的允许范围。(例如只授权GET/POST) - Access-Control-Allow-Headers
表示跨域请求的头部的允许范围。 - Access-Control-Expose-Headers
表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息) - Access-Control-Max-Age
表示预检请求 [Preflight Request] 的最大缓存时间。
1.问题扫描报告
2.CORS实现跨域访问修复-Nginx方案
删除指定响应头信息
proxy_hide_header Access-Control-Allow-Origin;
添加指定响应头信息
add_header Access-Control-Allow-Origin 'https://www.baidu.com/';
- 配置location模块的
location / {
proxy_pass http://localhsot:8080/web
add_header Access-Control-Allow-Origin *.xxx.com;
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
}
- 在http中定义一个通过map指令,定义跨域规则并返回是否合法
http {
map $http_origin $allow_cors {
default 1;
"~.*baidu.com.*" 1;
"~.*192.168.1.10.*" 1;
"~.*192.168.1.11.*" 1;
"~.*" 0;
}
server {
location /school-openwork-order {
if ($allow_cors = 0){
return 403;
}
proxy_pass http://localhsot:8080/web;
}
}
}
3.CORS实现跨域访问修复-Java方案
- 配置CorsFilter(全局跨域)
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否发送Cookie信息
config.setAllowCredentials(true);
//放行哪些原始域(请求方式)
config.addAllowedMethod("*");
//放行哪些原始域(头部信息)
config.addAllowedHeader("*");
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
config.addExposedHeader("*");
//2.添加映射路径
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
- 重写WebMvcConfigurer(全局跨域)
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
//重写父类提供的跨域请求处理的接口
public void addCorsMappings(CorsRegistry registry) {
//添加映射路径
registry.addMapping("/**")
//放行哪些原始域
.allowedOrigins("*")
//是否发送Cookie信息
.allowCredentials(true)
//放行哪些原始域(请求方式)
.allowedMethods("GET","POST", "PUT", "DELETE")
//放行哪些原始域(头部信息)
.allowedHeaders("*")
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
.exposedHeaders("Header1", "Header2");
}
}
}
}
- 在方法上(@RequestMapping)使用注解 @CrossOrigin
@RequestMapping("/hello")
@ResponseBody
@CrossOrigin("http://localhost:8080")
public String index( ){
return "Hello World";
}
- 手工设置响应头(局部跨域 )
@RequestMapping("/hello")
@ResponseBody
public String index(HttpServletResponse response){
response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
return "Hello World";
}
- Filter过滤器跨域
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse rep = (HttpServletResponse) response;
// 设置允许多个域名请求
String[] allowDomains = {
"http://www.toheart.xin","http://192.168.11.213:8080","http://localhost:8080"};
Set allowOrigins = new HashSet(Arrays.asList(allowDomains));
String originHeads = req.getHeader("Origin");
if(allowOrigins.contains(originHeads)){
//设置允许跨域的配置
// 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
rep.setHeader("Access-Control-Allow-Origin", originHeads);
}