http 中 origin 的含義:
跨域資源共享策略(cors)中灾而,當(dāng)瀏覽器發(fā)出跨域請求,會自動為請求頭帶上 origin 頭部
防護 csrf 的方法:
1.通過請求頭判斷請求是否與當(dāng)前頁面同源
檢驗 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
當(dāng)用戶請求一個網(wǎng)頁時候慕蔚,web 應(yīng)用生成一個與當(dāng)前 session 相關(guān)的 token,這個值存在服務(wù)器的 session 中斋配,并且把 token 發(fā)送給客戶端孔飒。當(dāng)客戶端發(fā)送"修改密碼"的請求的時候,在表單中用一個隱藏字段發(fā)送該 token 艰争,服務(wù)器驗證驗證 session 中存儲的 token 與客戶端發(fā)送來的 token 是否相同坏瞄,如果不相同或者沒有 token ,則拋棄該請求。
在 filter 中驗證請求中的 token
HttpServletRequest req = (HttpServletRequest)request;
HttpSession s = req.getSession();
// 從 session 中得到 csrftoken 屬性
String sToken = (String)s.getAttribute(“csrftoken”);
if(sToken == null){
// 產(chǎn)生新的 token 放入 session 中
sToken = generateToken();
s.setAttribute(“csrftoken”,sToken);
chain.doFilter(request, response);
} else{
// 從 HTTP 頭中取得 csrftoken
String xhrToken = req.getHeader(“csrftoken”);
// 從請求參數(shù)中取得 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;
// 動態(tài)生成 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 中含有只相當(dāng)頁的錨標(biāo)記
fragment = location.substring(fragmentIndex);
location = location.substring(0,fragmentIndex);
}
var index = location.indexOf('?');
if(index != -1) {
//url 中已含有其他參數(shù)
location = location + '&csrftoken=' + token;
} else {
//url 中沒有其他參數(shù)
location = location + '?csrftoken=' + token;
}
if(fragment != null){
location += fragment;
}
element.setAttribute(attr, location);
}
}