ログインする前に「記憶する」チェックボックスオプションを追加したい。
ユーザーのブラウザにクッキーを安全に保存する最良の方法は何ですか?
たとえば、Facebookには「remember me」チェックボックスがあり、facebook.comにアクセスするたびにすでにログインしていることがわかります。
現在のログインでは、単純なセッションを使用しています。
この質問はよく聞かれます。ここにいくつかのリンクがあります。
また、この質問への回答で収集されたいくつかの素晴らしいリソースがあります:ウェブサイト認証の決定的なガイド
更新(2017-08-13):の代わりに
selector
とtoken
を分離している理由を理解するためtoken
を使用するだけで、SELECTクエリのタイミング攻撃を防ぐためのトークンの分割に関する この記事をお読みください 。
このブログ投稿で説明されている戦略を抽出します 安全な長期認証について それは多くの分野をカバーしており、私たちは "remember me" 部分。
次のようなユーザーテーブルとは別のテーブルが必要です(MySQL):
_CREATE TABLE `auth_tokens` (
`id` integer(11) not null UNSIGNED AUTO_INCREMENT,
`selector` char(12),
`token` char(64),
`userid` integer(11) not null UNSIGNED,
`expires` datetime,
PRIMARY KEY (`id`)
);
_
ここで重要なことは、selector
とtoken
が別々のフィールドであることです。
random_bytes()
がない場合は、 random_compat のコピーを取得してください。
_if ($login->success && $login->rememberMe) { // However you implement it
$selector = base64_encode(random_bytes(9));
$authenticator = random_bytes(33);
setcookie(
'remember',
$selector.':'.base64_encode($authenticator),
time() + 864000,
'/',
'yourdomain.com',
true, // TLS-only
true // http-only
);
$database->exec(
"INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)",
[
$selector,
hash('sha256', $authenticator),
$login->userId,
date('Y-m-d\TH:i:s', time() + 864000)
]
);
}
_
_if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {
list($selector, $authenticator) = explode(':', $_COOKIE['remember']);
$row = $database->selectRow(
"SELECT * FROM auth_tokens WHERE selector = ?",
[
$selector
]
);
if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
$_SESSION['userid'] = $row['userid'];
// Then regenerate login token as above
}
}
_
セレクターには、9バイトのランダムデータ(12文字にエンコードされたbase64)を使用します。これにより、72ビットのキースペースが提供されるため、236 衝突耐性のビット(誕生日攻撃)。これは、ストレージ容量(integer(11) UNSIGNED
)よりも16倍大きいです。
実際のオーセンティケーターには、33バイト(264ビット)のランダム性を使用します。これは、すべての実用的なシナリオで予測不可能なはずです。
オーセンティケーターのSHA256ハッシュをデータベースに保存します。これにより、情報漏洩後のユーザーのなりすましのリスクが軽減されます。
ユーザーのCookieに保存されている認証子値のSHA256ハッシュを再計算し、 hash_equals()
を使用して保存されたSHA256ハッシュと比較して、タイミング攻撃を防ぎます。
DBルックアップは一定時間ではないため、セレクターを認証子から分離しました。これにより、劇的なパフォーマンスヒットを引き起こすことなく、検索に対するタイミングリークの潜在的な影響が排除されます。