JWT署名検証の欠如

C#でのJWT署名検証の欠如

説明

JWTを手動で分割したり、ReadJwtToken のようなデコード専用APIで読み取ったりするだけでは、署名は検証されません。得られたクレームを認証や権限判断で信頼すると、攻撃者が偽造した値を受け入れるおそれがあります。

想定される影響

  • 認証の回避、権限昇格、ユーザーへのなりすまし。

対処方法

JwtSecurityTokenHandler.ValidateToken またはASP.NET Coreの認証ミドルウェアを使い、署名、発行者、対象、有効期限を検証してください。

例

変更前

csharp
sealed class Jwt
{
    public string[] Decode(JwtValidationRequest request)
    {
        return request.Token.Split('.');
    }
}

sealed class JwtValidationRequest
{
    public string Token { get; set; } = "";
}

変更後

鍵は信頼できる設定から提供し、発行者と対象には実際のサービスの値を指定してください。検証失敗は認証失敗として扱ってください。

csharp
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;

ClaimsPrincipal ValidateJwt(string token, SecurityKey trustedSigningKey)
{
    var validationParameters = new TokenValidationParameters
    {
        RequireSignedTokens = true,
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = trustedSigningKey,
        ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 },
        ValidateIssuer = true,
        ValidIssuer = "https://issuer.example.com",
        ValidateAudience = true,
        ValidAudience = "api://orders",
        RequireExpirationTime = true,
        ValidateLifetime = true,
        ClockSkew = TimeSpan.FromMinutes(1)
    };

    return new JwtSecurityTokenHandler().ValidateToken(
        token, validationParameters, out _);
}

解説:

  • 変更前: 文字列の分割は検証ではありません。未検証のトークンのクレームを信頼すると、偽造された値や署名されていない値を受け入れるおそれがあります。
  • 変更後: 信頼する鍵と許可するアルゴリズムを固定し、署名、発行者、対象、有効期限をすべて検証します。ValidateToken の呼び出しを追加しても、検証オプションを弱めると安全ではありません。

参考資料