springboot CSRF保护 spring security csrf原理_表单

SpringSecurity

本章我们会一边讲解SpringSecurity框架,一边从头开始编写图书管理系统。

SpringSecurity是一个基于Spring开发的非常强大的权限验证框架,其核心功能包括:

  • 认证 (用户登录)
  • 授权 (此用户能够做哪些事情)
  • 攻击防护 (防止伪造身份攻击)

我们为什么需要使用更加专业的全新验证框架,还要从CSRF说起。

CSRF跨站请求伪造攻击

我们时常会在QQ上收到别人发送的钓鱼网站链接,只要你在上面登陆了你的QQ账号,那么不出意外,你的号已经在别人手中了。实际上这一类网站都属于恶意网站,专门用于盗取他人信息,执行非法操作,甚至获取他人账户中的财产,非法转账等。而这里,我们需要了解一种比较容易发生的恶意操作,从不法分子的角度去了解整个流程。

我们在JavaWeb阶段已经了解了Session和Cookie的机制,在一开始的时候,服务端会给浏览器一个名为JSESSION的Cookie信息作为会话的唯一凭据,只要用户携带此Cookie访问我们的网站,那么我们就可以认定此会话属于哪个浏览器。因此,只要此会话的用户执行了登录操作,那么就可以随意访问个人信息等内容。

比如现在,我们的服务器新增了一个转账的接口,用户登录之后,只需要使用POST请求携带需要转账的金额和转账人访问此接口就可以进行转账操作:

@RequestMapping("/index")
public String index(HttpSession session){
    session.setAttribute("login", true);   //这里就正常访问一下index表示登陆
    return "index";
}
@RequestMapping(value = "/pay", method = RequestMethod.POST, produces = "text/html;charset=utf-8") //这里要设置一下produces不然会乱码
@ResponseBody
public String pay(String account,
                  int amount,
                  @SessionAttribute("login") Boolean isLogin){
    if (isLogin) return "成功转账 ¥"+amount+" 给:"+account;
    else return "转账失败,您没有登陆!";
}

那么,大家有没有想过这样一个问题,我们为了搜索学习资料时可能一不小心访问了一个恶意网站,而此网站携带了这样一段内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>我是(恶)学(意)习网站</title>
</head>
<body>
    <div>
        <div>对不起,您还没有充值本站的学习会员,请先充值后再观看学习视频</div>
        <form action="http://localhost:8080/mvc/pay" method="post">
            <input type="text" name="account" value="hacker" hidden>
            <input type="number" name="amount" value="666666" hidden>
            <input type="submit" value="点我充值会员,观看完整视频">
        </form>
    </div>
</body>
</html>

注意这个页面并不是我们官方提供的页面,而是不法分子搭建的恶意网站。我们发现此页面中有一个表单,但是表单中的两个输入框被隐藏了,而我们看到的只有一个按钮,我们不知道这是一个表单,也不知道表单会提交给那个地址,这时整个页面就非常有迷惑性了。如果我们点击此按钮,那么整个表单的数据会以POST的形式发送给我们的服务端(会携带之前登陆我们网站的Cookie信息),但是这里很明显是另一个网站跳转,通过这样的方式,恶意网站就成功地在我们毫不知情的情况下引导我们执行了转账操作,当你发现上当受骗时,钱已经被转走了。

而这种构建恶意页面,引导用户访问对应网站执行操作的方式称为:跨站请求伪造(CSRF,Cross Site Request Forgery)

显然,我们之前编写的图书管理系统就存在这样的安全漏洞,而SpringSecurity就很好地解决了这样的问题。