事件采购和密码更改安全隐患

use*_*710 6 events password-protection event-sourcing

当密码更新问题出现时,我最近开始致力于事件采购.

我的理解如下:

  1. 事件存储在事件存储中,事件存储充当当前应用程序和对象状态的单一事实源.我们可能会在创建所述对象后重放给定对象的一系列事件,并找到该对象的当前状态.

  2. 事件必须无限期地存储,因为链中断会导致可能不一致的状态.如果每次为某些视图处理的事件太多,我们可能会创建事件链的快照(即对象的当前状态).

对我来说,这对于类似的东西有明显的安全隐患user updated password.在这种情况下,我们会看到类似的东西:

- UserCreatedEvent(user)
- ... // other events that might change the state of the User object
- UserChangedPasswordEvent(updatedPassword)
Run Code Online (Sandbox Code Playgroud)

我用这种方法看到的问题是,为了使应用程序保持一致状态,我们必须存储用户的所有先前密码,因为我们无法判断给定密码是当前密码还是用户以前的密码之一(给定只有UserChangedPasswordEvent).

为了论证,假设应用程序使用除了以外的较弱算法存储密码BCrypt,并且密码在给定的时间帧(即暴力/彩虹表)之后是可破解的.

在事件源的情况下,设法获得UserChangedPasswordEvent商店的攻击者现在将拥有用户在应用程序中使用过的所有密码的列表.在这种情况下,他们也不可能访问UserCreatedEvent商店,因此也可以访问用户的(通常)唯一电子邮件.

由于大多数临时用户不幸地在各种平台上重复使用密码,因此攻击者现在可能会访问用户可能在多个平台上使用过的任意数量的密码.如果存在诸如"X时间后强制密码更新"之类的机制,则会更糟.

尽管如此,这是最常见的事件源和密码更新方法,还是有一种标准化的方法来处理这部分应用程序?我承认场景的前提(弱密码哈希)是一个弱点,但它最好得到我的观点.

我可以想到两种方法来解决这个问题:

  • 加密事件存储和/或文件系统; 影响绩效
  • UserChangedPasswordEvent仅通知更改本身,密码通过其他渠道存储在其他地方; 然而,违背了事件采购的想法

我在这里推翻这个问题吗?是否有一个问题在这里,如果使用适当的散列算法?

Con*_*enu 5

实际上,将密码存储在事件中是一件非常危险的事情,但您没有真正的理由将密码存储在事件有效负载中.事实上,您甚至可能不会使用事件采购UserCredentialsSubdomain或整个事件AuthenticationDomain.

如果你仍然决定使用事件源AuthenticationDomain(这不一定是坏事),你不需要在里面存储密码,UserChangedPasswordEvent因为你不需要写模型中的整个密码历史记录(散列或明文).最后一个密码(或哈希)仅由身份验证服务用于验证用户的身份.没有其他Read模型需要这个; 您需要最近密码历史记录(即不允许更改为旧密码)的用例可以使用密码日志或类似的东西来实现,您不需要事件源.这UserChangedPasswordEvent可能很有用,例如向用户显示密码更改的最后日期,但不包含密码本身.

评论后更新:

您不需要在整个应用程序中使用ES,它不是所有ES或所有非ES.通常,对于身份验证,人们使用平面模型.但是,如果您选择使用ES,即使您没有用户密码,您仍然可以使用它来重建UserAggregate的状态,因为您实际上并不需要在此状态下使用该密码.

在我所指的这种情况下,密码检查是在UserAggregate(事件流的所有者)处理LoginCommand之前完成的,通过调用使用平坦持久性的PasswordCheckingService.这在应用程序层中完成:首先检查密码然后由UserAggregate进一步检查登录(即,如果用户仍处于活动状态,则可以登录).

实际上,从事件流中排除密码会让您意识到验证用户身份应该是一个单独的子系统,以及通过电话或生物识别扫描进行验证.在我看来,这会改变你的架构,使其更加清晰.整个身份验证可以隐藏在具有多个实现的简单接口之后.

您描述的场景不会明确地进行其他类型的调用

不,它不会或至少不会重建Aggregate的州.该远程调用将在Application层中完成.

在重建状态时调用外部服务是针对事件源 - 事件流必须足够.