攻击
站点1
- 需要授权访问的内容页面 page2
@RequestMapping("page2")
@ResponseBody
public String page2(){
//需要授权
if(SecurityUtils.getSubject().getSession().getAttribute("user") == null){
return "<h1>没有登录,操作失败</h1>";
}else{
return "<h1>操作成功</h1>";
}
}
- 未登录访问,显示
- 登陆后访问,显示
站点2
访问效果如下:
通过JS可以实现打开站点2,自动调用 go csrf。也就是访问站点1需要登录才能操作的内容。
点击连接,如果站点1正好打开,浏览器内有session会话信息,并且已登录站点1,那么点击后如下图
也就是在用户未授权的情况下,站点2 访问了站点1需要授权的内容。同理,如果站点1是银行网站,page2是转账操作,那么如果用户在登录银行网站的同时,被诱导打开了站点2,可以在用户不知情的情况下实现转账操作。这就是所谓的csrf.
防御
通过referer字段,高速是从哪个连接过来的,可以用来避免跨站攻击。
代码如下:
@RequestMapping("page2")
@ResponseBody
public String page2(HttpServletRequest request){
//验证referer
String referer = request.getHeader("Referer");
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort() + request.getContextPath();
if(referer == null || !referer.startsWith(basePath)){
return "<h1>CSRF攻击拒绝</h1>";
}
//需要授权
if(SecurityUtils.getSubject().getSession().getAttribute("user") == null){
return "<h1>没有登录,操作失败</h1>";
}else{
return "<h1>操作成功</h1>";
}
}
再次通过站点2点击,显示:
Ajax rsrf
$("#ajax").click(function(){
var ref = "http://localhost:18080";
$.ajax({
url:"http://localhost:18080/demo/page2",
headers:{"X-Alt-Referer":ref, "Referer":ref},
dataType:"text",
success:function(data){
console.log(data);
}
})
})
如上图所示,请求被拦截,具体原因就是跨域请求.
另外一个就是不允许手动设置Referer字段,浏览器的安全还是可以的。