【问题标题】:Password value object that can be either hashed or raw可以是散列或原始的密码值对象
【发布时间】:2014-08-06 20:32:50
【问题描述】:

我有以下值对象 (VO) Password。密码必须介于 6 到 20 个字符之间。但是由于我的UserMapper 在持久化实体之前对密码进行了哈希处理,所以我不知道我应该在这个 VO 中使用什么验证逻辑。

UserMapper 返回User 时,密码是60 个字符长的散列形式。

这是否意味着我必须在我的价值对象中考虑这两种情况?目前它会抛出 InvalidArgumentException 异常,因为该值不会介于 6 到 20 个字符之间,而是 60 个字符长(散列)。

namespace Models\Values\User;

use \InvalidArgumentException;

class Password
{
    private $min = 6;
    private $max = 20;

    private $password;

    public function __construct($password)
    {
        if (is_string($password) && !empty($password)) {
            $length = $this->stringLength($password);

            if ($length >= $this->min && $length <= $this->max) {
                $this->password = $password;
            }
        } else {
            throw new InvalidArgumentException(sprintf('%s must be a string from %s to %s characters.', __METHOD__, $this->min, $this->max));
        }
    }

    public function __toString()
    {
        return $this->password;
    }

    private function stringLength($string)
    {
        $encoding = mb_detect_encoding($string);
        $length   = mb_strlen($string, $encoding);

        return $length;
    }
}

【问题讨论】:

  • 为什么HashedPasswordPassword之间没有区别?
  • 我对 DDD 还是比较陌生,但这意味着它们中的任何一个都将始终是 null。注册时HashedPassword 为空,登录时Password 为空。实体中可以有空值吗?
  • 我对 DDD 也没有经验,只是一个想法,因为哈希密码和密码基本上是不同的东西
  • 另见 Openwall 的 PHP password hashing framework (PHPass)。它的便携性和强化了针对用户密码的一些常见攻击。编写框架 (SolarDesigner) 的人与编写 John The Ripper 并在 Password Hashing Competition 担任评委的人是同一个人。所以他对密码攻击略知一二。

标签: php validation hash domain-driven-design value-objects


【解决方案1】:

我同意上述评论中的@kingkero:将其设为两个不同的类。

我建议HashedPassword 只能通过Password 上的工厂方法创建(可能使用PasswordHashAlgorithm 服务作为参数),在Password 验证后将用于创建哈希密码输入。只有HashedPasswords 被持久化。

【讨论】:

  • 我的User 实体现在包含PasswordPasswordHash。为了散列密码(在我的UserMapper 中),我使用了可靠的内置 PHP 函数 password_hash()。我有一个UserFactory,它有一个build() 方法来构建完整的用户对象(使用从UserMapper 返回的数据)和buildFresh() 来构建new 用户对象并且仍然是被持久化(它保持 IdPasswordHash 为空,并使用 Password 代替)。我已经接受了你的回答,但我对你详细说明你的答案的方式有点困惑。那么,请您扩展一下吗?
  • 只有我的Password 包含验证逻辑,PasswordHash 没有,因为实际上不可能验证哈希本身。我只能检查哈希是否是正确的长度(60 个字符)。
  • 很抱歉,我没有完全理解您的问题。为什么你的User 包含Password PasswordHashUser 不需要 Password 吗?
  • 因为我的 VO 包含验证逻辑。并且Password(纯文本)与PasswordHash(散列)不同。 Password 用于注册新用户,PasswordHash 用于从我的数据库中检索,因为我的数据库中只存储散列密码。
  • 抱歉,我的意思是“User 不需要HashedPassword 吗?”。我认为不需要将Password 添加到User - Password 将在构造时验证输入,如果您随后将Password 传递给UserFactory,工厂可以散列验证密码并使用散列密码创建User
【解决方案2】:

长度的客户端密码验证可以在包含密码字符串项的文本框中。 之后,它应该被认为是一个安全的密码(如果密码存储接受它)。

之后,您不应从密码存储中设置或获取密码,而是要求存储为您验证密码。

所以我认为你检查密码强度为时已晚,除非你能早点做到。

【讨论】:

  • 那么你应该设置一个安全的(https)连接。
猜你喜欢
  • 1970-01-01
  • 2019-12-27
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2011-09-28
  • 2018-11-20
  • 2020-01-04
  • 1970-01-01
相关资源
最近更新 更多