モード変更


    言語

PASETO トークンベース認証の概要

2024/07/12

web アプリケーションのセキュリティを確保する際、認証・認可にはさまざまな選択肢があります。特に人気があるのは PASETO と JWT です。

JWT は何年も前から広く利用されてきましたが、PASETO は比較的新しい技術であり、その高度なセキュリティ機能から注目を集めています。

PASETO(Platform-Agnostic Security Tokens)は、セキュアなステートレス・トークンの仕様およびリファレンス実装であり、JWT に代わる安全性の高い技術です。

トークン・ベース認証の理解

セキュアな API でユーザーを認証するための典型的なフローは以下です。

  1. ユーザーは認証のためにユーザー名とパスワードを提供する。
  2. 認証に成功すると、API はアクセストークン(JWT または PASETO)を返す。
  3. アクセストークンは、保護されたエンドポイントへのリクエスト時に Authorization ヘッダーに含める。
  4. API サーバーはトークンを検証し、アクセスが有効であれば適切に保護されたデータで応答する。

Modern Token Base Authentication

JWT と制限の理解

JWT は 3 つのコンポーネントで構成されます。

  • ヘッダー:トークンの署名アルゴリズムを含む。
  • ペイロード:認証されたユーザーに関する情報と追加データを保持する。サーバーはペイロードのこの部分をカスタマイズできる。
  • 署名:秘密鍵を使用してサーバーが生成する。この署名によって、サーバーは検証プロセス中に JWT の真正性を検証できる。

JWT Demo

Photo by Wallarm

JWT はデジタル署名アルゴリズムと検証の実装の選択に柔軟性を提供しますが、この柔軟性は脆弱性ももたらします。

ECDSA(Invalid-Curve Attack に弱い)や RSA PKCSv1.5(Padding Oracle Attack に弱い)のように、弱く攻撃されやすいアルゴリズムが複数あります。

JWT の実装はエラーも起こしやすく、JWT 検証の破綻のようなセキュリティの脆弱性をもたらす可能性があります。

JWT を正しく使用すれば、信頼性が高く柔軟な認証システムになります。しかし、サーバーが潜在的な攻撃にさらされないよう、注意を払う必要があります。

これに対して PASETO は、実装プロセスを単純化することで、これらの問題に対処しています。

PASETO Solution

JWT が柔軟な実装を提供するのに対し、PASETO はより厳格なアプローチをとります。しかし、この厳格さが実装エラーや誤用を防ぐのに役立っています。

PASETO はユーザーフレンドリーに設計されており、JWT と比較して高い cryptographic resilience を提供します。

PASETO を使用する場合、ユーザーは 2 つの設定

  • PASETO のバージョン(v1, v2, v3, or v4)を トークンの version フィールドで指定する。
  • 暗号化と復号化を対称にするか非対称にするかを、トークンの purpose フィールドで指定する。

を行うだけです。

PASETO Token の構造

JSON Web Token(JWT)と同様に、PASETO Token はドット区切りの base64url エンコードされたデータで構成され、以下の形式で編成されます:

version.purpose.payload.footer
  • version: Token 形式のインクリメンタルな改良を許可する。2024 年 7 月現在のバージョンは "v1"、"v2"、"v3"、"v4 "です。
    • v1: 現在広く利用可能な強力な暗号理論を使用。
    • v2: より新しく強力な暗号理論を利用するが、サポートする暗号ライブラリの数は少ない。
  • purpose: Token の形式を "local "または "public "のどちらかを表す簡潔な文字列。
    • local: Token のペイロードは暗号化され、共有鍵を持つパーティのみがアクセスできる。
    • public: ペイロードは暗号化されず、公開鍵を使って署名・検証される。
  • payload: Token のバージョンと目的に応じてエンコードされたデータ。
  • footer (optional): 暗号化されていない JSON。通常、トークン検証のための公開鍵の ID を格納するために使用される。

