LockKeyPolicy
in package
ログイン試行ロックのキー生成
RateLimiter::validateLockPost() / RateLimiter::logLockPost() に渡す lockKey の組み立てを、 DB・セッションなどのグローバル状態に触れない純粋関数として切り出したもの。
Table of Contents
Methods
- forInputId() : string
- 入力されたユーザーID(user_code または user_mail)を元にしたロックキー
- forUserId() : string
- ユーザーIDを元にした2段階認証の試行ロックのキー
- hash() : string
- scope・種別・値を結合してハッシュ化する
Methods
forInputId()
入力されたユーザーID(user_code または user_mail)を元にしたロックキー
public
static forInputId(string $scope, string $inputId) : string
Why not: 入力文字列そのままの md5 だと、ユーザー検索(user_code = :id OR user_mail = :id)が
データベースの既定の照合順序(_ci)で大文字小文字を区別しない一方、カウンタのバケットは
表記ごとに分かれてしまう。そのため Foo@example.com と foo@example.com を交互に使うだけで
ロックを回避できてしまう。mb_strtolower() で正規化してからハッシュ化することで、
ユーザー検索と同じ粒度でバケットを揃える。
Parameters
- $scope : string
-
'Member_Signin' のようなロック対象の識別子
- $inputId : string
-
入力されたユーザーID(user_code または user_mail)
Return values
stringforUserId()
ユーザーIDを元にした2段階認証の試行ロックのキー
public
static forUserId(string $scope, int $userId) : string
Why not: ログインの lockKey は入力文字列(ID)に依存するため、2段階認証の判定でも 使い回すと ID の表記を変えるだけでバケットが変わってしまい、かつパスワード側の 予算を2段階認証の総当たりと共有してしまう(パスワード誤りで2段階認証まで ロックされる新たな利用者ロックアウトを生む)。2段階認証の時点では uid が確定しているため、 uid のみで別バケットのキーを作り、パスワード側の予算と分離する。
Parameters
- $scope : string
-
'Member_Tfa' のようなロック対象の識別子
- $userId : int
Return values
stringhash()
scope・種別・値を結合してハッシュ化する
private
static hash(string $scope, string $kind, string $value) : string
Why not: forInputId() と forUserId() を同じ scope で併用する(所見: パスワード側の ロックを入力IDベースとuidベースの2本立てにする)ようになったため、両者が生成する 文字列が絶対に一致しないことを保証する必要がある。単純な区切り文字(例: ':uid:') だけでは、$inputId 側にその区切り文字列を含む値を与えると衝突しうる (例: forInputId(scope, ':uid:1') と forUserId(scope, 1) が同じ文字列になる)。 $kind を 'id' / 'uid' の固定リテラルとして先頭に置くことで、$value の内容に関わらず 先頭バイト('i' と 'u')から必ず食い違い、文字列全体が一致しなくなる ('id' は 'uid' の接頭辞ではないため、値側の内容でこの食い違いを打ち消せない)。
Parameters
- $scope : string
- $kind : string
-
'id' または 'uid'
- $value : string