http 中 origin 的含义:
跨域资源共享策略(cors)中,当浏览器发出跨域请求,会自动为请求头带上 origin 头部
防护 csrf 的方法:
1.通过请求头判断请求是否与当前页面同源
检验 referer 字段,如果不存在则拒绝该请求!
注意,在检验的时候容易被绕过。如果你的站点是 site.com,要确保referer中是 site.com.attacker.com 不会被允许!
// 从 HTTP 头中取得 Referer 值
String referer=request.getHeader("Referer");
// 判断 Referer 是否以 bank.example 开头
if((referer!=null) &&(referer.trim().startsWith(“bank.example”))){
chain.doFilter(request, response);
}else{
request.getRequestDispatcher(“error.jsp”).forward(request,response);
}
2.csrf token
当用户请求一个网页时候,web 应用生成一个与当前 session 相关的 token,这个值存在服务器的 session 中,并且把 token 发送给客户端。当客户端发送"修改密码"的请求的时候,在表单中用一个隐藏字段发送该 token ,服务器验证验证 session 中存储的 token 与客户端发送来的 token 是否相同,如果不相同或者没有 token ,则抛弃该请求。
在 filter 中验证请求中的 token
HttpServletRequest req = (HttpServletRequest)request;
HttpSession s = req.getSession();
// 从 session 中得到 csrftoken 属性
String sToken = (String)s.getAttribute(“csrftoken”);
if(sToken == null){
// 产生新的 token 放入 session 中
sToken = generateToken();
s.setAttribute(“csrftoken”,sToken);
chain.doFilter(request, response);
} else{
// 从 HTTP 头中取得 csrftoken
String xhrToken = req.getHeader(“csrftoken”);
// 从请求参数中取得 csrftoken
String pToken = req.getParameter(“csrftoken”);
if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){
chain.doFilter(request, response);
}else if(sToken != null && pToken != null && sToken.equals(pToken)){
chain.doFilter(request, response);
}else{
request.getRequestDispatcher(“error.jsp”).forward(request,response);
}
}
在客户端对于请求加入 token
function appendToken(){
updateForms();
updateTags();
}
function updateForms() {
// 得到页面中所有的 form 元素
var forms = document.getElementsByTagName('form');
for(i=0; i<forms.length; i++) {
var url = forms[i].action;
// 如果这个 form 的 action 值为空,则不附加 csrftoken
if(url == null || url == "" ) continue;
// 动态生成 input 元素,加入到 form 之后
var e = document.createElement("input");
e.name = "csrftoken";
e.value = token;
e.type="hidden";
forms[i].appendChild(e);
}
}
function updateTags() {
var all = document.getElementsByTagName('a');
var len = all.length;
// 遍历所有 a 元素
for(var i=0; i<len; i++) {
var e = all[i];
updateTag(e, 'href', token);
}
}
function updateTag(element, attr, token) {
var location = element.getAttribute(attr);
if(location != null && location != '' '' ) {
var fragmentIndex = location.indexOf('#');
var fragment = null;
if(fragmentIndex != -1){
//url 中含有只相当页的锚标记
fragment = location.substring(fragmentIndex);
location = location.substring(0,fragmentIndex);
}
var index = location.indexOf('?');
if(index != -1) {
//url 中已含有其他参数
location = location + '&csrftoken=' + token;
} else {
//url 中没有其他参数
location = location + '?csrftoken=' + token;
}
if(fragment != null){
location += fragment;
}
element.setAttribute(attr, location);
}
}