すべての PASETO Token 形式は改ざん防止に対応しており、トークンに変更が加えられた場合、検証は失敗します。

Local Token (対称暗号化)

Local Token は常に共有秘密鍵を用いて対称暗号化される。つまり、Local PASETO Token の内容は、正しい秘密鍵なしには見ることができません。

Symmetric encryption

これはデコードされたペイロード、オプションのフッター、情報に署名するために使用される署名鍵を含む、Local PASETO Token の例です。

Symmetric encryption

Public Token (非対称暗号化)

Public PASETO Token は、関係者全員と秘密鍵を共有するのが安全でないシナリオに適しています。

Public Token は暗号化されませんが、デジタル署名されます。つまり、攻撃者が Public PASETO Token を入手した場合、PASETO Token に使用されているデジタル署名により、その内容を閲覧することはできますが、検出されずに変更することはできません。

悪意を持って変更された Public PASETO Token を検証しようとすると、エラーが発生します。

Asymmetric encryption

以下は、デコードされたペイロード、オプションのフッター、情報に署名するために使用される公開鍵と秘密鍵を含む、Public PASETO Token の例です。

Asymmetric encryption

Versions

PASETO の各バージョンは、前のバージョンよりも改良されています。PASETO を仕様通りに正しく実装するには、バージョンごとに提供されているドキュメントを参照してください。

https://github.com/paseto-standard/paseto-spec/tree/master/docs/01-Protocol-Versions

Libraries

以下のリンクには、一般的なすべての言語とそのサポートバージョンの PASETO を実装したライブラリがあります。

https://paseto.io/

Ruby ライブラリを使った実装

PASETO を実装した Ruby ライブラリの使用例を以下に示します。

https://github.com/bannable/paseto

事前に gem のインストールが必要です。

gem 'ruby-paseto'
gem 'rbnacl', '~> 7.1.1' # optional - PASETO version 4 を使う場合のみ使用

対称暗号化 (local)

require 'paseto'

####################
####### 暗号化 ######
####################

# 通常、この32バイトの共有鍵は、認証サーバーとクライアントサーバーの両方に格納される。
shared_secret_key = SecureRandom.bytes(32)

# PASETO 暗号化/復号化の初期化をする。
crypt = Paseto::V4::Local.new(ikm: shared_secret_key) # version: v4 / 用途: local

# 平文のペイロード
claims = { "company" => "monstarlab" }
footer = { "viewable" => "yes" }

# ペイロードをエンコードし、PASETOを取得する。
encrypted_token = crypt.encode(claims, footer: JSON.dump(footer))
# => "v4.local.E1Y_KQ6Ek8lSOKrJ6kI1YjWXfAKJ0OEcdhUPywznjBjK5SGDUr4-6rbaZk-CIM_mdQgQHGPj8yAWQswktkCe_Sm_Nj9eEfDxNBFeAC2KsgqFCjF07VJo5ail0jnSTNM0-PekMytJleea8OvNkKdoLs4GKAsZTTJ_-DEMmOMyVlddlmaWoVwnF2JkpjBzFRO7d6PlIIY29rQWOXSvZxoLEqkE5XJvHpFs4NTuCHnF4Pko10X_sgHCPkTGXkWNDg.eyJ2aWV3YWJsZSI6InllcyJ9"

####################
####### 復号化 ######
####################

# 通常、この32バイトの共有鍵は、認証サーバーとクライアントサーバーの 両方に保存される。
shared_secret_key = SecureRandom.bytes(32)

# PASETO 暗号化/復号化の初期化をする。
crypt = Paseto::V4::Local.new(ikm: shared_secret_key) # version: v4 / 用途: local
encrypted_token = "v4.local.E1Y_KQ6Ek8lSOKrJ6kI1YjWXfAKJ0OEcdhUPywznjBjK5SGDUr4-6rbaZk-CIM_mdQgQHGPj8yAWQswktkCe_Sm_Nj9eEfDxNBFeAC2KsgqFCjF07VJo5ail0jnSTNM0-PekMytJleea8OvNkKdoLs4GKAsZTTJ_-DEMmOMyVlddlmaWoVwnF2JkpjBzFRO7d6PlIIY29rQWOXSvZxoLEqkE5XJvHpFs4NTuCHnF4Pko10X_sgHCPkTGXkWNDg.eyJ2aWV3YWJsZSI6InllcyJ9"

