#password-hash #password #hash #security #crypto #building-block

nightly passwors

Passwors是一个简单的密码处理库,利用Rust的类型系统来强制执行更好的密码处理。将其用作更复杂认证系统的基本构建块。

2个版本

使用旧的Rust 2015

0.1.1 2016年8月30日
0.1.0 2016年8月30日

#2183 in 密码学

MIT许可协议

51KB
591

passwors

Passwors是一个简单的密码处理库,利用Rust的类型系统来强制执行更好的密码处理。将其用作更复杂认证系统的基本构建块。

Crates.io Latest Release Travis CI Build Status Dependency CI Status Clippy Linting Result MIT License

let pw      = ClearTextPassword::from_string(some_password_source).unwrap();
let salt    = HashSalt::new().unwrap();  // You should grab this from your database.
let a2hash  = Argon2PasswordHasher::default();
let pw_hash = pw.hash(&a2hash, &salt);

assert_eq!(pw_hash, stored_hash, "Login failed!");

查看文档

目录

为什么?

越来越多的Web应用程序是用Rust编写的,并且它们都需要密码处理。除此之外,还有很多网站在密码管理方面做得特别差。这个包旨在通过尽可能多地将其设计纳入最佳实践,使良好的密码处理变得简单,这样任何人都可以将其放入他们的项目中,而不必过多地担心细节。

那么,这些最佳实践是什么呢?

  • 密码应该难以猜测。
  • 密码是只有其所有者应该知道的秘密。
  • 应该使用强大的算法对密码进行散列,以保持明文密码的秘密性,同时仍然能够比较和存储“密码”。
  • 应使用随机数据对密码散列进行加盐。

现在,让我们看看Passwors是如何帮助实现这些目标的。

难以猜测

也称为衡量密码的“强度”。在这里,Passwors只强制实施最小和最大密码长度。在你感到恐慌之前:最大长度被设置得非常高,以至于即使是最疯狂的密码也不需要被截断。最小长度至少为14个字符,这是NIST在2016年建议的。此外,密码被视为原始字节的集合,这意味着没有任何东西阻止你在密码字段中支持所有的Unicode。你应该在密码字段中支持所有的Unicode。如果你想做得更花哨,可以在字段旁边添加一个完整的字符集。

然而,这些功能本身并不能使用户的密码更安全。字符类别要求也不能。要确保只有强密码被接受,你需要一个相当不错的密码强度计算器。我推荐使用zxcvbn。它有一些缺点,但总的来说,它是我知道的最好的计分器。

密码是秘密

是的,你的应用程序在某个时候必须接收用户的明文密码,但它不应该能够尝试读取它或获取任何其他信息,如其长度。你所能做的只是散列它,然后忘记它。

ClearTextPassword 完全就是这样做的。它阻止你在内存中留下不必要的明文密码副本,并阻止你读取、比较、存储或对其进行其他恶意的操作。一旦创建,你所能做的只是对其进行哈希处理。要获取 HashedPassword,你需要一个强制执行这些规则的 ClearTextPassword

ClearTextPassword 甚至在其 drop 期间将自己的内存清零,并清零其获取密码数据的来源。这确保了释放内存不会泄露旧明文密码一段时间。

额外说明:好的私钥存储使用技术甚至可以防止包含密钥数据的内存页面被交换到磁盘。我决定不使用这项技术,至少现在不使用,因为明文密码应该是非常、非常短暂的,尤其是在与解密私钥相比时,这使得它很少会被交换。

强大的密码哈希

这是最关键的安全问题。你选择了一个不好的哈希算法,比如MD5,你的安全就糟糕了。你创建了不必要的明文密码副本,你的安全可能会被削弱。你提供了不好的密码哈希器设置,你的安全就糟糕了。你没有使用给定的盐,你的安全就糟糕了。你的输出哈希非常小,你的安全就糟糕了。

因此,PasswordHasher 的哈希函数被标记为 unsafe。实现应谨慎选择。这就是为什么 Passwors 选项性地为你提供了一个默认实现,使用 argon2rs。其他好的哈希算法有 scryptbcrypt

加盐的哈希

要有一个好的盐,你应该有16字节或更多的良好随机数据。因此,HashSalt 是使用操作系统提供的CSPRNG创建的,并且至少有16字节大小。

构建Passwors

要编译 passwors 并将其用于自己的库或应用程序,你首先需要一个 nightly 安装Rust。将以下行添加到项目中的 Cargo.toml

[dependencies]
passwors = "*"

并在你的 lib.rsmain.rs 中添加此行

extern crate passwors;

然后你可以使用 Passwors 的类型

use passwors::{ClearTextPassword, HashedPassword, HashSalt, PasswordHasher};

由于 Passwors 使用了 Rust 的一些尚未稳定的功能,你需要一个 nightly Rust 安装。说到功能,有两个可选功能可以扩展 Passwors 的功能。默认情况下,Passwors 提供了一个默认的 PasswordHasher 实现,使用 argon2rs,并使用 serde 序列化 HashSaltHashedPassword。如果你不想使用 Argon2i 作为密码哈希器或 SerDe 来序列化数据,请禁用默认功能。然后你可以单独添加每个功能,通过将 use_argon2rsuse_serde 添加到你的 Cargo.toml

[dependencies.passwors]
version          = "*"
features         = ["use_serde", "use_argon2rs"]
default-features = false

用法

在处理密码时涉及四种类型

  • ClearTextPassword 是从用户输入中获得的。这是一个只有其创建者应该知道的秘密令牌。作为一个秘密令牌,你不能比较、复制或读取它。
  • HashedPassword 是用来验证某人身份的。它在那里被比较、存储、读取等。
  • HashSalt 是由强 CSPRNGs 生成的随机数据块。它应该为每个用户唯一生成,用于随机化明文密码的哈希结果。
  • PasswordHasher 是一个用于密码哈希器的 trait。它们是这里唯一的非安全组件,因为它们是唯一能够读取用户明文密码的组件。

许可协议

Passwors 使用 MIT 许可证。

版权所有(c)2016,Olaf "Evrey" Kukula

依赖关系

~2MB
~32K SLoC