1. 什么是前后端分离

从职责上区分:
负责交互与展示的部分为前端;
负责提供数据,处理业务的部分为后端。
核心思想是前端html页面通过ajax调用后端的restuful api接口并使用json数据进行交互。

2. 前后端分离架构的优势

1)提高工作效率,分工更加明确
前端只关注前端的事,后端只关心后端的活,两者开发可以同时进行。在后端还没有提供接口的时候,前端可以先通过Mock的方式模拟接口数据。页面的增加和路由的修改也不必再去麻烦后端,页面模板可以重复使用,开发更加灵活。
2)性能提升
前端页面可以按需加载,服务器也不需要解析前端页面,在页面交互及用户体验上有所提升。
3)降低维护成本
页面的调试不再需要后端人员的参与,可以非常快速的定位及发现问题所在,代码重构及可维护性增强。

推荐看一下这篇文章:《前后端分离的思考与实践(一)》,淘宝前端团队从开发角度详细阐释大厂在业务开发中使用前后端分离架构带来的优势,以及为何在前端技术栈要引入Node层。
下面我们就基于SPA+Node+JAVA的架构去聊一下前后端分离中可能存在的安全风险。

3. 安全风险分析

3.1 技术架构

spa_distributed
我们从图中可以看到前端工程师负责的静态资源和Node中间层部分开发和后端工程师负责的后端Server业务逻辑的开发。
②当用户携带token和请求业务单号applyNo,向Node.js Server请求,③④Node中间层通过thrift协议将token在用户中心验证并解析取出userid,⑤Node.js Server将userid与业务单号applyNo发送给后端,⑥后端根据传入的userid和业务单号applyNo进行业务逻辑,⑦返回数据。

3.2 越权漏洞的发生

3.2.1 参数归属校验缺失

后端没有校验前端传入的参数是否归属于当前登录用户:因为在第②步中前端的请求暴露在公网中可以任意请求和篡改的,例如我可以请求applyNo=123,也可以请求applyNo=456;虽然前端在第③④步中做了鉴权,并向后端发送了userid,但后端常常没有用到userid(缺少第⑥步中绿色部分),而是在业务逻辑中直接用applyNo进行业务逻辑并返回;这时候攻击者就可以构造大量applyNo请求,越权查询其他人敏感信息。

3.2.2 直接请求后端接口

从图中我们可知,攻击者也可以绕过Node.js Server层,直接向后端Server接口进行请求。即使在做了数据归属校验的情况下,如果直接向后端构造大量userid和applyNo请求,遍历两个参数,也可能造成大量敏感信息泄漏,只不过攻击成本高了许多。

3.2.3 前端框架引入的风险

在我们发现的漏洞案例中,因为前端框架Vue的路由配置模式“#”,而产生的不可预期的高危漏洞风险。
在vue的路由配置中有mode选项,最直观的区别就是在url中 hash 带了一个 # 而history模式是没有#的:
hash mode
hash-model
history mode:
history-model
而恰恰是因为这个#,导致前端先加载SPA单页应用的index.html可以浏览到后台dashboard等菜单,通过#的锚链接去路由各个前端界面,在浏览单页触发后端接口调用时发现登录态失效才会跳转到首页。
攻击者就会通过forexample.com/#/加载单页前端界面,偷窥web管理后台的相关界面和功能,会存在如下图中的情况:
router
原则上前端路由即使可以偷窥后台静态资源,也无法获取后端敏感数据,但在实际情况中后端某些接口疏忽了鉴权(例如上图中的/api/host)导致了敏感信息泄露。
我们应在加载index.html单页前进行鉴权,防止类似的事情发生。

4. 解决方案

  • 前端后端一起鉴权,Node层校验登录态,后端校验登录态,同时后端校验数据归属;
  • Vue-router使用“mode: history”模式,前后端一起配合鉴权。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    export default new Router({
    mode: 'history',
    base: 'c',
    routes: [
    {
    path: '/',
    // redirect: '/dashboard'
    redirect: '/dashboard'

    },
    ......

5. 参考链接

Vue-router 中hash模式和history模式的区别
前后端分离的思考与实践(一)

6. 致谢

感谢团队小伙伴对问题的探讨和开发实践。