浏览器跨域问题
浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询。下面分别列举没有同源策略所会产生的问题。
1. CSRF
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
- 登录受信任网站A,并在本地生成Cookie(A)。
- 在cookie(A)未失效的情况下,登陆危险网站B
- 网站B去请求A
由于浏览器会自动带上网站A的用户cookie,所以网站A无法知道是用户的访问还是网站B进行的访问,这样B就相当于此用户进行了操作。这种要是发生在网上支付等会造成用户的损失。
2. Dom查询
我们可能会了解到一些短信诈骗情况,点击链接登录银行账户进行转账。比如中国银行的域名是www.zgyh.com,但是短信链接是www.zgyhh.com。这个页面内嵌了中国银行的登录页面,你可能就会进行登录。具体操作如下:
// HTML
<iframe name="zgyh" src="www.zgyh.com"></iframe>
// JS
// 由于没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom
const iframe = window.frames['zgyh']
const username = iframe.document.getElementById('username')
const password = iframe.document.getElementById('password')
console.log("用户名:" + username + ",密码:"+ password)
这样等于你在内嵌页面输入的信息我都能进行获取了。
怎样算跨域
所谓同源是指,域名,协议,端口均相同,不明白没关系,举个栗子:
http://www.123.com 与 http://www.123.com(非跨域)
http://www.123.com 与 http://www.456.com (主域名不同:123/456,跨域)
http://abc.123.com 与 http://def.123.com (子域名不同:abc/def,跨域)
http://www.123.com:8080 与 http://www.123.com:8081 (端口不同:8080/8081,跨域)
http://www.123.com 与 https://www.123.com (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
Java后端的cors过滤器
一.自定义cors的filter
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CORSFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(CORSFilter.class);
private List<String> corsOriginList;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String curOrigin = request.getHeader("Origin");
LOGGER.info("当前访问来源是:{}", curOrigin);
// 从列表中获取,可以将数据放入缓存
if (corsOriginList.contains(curOrigin)) {
response.setHeader("Access-Control-Allow-Origin", curOrigin);
} else {
return ;
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
corsOriginList = new ArrayList<String>();
// 初始化可访问的域名列表
corsOriginList.add("http://127.0.0.1:8888");
corsOriginList.add("http://localhost:8888");
}
}
二.配置filter
<filter>
<filter-name>cors</filter-name>
<filter-class>com.limbo.survival.common.web.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
基于nginx反向代理
一.nginx和反向代理
可以通过nginx的反向代理,将前后端应用放置到同一域。
所谓反向代理,就是在自己的域名下架设一个Web服务器,这个服务器会把请求转发给第三方服务器,然后把结果返回给客户端。这时候,在客户端看来,自己就是在和这台反向代理服务器打交道,而不知道第三方服务器的存在。
所以,如果有一个Web服务程序,它同时提供了反向代理功能和静态文件服务功能,静态文件服务负责渲染前端页面,反向代理则提供对第三方服务器的透明访问。那么前端和后端就变成了同源的,不再受同源策略的约束。
二.nginx配置
http {
include mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name www.web.com;
# 对静态文件的匹配
location ~* ^.+\.(xls|woff2|log|jpg|jpeg|gif|png|svg|ico|html|cfm|cfc|afp|asp|lasso|pl|py|txt|fla|swf|zip|wav|json|js|css|less)$ {
# 前端跳转
proxy_pass http://localhost:8888;
}
location /web/ {
# 后端跳转
proxy_pass http://localhost:8080;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
三.指定配置文件启动nginx
nginx -c /usr/local/etc/nginx/nginx.conf.my
四.前端访问路径
前端的访问路径都指向www.web.com