# トークン `eyJ2aWV3YWJsZSI6InllcyJ9` の最後の部分は、base64エンコードされた文字列であることに注意。
# つまり、誰でもその内容を見ることができる。
Base64.decode64("eyJ2aWV3YWJsZSI6InllcyJ9")
# => "{\"viewable\":\"yes\"}"

# トークンをデコードし、ペイロードを取得する。
crypt.decode(encrypted_token)
# => <Paseto::Result
#           claims={
#              "exp"=>"2023-05-10T11:18:41+09:00",
#              "iat"=>"2023-05-10T10:18:41+09:00",
#              "nbf"=>"2023-05-10T10:18:41+09:00",
#              "company"=>"monstarlab"},
#           footer={"viewable"=>"yes"}
#    >

# トークンが悪意を持って変更された場合、エラーが発生する。
encrypted_token[-1] = "M"
crypt.decode(encrypted_token)
# Paseto::InvalidAuthenticator: Paseto::InvalidAuthenticator
# from /Users/tony_duong/.rvm/gems/ruby-3.1.3/gems/ruby-paseto-0.1.2/lib/paseto/symmetric_key.rb:53:in `decrypt'

非対称暗号化(公開)の使い方

公開鍵と秘密鍵のペアの生成が必要です。

ssh-keygen
# Output: 公開鍵と秘密鍵
require 'paseto'

####################
###### 暗号化 #######
####################

# PASETO 暗号化/復号化の初期化をする。
pem = File.read('private_key')
signer = Paseto::V4::Public.new(pem)

# 平文のペイロード
claims = { "company" => "monstarlab" }
footer = { "viewable" => "yes" }

# ペイロードをエンコードし、PASETOを取得する。
signed_token = signer.encode(claims, footer: footer)
# => "v4.public.eyJleHAiOiIyMDIzLTA1LTEwVDExOjQ2OjA0KzA5OjAwIiwiaWF0IjoiMjAyMy0wNS0xMFQxMDo0NjowNCswOTowMCIsIm5iZiI6IjIwMjMtMDUtMTBUMTA6NDY6MDQrMDk6MDAiLCJjb21wYW55IjoibW9uc3RhcmxhYiJ9taKQPCARAZHv85xk7yaWPDeWHaHt981eHmoiYIrIcA-monnIbMax2EDxIjObgr6qLLuYzAH4BK5N6q0TJANeBg.eyJ2aWV3YWJsZSI6InllcyJ9"

####################
###### 復号化 #######
####################

verifier = Paseto::V4::Public.new('public_key')

# 公開鍵で初期化された場合、検証/復号のみ実行可能。
# エンコードが呼び出されるとエラーが発生する。
verifier.encode({'foo' => 'bar'})
# => ArgumentError

signed_token = "v4.public.eyJleHAiOiIyMDIzLTA1LTEwVDExOjQ2OjA0KzA5OjAwIiwiaWF0IjoiMjAyMy0wNS0xMFQxMDo0NjowNCswOTowMCIsIm5iZiI6IjIwMjMtMDUtMTBUMTA6NDY6MDQrMDk6MDAiLCJjb21wYW55IjoibW9uc3RhcmxhYiJ9taKQPCARAZHv85xk7yaWPDeWHaHt981eHmoiYIrIcA-monnIbMax2EDxIjObgr6qLLuYzAH4BK5N6q0TJANeBg.eyJ2aWV3YWJsZSI6InllcyJ9"
verifier.decode(signed_token)
# => <Paseto::Result
#           claims={
#              "exp"=>"2023-05-10T11:18:41+09:00",
#              "iat"=>"2023-05-10T10:18:41+09:00",
#              "nbf"=>"2023-05-10T10:18:41+09:00",
#              "company"=>"monstarlab"},
#           footer={"viewable"=>"yes"}
#    >

