概要
従来のID/PW認証に加えて、パスキー等の多要素認証の導入が進むことで認証は以前よりも強固になっています。しかしながら、認証後に発行されるセッションCookieをフィッシング等で詐取されてしまうと、強固な認証も意味がありません。
攻撃者は被害者のセッションCookieを詐取することで、被害者の認証済みセッションを悪用でき、多要素認証を実質的に迂回できます。
Device Bound Session Credentials (DBSC)はセッションCookieを詐取された際に被害を軽減する技術です。
DBSCの保護の仕組みは大きく2つです。
- セッションCookieを短寿命にする → 詐取されても短時間で使えなくなる
- Cookieの更新時に公開鍵認証を課す → 認証に使用したデバイス(の秘密鍵)がなければ更新できない
これにより、攻撃者がセッションCookieの詐取に成功しても、短時間で無効化されるため被害を軽減できます。
DBSCがChromeに実装されたので、①DBSCのデモサイトを構築し、②DBSCの動作について解説します。
この記事に書いてあること
-
DBSCとはなにか -
DBSCデモサイトを使って動作解説
DBSCの動作フロー概要
動作を詳しく見る前に、全体の流れをシーケンス図で確認します。
登録フロー(初回ログイン時)
リフレッシュフロー(Cookie期限切れ前)
DBSCの動作詳細
DBSCの理解を深めるためにデモサイトを実装したので、そのサイトを使いながら動作を解説していきます。
本サイトはDevice Bound Session Credentials(DBSC)の動作を学習・検証する目的で個人が構築したテスト環境です。
- 本番環境での利用を想定しておらず、可用性・セキュリティは保証しません。
事前準備として、使用しているChromeのバージョンによってはDBSC機能を有効化する必要があります。
下記サイトの手順に従うことで1分ほどで設定できます。
https://github.com/w3c/webappsec-dbsc/wiki/Testing-early-versions-of-DBSC
登録時
1. ユーザーがログインすると、サービスは Secure-Session-Registration ヘッダーを返す
下記はログイン時のサービスからのレスポンスです。いったんMax-Ageが長いCookie(Max-Age=2592000)を発行するとともに、Secure-Session-Registrationヘッダーを返しています。ヘッダーには登録エンドポイントとチャレンジが含まれています。
- ブラウザがDBSCに対応している場合:このヘッダーを見てDBSCのプロセスを開始し、完了後にCookieが短寿命に切り替わります。
- ブラウザがDBSCに対応していない場合:このMax-Ageが長いCookieにフォールバックし、従来通りのセッションCookieとして動作します(セキュリティレベルは従来と同等)。
HTTP/1.1 200 OK
Date: Thu, 09 Apr 2026 23:27:15 GMT
Secure-Session-Registration:(ES256);path="/app/StartSession";challenge="8Tqtssio_d23_ZaCNFucc8qBpcF7HWA9Es_eXWjKMP8"
Set-Cookie: short-term-cookie=hmwxSBU5-Rzwve7yicdS-MRBD2G8P9gv; Expires=Sat, 09 May 2026 23:27:15 GMT; Max-Age=2592000; Secure; HttpOnly; Path=/; SameSite=Lax
下記画像の「Start DBSC Session」ボタンを押すとDBSC保護対象のCookieが発行されます。
ボタンを押すとDBSCの機能チェック確認画面に遷移します。①から⑥までの全てのチェックが完了すると、ブラウザがDBSC対応していることが確認できます。
2. Chrome は鍵ペアを生成する
Secure-Session-Registrationを受け取ったブラウザはDBSCのプロセスを開始します。公開鍵認証に使用する鍵ペアを生成し、秘密鍵をTPMなどの安全な領域に保存します。これにより秘密鍵はデバイス外に持ち出せなくなります。
3. Chrome は登録エンドポイントへ公開鍵を送信する
サービスから受け取った登録エンドポイント/app/StartSessionへ公開鍵を送付します。公開鍵に対応する秘密鍵を保有していることを証明するために、チャレンジへの署名も一緒に送付します。公開鍵と署名はJWT形式でSecure-Session-Responseヘッダーに格納されます。
--> POST /app/StartSession HTTP/1.1
Host: www.infra-todo.jp
Secure-Session-Response: eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkZVU1NQbGN2TVJ2TzVvR1dfdHR6cUFNTE9oM0pTT3hkXzhRUm5SQ19RLW8iLCJ5IjoiRU45QjVvRTNoZGpIS0lQTlg2Y0V5c2hpR3gtM2NqSWRUUGRBUlExUDVkWSJ9LCJ0eXAiOiJkYnNjK2p3dCJ9.eyJqdGkiOiJjd1MwX2RVNHJRMWhBTXJKdVg2WWZqUzhVUmFzNV91dHhMLVJmcHF2T0NnIn0.SvRyC5pqRrbw3LeWydiq6zAj1g8035Utq0eaNkYP9qBSWodiJ7pvEzh6EeM65i0bEGKiQMb9U2JERtkY3PTjzA
Cookie: short-term-cookie=pg4L1SAXpci3FmrtwZWGj2nu1liEBDjR
DBSCの動作のうち、いくつかはChromeの開発者ツールからは確認できません。
chrome://net-export/ でイベントを取得した後に、下記サイトで中身を見ることができます。
https://netlog-viewer.appspot.com
4. サービスは公開鍵を現在のセッションに紐付けて保存する
サービスが署名検証(公開鍵でチャレンジへの署名を検証)に成功すると、200応答を返すとともに、公開鍵を現在のセッションに紐づけて保存します。このタイミングでCookieが短寿命に切り替わります。今回の例だとMax-Age=150
--> HTTP/1.1 200 OK
Secure-Session-Challenge: "H9xMHdrBVW1051SUmjWDt3aTbgUM7ww8aeO_t4QeBbQ";id="pg4L1SAXpci3FmrtwZWGj2nu1liEBDjR"
Set-Cookie: short-term-cookie=pg4L1SAXpci3FmrtwZWGj2nu1liEBDjR; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=150
レスポンスボディにはCookieの更新に使う更新エンドポイントの情報が含まれます。Chromeはこの情報をもとにリフレッシュ動作を行います。
{
"credentials": [
{
"name": "short-term-cookie",
"type": "cookie",
"attributes": "Path=/; Secure; HttpOnly; SameSite=Lax"
}
],
"refresh_url": "/app/dbsc/refresh"
}
リフレッシュ時
1. DBSC管理対象のCookieが期限切れになる
Cookieの期限切れ時、または期限切れの一定時間前に、Chromeがリフレッシュ動作を開始します。
【実装メモ】Chromeの事前リフレッシュタイミングについて
2026年4月時点のChromeでは、Cookieの期限切れ120秒前にリフレッシュを開始する実装になっています。そのため、CookieのMax-Ageを120秒より短くすると、リクエストのたびにリフレッシュが発生してしまいます。
筆者はMax-Ageを30秒ほどに設定して検証していたため、数秒の頻度でリフレッシュが発生してしまいました。
Chromiumのソースコードで確認できます:
https://chromium.googlesource.com/chromium/src/+/HEAD/net/base/features.cc
BASE_FEATURE_PARAM(base::TimeDelta,
kDeviceBoundSessionProactiveRefreshThreshold,
&kDeviceBoundSessionProactiveRefresh,
"Threshold",
base::Seconds(120));
2. Chrome は リフレッシュエンドポイントへ署名付きリクエストを送信する
Chromeはデバイス内の秘密鍵でチャレンジに署名し、Secure-Session-Responseヘッダーに格納してリフレッシュエンドポイントへ送信します。
-> POST /app/dbsc/refresh HTTP/1.1
Host: www.infra-todo.jp
Secure-Session-Response: eyJhbGciOiJFUzI1NiIsInR5cCI6ImRic2Mrand0In0.eyJqdGkiOiJIOXhNSGRyQlZXMTA1MVNVbWpXRHQzYVRiZ1VNN3d3OGFlT190NFFlQmJRIn0.iVpYLszWkOxlL1yVs0ZQrd8vpNEQZEtIE4wtAxr6mF7DBp0YzkUf1bHwVkJs7HprI-AaZEvLf6YB4Lq4CYGf1Q
Cookie: short-term-cookie=pg4L1SAXpci3FmrtwZWGj2nu1liEBDjR
3. サービスは署名を検証してセッションCookieを更新する
サービスが署名の検証に成功すると、Cookieを更新し、200レスポンスを返します。
Cookieの値がpg4L1SAXpci3FmrtwZWGj2nu1liEBDjRから5pWt394PKht4k69pKzSsEBoxY7J5NF40に更新され、次回更新用のチャレンジが事前に渡されます。
--> HTTP/1.1 200 OK
Date: Thu, 02 Apr 2026 09:55:25 GMT
Secure-Session-Challenge: "Ox_6jcq2dqd_awMMk-bcn7QlyCHIsze9Xg6atrrDKqM";id="pg4L1SAXpci3FmrtwZWGj2nu1liEBDjR"
Set-Cookie: short-term-cookie=5pWt394PKht4k69pKzSsEBoxY7J5NF40; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=150
リフレッシュに成功すると、画面上のチェックがすべて完了し、DBSCが動作していることを確認できます。
まとめ
本記事では、セッションCookieの詐取による多要素認証迂回という攻撃シナリオを踏まえ、DBSCの仕組みと動作をデモサイトを使って解説しました。
DBSCのポイントを改めて整理すると、以下のとおりです。
- 短寿命Cookie:セッションCookieのMax-Ageを短く(本記事では150秒)することで、詐取されても短時間で無効化される
- 公開鍵認証によるリフレッシュ:Cookie更新時にデバイス内の秘密鍵(TPM等に保存)で署名を行うため、秘密鍵を持たない攻撃者はCookieを更新できない
- フォールバック対応:DBSC非対応ブラウザでは長寿命Cookieにフォールバックするため、サービス側は段階的に導入可能
DBSCはCookieを盗まれること自体を防ぐ技術ではなく、盗まれた後の被害を最小化する技術です。フィッシングやAiTM(Adversary-in-the-Middle)攻撃への対策として、多要素認証と組み合わせることで多層防御を実現できます。



