DAT (Distributed Access Token)

1. 概要

同時接続ユーザー数の増加にともないセッション (Session) の数も増え、セッションサーバーに過大な負荷が発生します。

DAT は、このようなセッションサーバーの負荷問題を解決し、サーバー間で状態を共有しない (Stateless) 効率的な認証を実現するために考案されたトークン仕様です。

DAT はピリオド (.) で区切られた 5 つの固定フィールドから成る文字列です。JSON パースなしに区切り文字の位置だけで各フィールドを切り出すことができ、有効期限と暗号化領域が仕様そのものに含まれています。


2. ワイヤーフォーマット

DAT ワイヤーフォーマット
expire
uint64 (10進)
.
cid
uint64 (16進)
.
plain
Base64Url
.
secure
Base64Url
.
signature
Base64Url
各フィールドにマウスを乗せると説明が表示されます。
expire . cid . plain . secure . signature
フィールドエンコーディング備考
有効期限uint6410 進文字列Unixtime (秒)
CIDuint6416 進文字列証明書 ID
平文データBinaryBase64Url (パディングなし)公開データ
暗号化データBinaryBase64Url (パディングなし)暗号化データ
署名BinaryBase64Url (パディングなし)署名
構造
サンプルrefresh
/

2.1. フィールド別詳細仕様

有効期限 : uint64 (Unix Time)

  • トークンの有効期限を秒 (Seconds) 単位の 64 ビット符号なし整数で表します。
  • 純粋な 10 進数字のみを許可します。符号・空白・区切り文字が含まれる場合は形式エラーです。

CID : Hex (uint64)

  • トークン検証に使用する証明書 ID (Certificate ID) です。
  • 純粋な 16 進数字のみを許可し、0x プレフィックスは使用しません。

平文データ : Base64Url (Binary)

  • クライアントに公開するデータを格納します。文字列だけでなくバイナリデータもサポートしており、クライアント側でデコードして確認できます。
  • 暗号化されません。 機密性のある値を入れてはいけません。

暗号化データ : Base64Url (Binary)

  • クライアントに非公開とするデータを格納します。証明書の暗号化アルゴリズムで暗号化されているため、証明書を持たないクライアントは内容を復号できません。
  • 内部構造は IV(96bit) + 暗号文 であり、IV は暗号化のたびに新しく生成されます。

署名 : Base64Url (Binary)

  • トークンの改ざんを検証するための署名データです。先行するフィールドを証明書の署名アルゴリズムで署名して生成します。
  • 署名検証に失敗したトークンは、どのフィールドも信頼してはいけません。

3. 正規ルール (Canonical Rules)

複数の言語で実装されたクライアントが同じトークンを同じように解釈するためには、以下のルールが実装ごとに食い違ってはなりません。リファレンス実装は Rust (dat-rust) であり、その他の実装はすべてこのルールに合わせられています。

3.1. 数値フィールドのパース

expirecid厳格に解釈します。以下の入力はすべて形式エラーとして拒否されます。

入力例結果理由
100通過純粋な 10 進
007通過先行ゼロは許可
+100拒否符号は使用不可
-1拒否符号は使用不可
" 100 "拒否空白は不可
1_0拒否区切り文字は不可
0x10拒否プレフィックスは不可
zzzz拒否数字ではない
""拒否空文字列
18446744073709551616拒否uint64 の範囲を超過

なぜ厳格でなければならないのか

寛容なパーサーは -1 を uint64 の最大値に折り返して事実上失効しないトークンを作り出したり、数字でない値を黙って 0 に置き換えたりします。実装ごとに寛容さが異なると、同じトークンが一方では通過し他方では拒否され、相互運用が壊れます。

3.2. 有効期限の判定

DAT トークンと証明書では有効期限の境界が異なります。 混同しないでください。

対象有効条件有効期限ちょうど (expire == now)
DAT トークンexpire > now失効として拒否
証明書expire >= nowまだ有効

トークンは有効期限に達した瞬間ただちに無効となり、証明書はその時刻まで有効です。境界で発行されたトークンを検証できるようにするため、証明書はトークンより 1 ティック長く生きている必要があるからです。

3.3. 空の secure ペイロード

暗号化するデータがない場合、secure空文字列です。

  • encrypt(空の入力) → 空の出力 (IV も GCM タグも付きません)
  • decrypt(空の入力) → 空の出力
  • 空でないのに IV の長さ (12 バイト) 以下である場合は復号エラーです。
1893456000.1a.SGVsbG8..T3RoZXItc2lnbmF0dXJl
                      ↑ secure の位置が空である正常なトークン

4. 発行と検証

DAT 発行 → 受け渡し → 検証
DAT CMS
発行サーバー
クライアント
検証サーバー
証明書の配布
証明書の配布
ログイン
issue(plain, secure)
DAT の発行
DAT 付きリクエスト
CID で証明書を照会 → 署名検証 → 復号
レスポンス
リクエストレスポンス証明書の同期

4.1. 発行手順

  1. マネージャーが保有する証明書のうち、発行可能な (issuable) 証明書を選びます。
  2. expire = now + dat_ttl_seconds を計算します。
  3. plain を Base64Url でエンコードし、secure は暗号化したうえで Base64Url でエンコードします。
  4. expire.cid.plain.secure の文字列に署名し、最後のフィールドとして付け加えます。

4.2. 検証手順

  1. ピリオド (.) で 5 つのフィールドに分割します。フィールド数が異なる場合は形式エラーです。
  2. expire を確認します。失効したトークンは署名検証より前に拒否されます。
  3. cid で証明書を探します。見つからなければ検証できません。
  4. expire.cid.plain.secure の区間に対して署名を検証します。
  5. 検証に成功した後で初めて secure を復号します。

署名検証前の値を信頼しないでください

一部の実装は、署名を確認せずにフィールドを取り出す API (parse without verify 系) を提供しています。この値は完全に攻撃者が操作できる値であり、ログ出力やデバッグ用途にのみ使用してください。


5. JWT との比較

DAT と JWT (JSON Web Token) は、ピリオド (.) で区切られたトークン構造と署名による検証方式を共有していますが、内部設計において次のような重要な違いがあります。

5.1. 構造的な差異の比較

  • JWT 構造

    headerbodysignature
    Base64Url (JSON String)Base64Url (JSON String)Base64Url (Binary)
  • DAT 構造

    有効期限CID平文データ暗号化データ署名
    Unixtime (uint64)Hex (uint64)Base64Url (Binary)Base64Url (Encrypt Binary)Base64Url (Binary)

5.2. 主要な相違点

  • Binary ベースの軽量化: JWT は Header と Body を JSON 文字列の形で扱いますが、DAT はバイナリ (Binary) データを直接扱うことでデータサイズを最適化し、パース効率を高めています。
  • セキュリティの内在化 (暗号化データ フィールド): JWT は基本的にペイロード (Payload) が平文で露出しており、暗号化が必要な場合は JWE のような別途の仕様を適用する必要があります。一方 DAT は、暗号化データ フィールドによってトークン自体が暗号化機能をサポートします。
  • 有効期限の制約の強制: JWT では exp (Claims) フィールドが任意項目ですが、DAT は有効期限 フィールドがトークン構造上で強制されているため、有効期限の検証が必ず実行されます。
  • アルゴリズム交渉なし: JWT はヘッダーの alg 値をトークン自身が持ち歩くため、アルゴリズム混同攻撃の攻撃面が生じます。DAT はアルゴリズムを証明書が決定し、トークンにはアルゴリズム情報が含まれません。