阅读 126

jwt与接口token鉴权结合使用不完全指北

 最近在写一个新项目,主要做管理后台的。本来按照以往的项目架构设计,后台必须得是java大佬去撑场,我们前端做做页面,接接口渲染下数据就完事了。但是作为一个有“理想”的前端,耐不住自己要作死的心,打包票,直接前端一手包揽了。本次项目后台采用了nodejs+koa2+mongoose 框架结构进行设计开发。

6af89bc8gw1f8txigxessj205505i746.jpeg
 在愉快敲了一个月代码后,给领导演示后,领导觉得可以先上线,把项目跑起来,后续再继续迭代。激动的心,颤抖的手,我的项目要上线了???? ????????。提交测试,提交安全部门做渗透,上线时间都安排好了,晴天霹雳来了,安全报告给我一个大大的巴掌????。有一个高危和一个中危漏洞,安全部门只给了两天修复时间,过时不侯,不允许上线。????‍????哎,冷静下,还是想想怎么解决吧。这次主要重点讲讲高危漏洞的解决。

安全漏洞分析

 本次渗透测试出现的高危漏洞是存在越权漏洞,这类漏洞是指应用在检查授权(Authorization)时存在纰漏,使得攻击者在获得低权限用户帐后后,可以利用一些方式绕过权限检查,访问或者操作到原本无权访问的高权限功能。这次漏洞就是安全人员通过先登陆管理员账户,拿到账户uid,然后再登陆测试账户,将发送包里的uid改为管理员uid,从而获取到管理员的权限。在项目中,鉴权只做了token登陆态健全,没有做统一的权限鉴权。虽然在post接口内做了单独的权限校验,但是忽略了有些get请求的权限鉴权。这块的忽视,引发了这个漏洞。自己挖坑自己填。

006APoFYjw1fbpo1lrui2g302s02sjrq.gif

原先的jwt鉴权

 项目中登陆态鉴权 我们使用jsonwebtoken中间件。JWT(Json Web Token)是实现token技术的一种解决方案,JWT由三部分组成: header(头)payload(载体)signature(签名)。使用方式很简单:

  1. npm i jsonwebtoken 安装jwt

  2. 需要指定一个密钥(secret),可以保存在服务端配置文件里

  3. 引入并注册一个token签名

const jwt = require("jsonwebtoken")
const token = jwt.sign({ 
        uid: uid,
        ...
    }, SECRET, { expiresIn: "2h" })复制代码

这样子就生成一个token登陆态了。在登陆后下发给前端,在需要验证的接口头部里带上token
验证我们使用koa-jwt中间件验证,在app.js文件里,使用这个中间件app.use(koajwt({ secret: JWT_SECRET }) 他会自动校验header里authorization的字段。这样子就完成了登录态的校验。

现在的jwt与用户鉴权

 现在为了防止越权访问,我们需要将jwt的token利用起来,在app.js里我们写了个中间件,计划拦截所有带有token的接口。

app.use(async (ctx, next) => {
    if(ctx.request.get("token")){
      const verifydata = ctx.method=="POST" ? ctx.request.body : ctx.request.query
      
      const uid = verifydata.uid || ctx.request.get("uid")
      const tokenstatus = await tokenVerfiy(ctx.request.get("token"),uid)
      if(!tokenstatus){
        ctx.body = '';
        ctx.status = 403;
        return
      }
})复制代码

接下来编写tokenVerfiy校验函数

const jwt = require('jsonwebtoken');
const {JWT_SECRET} = require('../config')
const tokenVerfiy = async (token,uid)=>{
   if(!uid){return false}
   try {
    // 解密token,提出内容体
    const decoded = jwt.verify(token,JWT_SECRET) 
    // 后台接口设计默认uid字段是当前用户id字段,固定用户字段 
    if(uid && uid != decoded.uid){ // 如果存在用户参数id
        console.error("token鉴权失败,用户ID与token内ID不匹配")
        return false
    } 
    if(xx){ // 一些其他的敏感校验
        // do something
    }
    return true
   } catch (error) {
       console.log("token鉴权失败",error)
       return false
   }
}

module.exports = tokenVerfiy复制代码

这样,每一个带有token的请求,都会执行以上的函数。通过获取到接口body里的uid或者header头部里uid的字段,然后与在登陆后jwt生成token后解密出来的内容体中信息进行匹配。这样子初步可以进行登陆鉴权与用户鉴权相互结合使用,让这个漏洞打上了个补丁。注意:在实际项目中必须要对jwt.verify进行try catch捕捉错误,因为如果token过期或者无效会直接抛出错误。

写在最后

 可以交差了????。在解决完所有的漏洞后,怀着忐忑的心,再次提交安全测试,幸运的是这次没问题,如期上线。这次漏洞也让我警醒,安全无小事,不要因为懒而不做安全防护。毕竟,你现在不做,后面就得花更多的时间去补救。


作者:带上小鱼干去旅游吖
链接:https://juejin.cn/post/7065222051929260040


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