两个“跑路”级别BUG复盘

自动登录越权

背景

小程序原生跳转到webview的H5页面时,需要打通用户登录;此时需要在跳转的URL上带上临时token,通过临时token换取登录cookie。

实现的方案为通过Node服务的拦截器,自动拦截小程序环境中的H5页面请求,自动设置上cookie。

问题&原因

自动登录相关的逻辑封装在AutoLogin类中,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 自动登录相关
*/
class AutoLogin {
constructor () {
this.ctx = null
}

init (ctx) {
this.ctx = ctx
return this
}

/**
* 触发条件
* @returns {boolean}
*/
trackRule () {

}

/**
* 自动登录逻辑
* @param res
*/
async autoLogin () {

}

/**
* 自动退出登录逻辑
* 备注:当实现小程序跳H5自动登录后,此时小程序退出登录,需同时保证H5页面也退出登录
*/
async autoLogout () {

}
}
}

module.exports = new AutoLogin()

核心原因在于this.ctx = ctx这一行,这行代码意味着在内存中持有了koa的ctx对象,当并发场景,会造成第一个请求链路还未完结时,ctx被替换为第二个请求的上下文对象了,从而造成header中的cookie信息不对,权限错乱。

类型异常

问题&原因

问题代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Object.entries(config.proxy).map(([path, target]) => {
let { url, login, intercept, extParams } = this.getProxyParams(target)
this.addRouter({
routerPath: `${routerRoot}${path}`,
target: url,
callback: async ctx => {
// 支持extParams为function类型,传入ctx方便从request中获取数据
extParams = Object.assign({}, typeof (extParams) === 'function' ? extParams(ctx) : extParams)
// 登录校验
if (login) {

}
// 接口透传
await proxy.launch({ url, reqParams }, ctx)
}
})
})

问题在于这一行代码extParams = Object.assign({}, typeof (extParams) === 'function' ? extParams(ctx) : extParams)

第一次请求的时候extParams为function类型,正常运行;第二次进来由于extParams已经变为了Object类型了,所以这段代码当第二个人请求进来时,永远都是运行的false逻辑,也就是第一个人ctx中的内容。

最后

  • 在Node服务中,切忌保存上下文对象,尽量不要持有跟用户相关的非全局信息
  • 缺少TS的场景下,注意JS的类型

留言

欢迎交流想法。留言会通过 GitHub Issues 保存,首次使用需要登录 GitHub。