JWT の署名検証は「トークンが改ざんされていないことを保証するための最重要ステップ」です
読者のみなさんが Web API や業務システムを開発する際、 JWT(JSON Web Token)を安全に扱うためには 署名の検証(Signature Validation) が必須です。
署名検証は、次のことを保証します。
- トークンが第三者に書き換えられていない
- 正しい秘密鍵(または公開鍵)で署名されている
- 信頼できる発行者(Issuer)が作ったトークンである
ここでは、初心者でも理解できるように ステップバイステップで思考しながら、 実務で使える C# の JWT 署名検証ユーティリティを丁寧に解説します。
JWT の署名検証とは何か
JWT の構造を理解する
JWT は次の 3 つの部分で構成されています。
- Header(署名方式)
- Payload(ユーザー情報・有効期限)
- Signature(改ざん防止の署名)
例: xxxxx.yyyyy.zzzzz
署名部分(zzzzz)は、Header と Payload を秘密鍵または公開鍵で署名したものです。
なぜ署名検証が必要なのか
署名を検証しないと、攻撃者が次のようなことをできます。
- Payload を書き換えて権限を偽装
- 有効期限を延長
- 別ユーザーの ID に書き換え
署名検証は JWT の安全性の中心 です。
C# で JWT の署名を検証するためのライブラリ
.NET では公式ライブラリが用意されています。
- System.IdentityModel.Tokens.Jwt
- Microsoft.IdentityModel.Tokens
これらを使うことで、安全な署名検証ができます。
署名方式(アルゴリズム)を理解する
HS256(対称鍵方式)
- 秘密鍵を共有する方式
- 単一サービス向け
- API サーバーが署名と検証の両方を行う
RS256 / ES256(公開鍵方式)
- 公開鍵で検証
- 複数サービス間での認証に向いている
- Identity Provider が署名し、API サーバーが公開鍵で検証する
実務で使える JWT 署名検証ユーティリティ(HS256)
まずは最も一般的な HS256 の検証テンプレートです。
csharp
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
public static class JwtValidator
{
public static ClaimsPrincipal Validate(string token, string secretKey)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var parameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "your-app",
ValidAudience = "your-app",
IssuerSigningKey = key
};
var handler = new JwtSecurityTokenHandler();
return handler.ValidateToken(token, parameters, out _);
}
}
署名検証の使い方(実務コード例)
csharp
string secretKey = "your-very-strong-secret-key-1234567890";
string token = "受け取ったJWTトークン";
try
{
var principal = JwtValidator.Validate(token, secretKey);
string userId = principal.FindFirst("userId")?.Value;
Console.WriteLine($"認証成功: {userId}");
}
catch (Exception ex)
{
Console.WriteLine("署名検証に失敗しました: " + ex.Message);
}
公開鍵方式(RS256 / ES256)の署名検証(深掘り)
外部サービス(Auth0、Azure AD、Google、LINE Login など)から JWT を受け取る場合は 公開鍵方式(RS256 / ES256) を使います。
公開鍵は X.509 証明書として提供されることが多いです。
RS256 の検証テンプレート
csharp
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
public static class JwtValidatorRs256
{
public static ClaimsPrincipal Validate(string token, X509Certificate2 cert)
{
var key = new X509SecurityKey(cert);
var parameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidIssuer = "your-issuer",
ValidAudience = "your-audience"
};
var handler = new JwtSecurityTokenHandler();
return handler.ValidateToken(token, parameters, out _);
}
}
署名検証でよくある失敗と対策(重要)
Issuer / Audience が一致しない
検証側の設定とトークンの値が一致しないと必ず失敗します。
公開鍵が古い・間違っている
Identity Provider が鍵をローテーションする場合があります。 最新の公開鍵を取得する必要があります。
有効期限切れ
exp が過ぎていると検証に失敗します。
Clock Skew(時刻のズレ)
サーバーの時刻がずれていると有効期限判定が誤ります。
実務的ベストプラクティス
- HS256 の秘密鍵は 32 文字以上にする
- RS256 / ES256 の公開鍵は定期的に更新する
- JWT は短命(15〜30 分)にする
- リフレッシュトークンを併用する
- HTTPS を必ず使う
- JWT をログに出力しない
- ペイロードに機密情報を入れない
まとめ:JWT の署名検証は「改ざん防止の中心技術」
署名検証の本質は次の 3 つです。
- 正しい鍵で署名されているか確認する
- 改ざんされていないことを保証する
- 有効期限や発行者をチェックする
これらを正しく実装することで、 攻撃者がトークンを偽造したり、書き換えたりするのを防げます。
読者のみなさんが業務システムを開発する際、 このユーティリティを使うだけでセキュリティレベルが大幅に向上し、 ユーザーの安全を確実に守ることができます。
必要であれば「JWT とリフレッシュトークンの完全設計テンプレート」も作成できます。
