【问题标题】:Fixing a timing attack修复定时攻击
【发布时间】:2021-06-06 01:21:42
【问题描述】:

我使用此代码登录用户。密码使用bcrypt 加密,SALT_ROUNDS 对每个用户都相同

const user = await User.findOne({email: args.email});
if (!user || !await user.comparePassword(args.password)) throw new Error("User or Password is not correct");

(comparePassword 是一个猫鼬函数)

UserSchema.methods.comparePassword = async function (candidatePassword) {
    return await bcrypt.compare(candidatePassword, this.password);
};

如您所见,由于短路,if-check 可能需要不同的时间来执行 - 这对于客户端来说是可衡量的。

这意味着,客户可以查明某封电子邮件是否使用了我们的服务 - 这是轻微的数据泄露。

我需要这样的脚本:

const err = new Error("User or Password is not correct.")
if (!user) {
  await "wait as long as a password comparison would usually take"
  throw err
} else if (!await user.comparePassword(args.password)) {
  throw err
}

但不知道如何实现。

一个想法是创建一个虚拟用户以在!user 上创建comparePassword,但我不确定这样做的优点/缺点或是否有更好的解决方案。

编辑:我将所有这些都包装在setTimeout 函数中怎么样?无论如何都需要 1 秒(或 500 毫秒或其他时间)。

【问题讨论】:

  • 有人还可以在 comparePassword 方法上设置断点,以查看它是否被调用 - 所以“等待一段时间”只是进一步踢罐子。
  • 只是想注意这在 npm 包自述文件 npmjs.com/package/bcrypt#a-note-on-timing-attacks 中得到了解决
  • @ihodonald 好像我读过最后一段。我认为比较也会节省时间。由于这个原因,低风险和我缺乏节省时间的技能,我想我会继续前进。
  • @riggedCoinflip 如果您在服务器上(或在无服务器函数中)使用此代码,则用户无法访问任何此代码。我不会把它放在客户端上。
  • 这是一个后端功能,我永远不会相信客户端会自己登录。但是可以测量服务器响应登录所需的时间。

标签: javascript bcrypt timing-attack


【解决方案1】:

我想出了这个解决方案:

const user = await User.findOne({email: args.email});

const start = performance.now()
const errorToThrow = (!user || !await user.comparePassword(args.password))
const timeElapsed = performance.now() - start

//console.log(`time elapsed: ${timeElapsed}`)
//wait constant time to protect against timing attacks
// OPTIMIZE still able to go for timing attack if `comparePassword` takes >1000ms
await new Promise((resolve) => {
    setTimeout(resolve, 1000 - timeElapsed);
});
//console.log(`Constant wait time: ${performance.now() - start}`)

if (errorToThrow) throw new Error("User or Password is not correct.")

//generate token
return jwt.sign({
        _id: user._id,
        username: user.name,
        role: user.role
    },
    process.env.JWT_SECRET, {
        expiresIn: "24h"
    });

测量性能表明这是可行的

#successful login
time elapsed: 111.46860000118613
Constant wait time: 1008.9731000009924
time elapsed: 77.95830000005662
Constant wait time: 1011.4061999991536
time elapsed: 77.98919999971986
Constant wait time: 1001.5624000001699
time elapsed: 73.09439999982715
Constant wait time: 1000.9662999995053

#user doesnt exist
time elapsed: 0.002399999648332596
Constant wait time: 1015.8186999987811
time elapsed: 0.002199999988079071
Constant wait time: 1006.2013000007719
time elapsed: 0.0023000016808509827
Constant wait time: 1006.3976000007242
time elapsed: 0.0037999991327524185
Constant wait time: 1003.9857000000775

#password incorrect
time elapsed: 74.4993999991566
Constant wait time: 1009.0491999983788
time elapsed: 73.85539999976754
Constant wait time: 1012.3958000000566
time elapsed: 75.48650000058115
Constant wait time: 1014.1987999994308
time elapsed: 71.53899999894202
Constant wait time: 1007.4519999995828
time elapsed: 74.53729999996722
Constant wait time: 1001.8896000012755

因此,除非服务器需要 10 倍于通常的时间来响应此工作。

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 2019-03-17
    • 2013-04-08
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2016-04-11
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多