cymapgt / usercredential
密码认证策略管理包
Requires
- php: >=7.3.0
- cymapgt/phpass: ^8.0.0
- freedsx/ldap: *
Requires (Dev)
- geerlingguy/ping: *
- phpunit/phpunit: 9.*
README
此包可以实现密码认证和政策管理。它可以执行多种类型的检查,以评估用户密码和认证过程是否符合安全建议。
描述
PHP UserCredential 包是一个可插入的服务,允许您验证密码和政策。它根据 OWASP Web 应用最佳实践指南推荐的密码策略集进行验证。
此包还提供了一个接口,允许插入第三方库,特别是用于多因素认证方法。为了说明如何做到这一点,我们已插入 MultiOTP 库(https://github.com/multiOTP/multiotp),用于提供此包的 SMS OTP 和 Google Authenticator TOTP 服务。
安装
通过 Composer 安装应用程序
require "cymapgt/usercredential": "*"
用法
概述
此包旨在用于使用密码进行认证且需要维护某种用户凭证政策的 PHP 应用程序。我们还提供利用 MultiOTP 库的多因素认证服务。
此包的目标是
-
实现密码加密和验证策略(目前是 PHP 的 bcrypt 库)
-
通过实施 OWASP 安全编码实践中的认证指南来实现认证和密码管理(https://www.owasp.org/index.php/OWASP_Secure_Coding_Practices_-_Quick_Reference_Guide)
-
提供一种简单的方法将密码策略集成到您的应用程序中。当您使用未经定制的默认配置的服务时,它提供以下功能
(版本 1.2 引入)
-
连续4次非法登录尝试后,账户将被临时锁定10分钟
-
在第5次连续非法登录尝试时,账户将被无限期锁定
-
用户不能重复使用过去5个密码
-
用户密码在45天后过期
-
当密码不符合所需熵时强制更改密码
-
所需的最小密码长度为8个字符
-
最小密码熵为2个大写字母字符,2个小写字母字符,1个数字字符和1个特殊字符
-
用户不能在密码字符串中使用他们的用户名,或他们的真实姓名(或部分)
(版本 1.3 引入)
-
密码不能包含超过2个连续字符(例如 aaa)
-
包含密码强度检查类(感谢 Ryan Chouinard 开发了可爱的 Phpass 包(rchouinard/phpass)https://github.com/rchouinard/phpass),我们为其分支用于强度功能检查,使用了 NIST 和 Wolfram 算法
- 提供一致的接口,无论使用的后端存储方式如何,都可以用于认证和政策过程
实施 OWASP 指南
-
所有认证控制都应安全失败:服务不会侵入。服务提供用户配置文件,并且它不会干预,除非它遇到认证或政策问题,此时它抛出 UserCredentialException,然后应该处理该异常
-
强制执行政策或法规规定的密码复杂度要求。认证凭证应足以抵御部署环境中常见的威胁攻击。(例如,要求使用字母以及数字和/或特殊字符):该服务有一种基于长度和复杂度实现用户定义策略的方法。然而,它不允许设置弱策略,因为它会将用户定义的策略与内置基本策略进行比较,如果用户定义的策略较弱,例如,如果用户定义策略中的密码长度为5个字符,它将回退到基本策略(根据OWASP为8个字符)。注意:回退功能尚未实现。
-
强制执行政策或法规规定的密码长度要求。通常使用8个字符,但16个字符更好或考虑使用多词密码短语:参见前一点
-
在达到一定次数的无效登录尝试后强制禁用账户(例如,五次尝试是常见的)。账户必须被禁用足够长的时间以阻止暴力猜测凭证,但不要长到允许执行拒绝服务攻击:该服务将账户临时锁定(基本策略为10分钟)以防止重复尝试。10分钟后,用户可以使用正确的密码成功登录。然而,如果在之后任何时间用户提供了另一个错误的密码,该服务将无限期地锁定账户,这将需要管理员干预才能解锁
-
强制在下次使用时更改临时密码:当使用弱密码时,该服务将建议/强制在下次尝试登录时更改密码
-
防止密码重用:该服务可以支持此功能。默认情况下不允许重复使用最后5个密码。用户定义策略可以增加这个数量。我们已经在一些环境中看到使用多达12个以前的密码。
-
根据政策或法规规定的要求强制更改密码。关键系统可能需要更频繁的更改。重置之间的时间必须由管理员控制:该服务默认密码过期期限为45天。可以使用用户定义策略方法设置更强大的用户定义策略(例如,30天)。
-
对高度敏感或高价值交易账户使用多因素认证:该服务实现了可以允许多因素认证的接口。
使用该包
命名常量
//UserCredential constants for user authentication
const USERCREDENTIAL_ACCOUNTSTATE_LOGGEDOUT = 1;
const USERCREDENTIAL_ACCOUNTSTATE_LOGGEDIN = 2;
const USERCREDENTIAL_ACCOUNTSTATE_LOCKED1 = 3;
const USERCREDENTIAL_ACCOUNTSTATE_LOCKED2 = 4;
const USERCREDENTIAL_ACCOUNTSTATE_RESET = 5;
const USERCREDENTIAL_ACCOUNTSTATE_SUSPENDED = 6;
const USERCREDENTIAL_ACCOUNTSTATE_AUTHFAILED = 7;
const USERCREDENTIAL_ACCOUNTSTATE_WEAKPASSWD = 8;
/**
* UserCredential constants for account policy actions. These also serve as
* exception codes during the authentication and policy check process.
* Internal Exception codes are documented in the EXCEPTIONS.md file
*/
const USERCREDENTIAL_ACCOUNTPOLICY_VALID = 1;
const USERCREDENTIAL_ACCOUNTPOLICY_EXPIRED = 2;
const USERCREDENTIAL_ACCOUNTPOLICY_ATTEMPTLIMIT1 = 3;
const USERCREDENTIAL_ACCOUNTPOLICY_ATTEMPTLIMIT2 = 4;
const USERCREDENTIAL_ACCOUNTPOLICY_REPEATERROR = 5;
const USERCREDENTIAL_ACCOUNTPOLICY_WEAKPASSWD = 6;
const USERCREDENTIAL_ACCOUNTPOLICY_NAMEINPASSWD = 7;
//Password strength constants
const PHPASS_PASSWORDSTRENGTHADAPTER_NIST = 0;
const PHPASS_PASSWORDSTRENGTHADAPTER_WOLFRAM = 1;
构建您的用户档案
- 此服务与用户和认证信息的后端存储解耦。它需要一个用户档案数组,您应该构建并提供给服务。
示例用户档案
array (
"username" => "james",
"password" => "m&$1eLe6Ke()", //Password provided by user when loggin in, else null if youre running this in session and not log in
"fullname" => "James Rodriguez",
"passhash" => "bcrypt",
"passhist" => array( //These should be already stored as encrypted in your backend store and would be of required entropy :)
\password_hash('abc', \PASSWORD_DEFAULT),
\password_hash('def', \PASSWORD_DEFAULT),
\password_hash('ghi', \PASSWORD_DEFAULT),
\password_hash('jkl', \PASSWORD_DEFAULT),
\password_hash('mno', \PASSWORD_DEFAULT),
\password_hash('pqr', \PASSWORD_DEFAULT),
\password_hash('stu', \PASSWORD_DEFAULT),
\password_hash('vwx', \PASSWORD_DEFAULT),
\password_hash('xyz', \PASSWORD_DEFAULT)
),
"policyinfo"=>array(
'failed_attempt_count' => 0,
'password_last_changed_datetime' => new \DateTime('2014-05-04'),
'last_login_attempt_datetime' => new \DateTime('2014-05-16 23:45:10')
),
"account_state" => \USERCREDENTIAL_ACCOUNTSTATE_LOGGEDIN
);
认证用户
该服务包含3种密码认证服务,您可以选择使用。有关使用每种服务以及实施密码策略的Wiki正在开发中。本文http://bit.ly/29m2aWL解释了使用数据库作为后端存储可能会有助于开始使用此包。
检查这些服务的测试文件以获取它们的工作原理的文档。
UserCredentialPasswordLoginService
此服务仅执行密码认证。要使用此服务,您需要将其连接到您正在使用的认证框架/插件。
UserCredentialSmsTokenLoginService
此服务生成令牌,并将其发送到映射到用户的手机号码或电子邮件。此类扩展了UserCredentialPasswordLoginService,执行认证的第一步。
UserCredentialGoogleAuthLoginService
此服务生成每30秒变化一次的TOTP令牌。因此,这些可以支持Google Authenticator。此类扩展了UserCredentialPasswordLoginService,执行认证的第一步。
认证后强制执行密码策略
use cymapgt\core\application\authentication\UserCredential;
//Build user Profile First (see sample above)
$userCredentialService = new UserCredentialManager($userProfile);
try {
$usercredentialService->validateEntropy();
$usercredentialService->validateLength();
$usercredentialService->validateConsecutiveCharacterRepeat();
$checkPolicy = true;
} catch (UserCredentialException $enException) {
$enExceptionId = $enException->getCode();
$checkPolicy = false;
//Handle the Exception...
}
if ($checkPolicy) {
try {
$usercredentialService->validatePolicy();
} catch (UserCredentialException $plcyException) {
//Handle the Exception...
}
}
//Yay, we made it. Do something Amazing ... :)
会话期间强制执行密码策略
- 会话期间的使用与上述相同,但您不能使用 validateEntropy() 等... 只能使用 validatePolicy() 等,例如在访问资源时,可能会计算45天已过并抛出异常,要求更改密码
使用Phpass验证密码强度
强度检查方法为静态,以便在不需要实例化 UserCredentialManager 类的情况下使用。因此,它也可以在用户更改密码或设置新密码时协助用户。
use cymapgt\core\application\authentication\UserCredential;
$passwordStrength = UserCredentialManager::passwordStrength($passwordString);
//do something like show strength bar, or enforce stronger password
测试
该软件包提供了PHPUnit测试
贡献
- 发送电子邮件至 @rhossis 或通过Skype联系
- 在GitHub上分叉存储库以开始对主分支(或从中分叉)进行更改。
- 您将被添加为贡献者
许可证
BSD 3 条款