如何在Vapor 3中处理密码散列?

时间:2019-01-06 22:55:22

标签: swift vapor

我正在建立一个基本的身份验证设置,类似于在Vapor的lw模板(来自here)中的使用方式。我已经按照模板中的所有方法进行了设置。

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

auth-template

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

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()
    }
}

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

在Vapor 3中是否有标准化的方法来处理密码哈希?

2 个答案:

答案 0 :(得分:5)

它在Vapor中的工作方式是每个BCrypt哈希都有一个唯一的盐,并使用密码保存在数据库中。 Vapor中的BCrypt默认功能可以实现这一点。

如果您想走一条不同的路线,请查看用于对密码进行哈希处理的函数-这需要花些时间。然后,您可以将其保存在其自己的字段中,并在验证密码时进行检索。老实说,除非您有非常具体的理由,否则我会说只使用默认值

答案 1 :(得分:1)

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

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

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

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

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

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

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

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