域
域既是 Windows 网络操作系统的逻辑组织单元,也是Internet的逻辑组织单元,它是安全边界
。
只有域的所有者才能访问管理域内部的资源,若其他的域要访问或者管理,则需要该域赋予其他域相关权限。
发生跨域请求的情况
当请求的资源与当前所在页面的资源的服务器不同的域、协议或端口不同的时候,如http://192.168.3.122:8080 这样一个地址。
- 域不同,地址换成了 192.168.3.123
- 协议不同,http变成了https
- 端口不同,原来是8080,换成了8081
- 在以上这些情况就会引起跨域问题。跨域一般产生在js的代码中,src等路径一般可以直接访问跨域资源
浏览器的同源策略
主要有两种
-
DOM 同源策略 : 禁止对不同源页面的 Dom 元素进行操作,主要是在 iframe 标签加载跨域页面出现。
-
XMLHttpRequest 同源策略 : 禁止使用 XHR 对象对不同源地址发起请求。
存储在浏览器中的数据,如localStroage、Cookie和IndexedDB不能通过脚本跨域访问
CSRF跨站请求伪造
如果没有 XHR 同源策略,以及不允许跨域获取cookies等的限制
那么攻击者将可以发起 **CSRF (跨站请求伪造)
**攻击场景可以如下:
- 你登录了某个银行网站,银行网站返回你的登录状态并且保存在cookies中。
- 你没有安全退出清空cookies,又刚好不小心浏览到了恶意网站
- 一进入恶意网站,它将会向
银行网站
发起XHR请求。(发送请求将会带上目标网站设置的cookies) - 银行拿到cookies,验证通过,返回数据。
CORS 跨域资源共享
CORS
是一个 W3C标准,该标准定义了在访问跨域资源时,服务端和客户端需要如何沟通,如何授权信任
原理:使用 http自定义头部 ,请求头附带客户端信息,服务端验证,并且返回响应头告诉客户端是否允许访问。
该标准需要客户端和服务端同时配合支持,当前所有的浏览器都支持该标准。 对于用户是无感知的,由浏览器自动完成只需要由服务端改动,前端不需要改动。
CORS将http请求分为简单请求和非简单请求
非简单请求
-
在发送真正请求之前,会先发送一次预检请求,来判断服务端是否支持非简单请求的类方法。预检请求包含跟简单请求一样的,还有指定
允许访问该资源的外域 URI
Access-Control-Allow-Origin
真实请求的方法
Access-Control-Request-Method
如PUT
、DELETE
是否需要附带cookie信息
Access-Control-Allow-Credentials: true
自定义复杂头部
Access-Control-Request-Headers
(可选) -
预检通过之后,浏览器会再次使用
真实请求方法
发起请求
第一次发送options方法进行预检请求,第二次才是真发送put,delect等方法。
注:在一个页面中,预检操作只需要进行一次。
OPTIONS
查询支持的方法
查询指定的 URL 能够支持的方法。
会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容
Java后端解决跨域方案拦截器WebMvcConfigurer
存笔记,方便以后Copy
前后端都需要解决跨域问题的方式有很多,Java解决的方式主要是添加注解的方式和采用添加拦截器的方法。
WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,提供很多自定义的拦截器,例如跨域设置、类型转化器等等
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 解决跨域问题
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
如果整合到Shiro+Jwt组合的安全拦截验证框架中,还需要再JwtFilter中加入,重写preHandle方法
@Component
public class JwtFilter extends AuthenticatingFilter {
@Autowired
JwtUtils jwtUtils;
......
.....
....其他方法,例如AuthenticationToken,onAccessDenied....
...
..
.
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
//跨域处理
HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
// 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(org.springframework.http.HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
}