結論

JSON Web Token(JWT)の不注意な使用から発生する可能性のある脆弱性について説明しました。JWT は、正しく使用されれば、認証をシステムに組み込む効果的な手段として機能しますが、その柔軟な仕様は、潜在的に実装エラーやその後のセキュリティ問題を引き起こす可能性があります。

このような懸念に対処するため、PASETO は、特定の設計目標を念頭に置いた代替ソリューションとして導入されました。

  • 使用方法の簡素化: PASETO は、purpose と version のパラメータを指定するだけで、トークン作成プロセスを簡素化します。
  • 実装エラーへの耐性: JWT とは異なり、PASETO では安全でない可能性のある暗号アルゴリズムを広範囲から選択する必要がないため、実装ミスのリスクを軽減することができます。

PASETO は、開発者の意思決定プロセスを合理化することで、セキュリティ・トークンに対する開発者ファーストのアプローチを取っています。対称または非対称のセキュリティモデルという 2 つの異なる目的を提供することで、PASETO は認証された暗号化とデジタル署名に最適なオプションを自動的に選択します。これにより、トークンの安全性が確保され、暗号の脆弱性を回避することができます。

全体として、PASETO はセキュリティー・トークン管理により強固でわかりやすいアプローチを提供し、JWT に関連するリスクを軽減すると同時に、システムのセキュリティーを高いレベルで維持します。

References

  • PASETO: The JWT Killer? - article by Sandesh Dahake
  • PASETO: Platform-Agnostic Security Tokens - Github repository
  • Why PASETO is better than JWT for token-based authentication? - Youtube video by Tech School
  • Introducing JPaseto: Security Tokens For Java - article by Brian Demers
  • Encode or Decode PASETO
  • Paseto - Github repository

Article Photo by Erik Mclean

backendsecurityauthenticationpasetojwt

Author

Tony Duong

Tony Duong

Backend Developer

Currently on the never-ending learning journey 🚀
Yukio Ueda

Yukio Ueda

Backend Engineer

Golang & TypeScript enthusiast

その他おすすめ記事

2024/11/05

エンタープライズデータ基盤における dbt の活用戦略

近年、データ駆動型の意思決定が企業の競争力を左右する重要な要素となっており、大規模かつ複雑なデータ基盤の構築が不可欠となっています。この潮流の中で、dbt(data build tool)は、エンタープライズレベルのデータ変換とモデリングを効率化する強力なツールとして注目を集めています。 dbt は、SQL を使用してデータ変換を定義し、バージョン管理、テスト、ドキュメンテーションを統合的に行うことができるオープンソースツールです。特に以下の点で、エンタープライズデータ基盤の構築に大きな価値をもたらします...

Yoshiaki Sano

Yoshiaki Sano

Architecture

2024/11/04

データエンジニアリング初心者でも分かる!dbtの魅力と基本

データ駆動型ビジネスが当たり前となった今日、多くの企業がデータ分析の課題に直面しています。複雑な SQL クエリの管理、データの整合性確保、分析プロセスの再現性など、様々な問題が山積みです。そんな中で注目を集めているのが「dbt(data build tool)」です。 本記事では、データエンジニアリングの深い知識がなくても理解できるよう、dbt の基本と魅力について解説します。 dbt とは? dbt は、SQL を中心としたデータ変換ワークフローを管理するためのオープンソースツールです。従来の SQL...

Yoshiaki Sano

Yoshiaki Sano

Architecture

サービス開発実績会社情報
採用情報インサイトお問い合わせ
© 2022 Monstarlab
情報セキュリティ基本方針個人情報の取り扱いについて個人情報保護方針