【问题标题】:How do I handle salting a password hash in Vapor 3?如何处理在 Vapor 3 中对密码哈希进行加盐处理?
【发布时间】:2019-01-06 22:55:21
【问题描述】:

我正在构建一个基本的身份验证设置,类似于它在 Vapor 的 auth-template 模板(来自 here)中的使用方式。我的所有设置都与模板中的方式相同。

但是,我想加盐。我可以在创建时为用户生成盐:

static func create(_ req: Request, newUserRequest user: CreateUserRequest) throws -> Future<User.Public> {
    return User.query(on: req).filter(\.username == user.username).first().flatMap { existingUser in
        guard existingUser == nil else {
            throw Abort(.badRequest, reason: "A user with the given username already exists.")
        }

        guard user.password == user.passwordVerification else {
            throw Abort(.badRequest, reason: "Given passwords did not match.")
        }

        let count = 16
        var pw_salt_data = Data(count: count)
        let _ = pw_salt_data.withUnsafeMutableBytes { mutableBytes in
            SecRandomCopyBytes(kSecRandomDefault, count, mutableBytes)
        }
        let pw_salt = try BCrypt.hash(pw_salt_data.base64EncodedString())

        let pw_hash = try BCrypt.hash(pw_salt + user.password)

        return User(id: nil, username: user.username, pw_hash: pw_hash, pw_salt: pw_salt, email: user.email).save(on: req).toPublic()
    }
}

但在登录期间执行身份验证时无法检索该盐:

static func login(_ req: Request) throws -> Future<UserToken> {
    let user = try req.requireAuthenticated(User.self)
    let token = try UserToken.create(userID: user.requireID())
    return token.save(on: req)
}

我希望为每个用户随机生成盐,并将其作为与哈希密码分开的列存储在数据库中,以便稍后在身份验证期间使用。

是否有一种标准化的方法来处理在 Vapor 3 中对密码哈希进行加盐处理?

【问题讨论】:

    标签: swift vapor


    【解决方案1】:

    它在 Vapor 中的工作方式是每个 BCrypt 哈希都有一个唯一的盐,该盐与密码一起保存在数据库中。 Vapor 中的 BCrypt 默认函数期望这一点。

    如果您想走不同的路线,请查看散列密码的函数 - 它需要一个盐。然后,您可以将其保存在自己的字段中并在验证密码时检索。老实说,我会说只使用默认值,除非你有非常具体的理由不这样做

    【讨论】:

    • 哦,我明白了,我没有意识到 BCrypt 会自动生成盐并将其存储在相同的数据中!谢谢你解释。我想我会坚持使用默认实现,因为我更好地理解了它。干杯!
    【解决方案2】:

    您使用 BCrypt 对密码进行哈希处理。 BCrypt 已经是 Vapor 依赖项的一部分。

    BCrypt.hash("vapor", cost: 4)
    

    这将使用随机生成的盐对字符串“vapor”进行哈希处理,复杂度为 4。选择成本是主观和任意的,但建议实际安全应用程序的成本系数应高于 10-12。如果您不喜欢 BCrypt 随机生成的 salt,并且想要生成自己的 salt,您可以将 salt 提供给哈希函数,该函数具有以下签名:

    public func hash(_ plaintext: LosslessDataConvertible, cost: Int = 12, salt: LosslessDataConvertible? = nil) throws -> String 
    

    文档说如果手动提供盐必须是 16 字节。 这是一个示例哈希:

    $2a$04$/nqhWqplnughhq6mlKmi8.raprxoG/dczY8kdbOKm.zC5sPu.2IBi
    

    如您所见,它包括辅助信息,例如复杂性、算法类型和盐,以及进行验证所需的一切。如果您提供了自己的盐,它也将成为最终哈希的一部分,您无需单独提供。您可以按照下面的说明进行验证。

    try BCrypt.verify("vapor", created: hashedPasswordSavedInDatabase)
    

    【讨论】:

    • 我明白了!从您的评论中,我能够找到更多文档 herehere。我没有意识到 BCrypt 会自动为我生成盐。现在我更好地理解了这一点,我将坚持使用默认实现。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多