🧑‍💻

#11 Webサービスのセキュリティの基礎知識:「認証」

2024/07/30に公開

はじめに

近頃、Webサービスにおける個人情報漏洩のニュースを目にする機会が多くありました。
そこでWebサービスのセキュリティの基本的な概念である「認証」と「認可」について、前後半に分けて備忘録としてまとめていきたいと思います。
今回は、その前半として「認証」の概念と、認証方法の一例としてJWT認証についても触れていきます。

認証とは

Webサービスにおける認証は以下のように説明されます。

ユーザーが表明しているとおりのユーザーであるかを検証します。ユーザーのアイデンティティは、ユーザー自身が提供する資格証明に基づいて検証されます。資格証明には次のものがあります。

  1. ユーザーが所有しているもの。たとえばパスポート(実世界)やスマート・カード(ITの世界)など、信頼できる機関が発行した資格証明。
  2. ユーザーが知っているもの。たとえばパスワードなどの共有の秘密鍵。
  3. ユーザーの特性。たとえばバイオメトリック情報。

パスポートやパスワードが自身を証明するツールであることは、とてもイメージしやすいかと思います。 バイオメトリック情報を用いた認証方法の例としては、指紋認証や顔認証が代表的です。

これらを組み合わせて使用することで、より強固な認証を実現できます。なりすましや改ざんが難しくなるほど、「本人である証明」をより確実なものとしていくことができます。

JWT認証について

上のように、Webサービスの認証方法は大きく3種類に分けることができますが、それに基づいて開発された認証方法は、ワンタイムパスワードやセッションIDを利用した認証など様々にあります。
今回はトークンを利用した認証方法のひとつであるJWT認証についてまとめていきます。

JWTとは

RFCでは以下のように定義されています。

JSON Web Token(JWT)は、HTTP AuthorizationヘッダーやURIクエリパラメーターなど、スペースに制約のある環境向けのコンパクトなクレーム表現形式です。

JWTはエンコードされたJSONオブジェクトとして一連のクレームを表します。クレームには文字列のクレーム名と任意の値であるクレーム値があり、この組み合わせをクレームセットと呼びます。
クレーム名には既に定義されているものがありますが、これらはオプションであり、絶対に使用しなければならないものではありません。
定義外のクレーム名を任意で設定することも可能です。

以下、定義済クレームセットの例です。

{
  "iss": "Sum", //「Issuer(発行者識別子)」
  "exp": 1512221102, //「Expiration Time(有効期限)」
  "iat": 1306111350, //「Issued At(発行日時)」
  "sub": "1551" //「Subject(同Issuer内で一意となる値)」
}

具体例から構成を確認

JWT認証とは認証情報が設定されたJWTを用いた認証方式を指します。
JWT認証用のトークンは「ヘッダ」「ペイロード」「署名」の3つで構成されており、それぞれを「.」で区切った一連のURLセーフパーツとして表されます。
ここでは、実際に具体例を参照しながら構成を確認してみましょう。

ヘッダ例

以下ではエンコードされたオブジェクトがJWTであること、HMAC SHA-256アルゴリズムを使用することが宣言されています。

{
  "alg": "HS256",
  "typ": "JWT"
}

これをBase64 URLでエンコードしたものが下になります。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

ペイロード例

以下では、2つのJWTクレームセットが設定されています。

{
  "sub": "sample",
  "name": "Sum"
}

「name」のように任意のクレーム名を設定することも可能です。
これをBase64 URLでエンコードしたものが下になります。

eyJzdWIiOiJzYW1wbGUiLCJuYW1lIjoiU3VtIn0

署名例

署名(signature)とは、エンコードされたヘッダとペイロードに暗号鍵とalgに指定した方式で暗号化したものです。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  [ 暗号鍵 ] //例では「your-256-bit-secret」を暗号鍵として設定
)

ヘッダで宣言したアルゴリズムによって暗号化されます。今回の例ではHMAC SHA-256アルゴリズムが用いられます。

fsRFCA4ia1zq_wIm7z56_ObSl92WKqQtQM4rI5MFfzY

これを更にBase64 URLでエンコードすることも可能です。

Y_wBKc7MJn-p025d5LwhOhie8teVw_9I-go56mzxCwE

ここからわかるように「複合化された署名」と「ヘッダ+ペイロード」の値は一致していなければなりません。
仮に一致していないのであれば、「ヘッダ+ペイロード」の値が改ざんされたということになります。
これは暗号鍵に以下の前提があることで成り立ちます。

  1. 信頼できる相手のみ暗号鍵を保有している
  2. 同じ暗号鍵でなければ複合化できない

上記の例をヘッダ、ペイロード、署名にそれぞれ設定した場合に作成されるものがこちら。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzYW1wbGUiLCJuYW1lIjoiU3VtIn0.Y_wBKc7MJn-p025d5LwhOhie8teVw_9I-go56mzxCwE

このようなトークンを作成し、ユーザ認証などの際にトークンが改ざんされていないかを検証することで、本人確認の証明として利用することができます。

注意したい点

JWTトークンの構成で確認した通り、ヘッダとペイロードはBase64 URLでエンコードされているだけなので容易に中身を閲覧することが可能です。
ペイロードに機密情報を含めてしまうと、第三者に閲覧される危険性があることを留意しましょう。

また当然ながら、暗号鍵が外部に漏れてしまえば認証ツールとして機能しません。
暗号鍵の取り扱いや脆弱な文字列の暗号鍵の使用には十分な注意が必要です。

様々なセキュリティー対策に共通することですが、取り扱い方によってセキュアな運用ができるかどうかが決まります。
「JWT認証を用いているから絶対安全」とはならないので、ベストプラクティスな実装を心がけることが重要です。

おわりに

今回、Webサービスのセキュリティとして基本的な概念である「認証」、その例としてJWT認証を取り上げ、構成についてまとめてみました。JWT認証の攻撃方法やセキュアな実装方法など、具体的な内容については少々話が逸れてしまうと思い、取り上げませんでした。
機会があれば、そちらについてもまとめていきたいと思います。

次回はWebサービスのセキュリティの基本的な概念【後半】として「認可」について触れていきたいと思います。

以上です、閲覧ありがとうございました。

出典:

Discussion