質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

1281閲覧

[C#]JWT認証が失敗してしまう

退会済みユーザー

退会済みユーザー

総合スコア0

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2022/12/26 06:20

編集2022/12/26 08:37

前提

プログラマ1年目の初心者です。至らない点や認識の間違いなどあるかと思いますが、どうかよろしくお願いいたします。
JWT(Json Web Token)発行を実装したいのですが、発行はしているが、正しい署名情報でないためか、認証失敗してしまいます。
調べましたが、情報が乏しいため、こちらに質問させていただくに至りました。
ES256形式(curve : P-256 (secp256r1),hash Algorithm : SHA-256)による実装です。

実現したいこと

  • JWTの鍵による認証を成功させたい

発生している問題・エラーメッセージ

下記認証サイトによるInvailed Signatureエラー
https://jwt.io/

該当のソースコード

C#

1using System; 2using System.Linq; 3using System.Text; 4using System.Windows.Forms; 5using System.Text.Json; 6using System.IO; 7using Org.BouncyCastle.Crypto; 8using Org.BouncyCastle.OpenSsl; 9using Org.BouncyCastle.Crypto.Signers; 10 11namespace WindowsFormsApp1 12{ 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 } 19 20 private static string plainText; 21 private static string key; 22 private static byte[] signature; 23 24 /// <summary> 25 /// ボタンクリックイベント(main) 26 /// </summary> 27 /// <param name="sender"></param> 28 /// <param name="e"></param> 29 private void ConfirmButton_Click(object sender, EventArgs e) 30 { 31 // generate token 32 string token = GenerateJwtToken(); 33 34 // output token 35 Console.WriteLine(token); 36 } 37 38 /// <summary> 39 /// Jwtトークンの生成 40 /// </summary> 41 /// <param name="privateKey"></param> 42 /// <returns></returns> 43 public static string GenerateJwtToken() 44 { 45 var header = new Header() 46 { 47 Typ = "JWT", 48 Kid = "kid", 49 Alg = "ES256" 50 }; 51 52 var payload = new Payload() 53 { 54 Name = "name" 55 }; 56 57 // header,payload確認 58 var jsonHeader = JsonSerializer.Serialize(header); 59 var jsonPayload = JsonSerializer.Serialize(payload); 60 string encodedHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonHeader)).TrimEnd('=').Replace('+', '-').Replace('/', '_'); 61 string encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonPayload)).TrimEnd('=').Replace('+', '-').Replace('/', '_'); 62 63 // token発行 64 plainText = encodedHeader + "." + encodedPayload; 65 key = @"C:\~~~\prime256v1.privatekey"; 66 signature = Sign(plainText, key); 67 string encodedSignature = Convert.ToBase64String(signature).TrimEnd('=').Replace('+', '-').Replace('/', '_'); 68 string token = encodedHeader + "." + encodedPayload + "." + encodedSignature; 69 70 return token; 71 } 72 73 /// <summary> 74 /// 署名する 75 /// </summary> 76 static byte[] Sign(string clearText, string key) 77 { 78 var plain = Encoding.UTF8.GetBytes(clearText); 79 80 // 鍵を読み込む 81 AsymmetricCipherKeyPair pair = null; 82 using (var stream = new StreamReader(key)) 83 { 84 var reader = new PemReader(stream); 85 pair = reader.ReadObject() as AsymmetricCipherKeyPair; 86 } 87 88 // 署名インスタンスを生成&署名 89 var signer = new ECDsaSigner(); 90 signer.Init(true, pair.Private); 91 var sign = signer.GenerateSignature(plain); 92 93 // 署名の値をbyte[]にしておく 94 var sign1 = sign[0].ToByteArray().SkipWhile(b => b == 0x00).Reverse(); 95 var sign2 = sign[1].ToByteArray().SkipWhile(b => b == 0x00).Reverse(); 96 byte[] signature = sign1.Concat(sign2).ToArray(); 97 98 return signature; 99 } 100 101 102 /// <summary> 103 /// ヘッダー格納用クラス 104 /// </summary> 105 public class Header 106 { 107 public string Typ { get; set; } 108 public string Kid { get; set; } 109 public string Alg { get; set; } 110 } 111 112 /// <summary> 113 /// ペイロード格納用クラス 114 /// </summary> 115 public class Payload 116 { 117 public string Name { get; set; } 118 } 119 120 } 121}

試したこと

大参考記事 https://qiita.com/rawr/items/1a11edf694f550596879
①opensslで鍵ペアを作成
②(①を取り込んだ)C#を実行し、JWTを生成
③ ①と②を https://jwt.io/ に入力し、認証

②の署名作成部分(Sign())が間違っているのではないかと思ったのですが、調べても同じような実装例が見つからず、解決できませんでした。

参考記事の認証メソッドVerifyも実装しました。メソッドでは認証が成功しましたが、認証サイトでは認証が成功しませんでした。

補足情報(FW/ツールのバージョンなど)

Windows10
Visual studio 2019
.NET Framework 4.7.2
BouncyCastle 1.8.9(VS2019インストール時にすでにインストール済)
OpenSSL 1.1.1s 1 Nov 2022

openssl実行コマンド:

$ openssl ecparam -genkey -name prime256v1 -out prime256v1.keypair
$ openssl ec -in prime256v1.keypair -outform PEM -out prime256v1.privatekey
$ openssl ec -in prime256v1.keypair -outform PEM -pubout -out prime256v1.publickey

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/12/26 08:00

> 認証サイトでは認証が成功しませんでした。 「認証サイト」って何ですか?  https://jwt.io/ のことですか? そこは認証サイトではなく JWT を Decode するだけのようですが? 「成功しませんでした」ってどういうことですか?
退会済みユーザー

退会済みユーザー

2022/12/26 08:17

コメントありがとうございます! >>「成功しませんでした」ってどういうことですか? https://jwt.io/ に必要な情報を入力すると、Invailed Signature というエラーが表示されることを「認証が成功しませんでした」と表現しました。 これは、「正しい署名を作成できていないため、鍵による認証が成功しなかった」という認識だったのですが、この認識は間違っていますか。
退会済みユーザー

退会済みユーザー

2022/12/26 08:31

ES256方式のJWTを入力すると、デコード結果の下に鍵ペアを入力する欄が現れ、本来ならそこに鍵情報を入力すると、JWT入力欄の下にSignature Verified と表示されるのですが、Invailed Signatureと表示されてしまいます。
退会済みユーザー

退会済みユーザー

2022/12/26 08:36

> これは、「正しい署名を作成できていないため、鍵による認証が成功しなかった」という認識だったのですが、この認識は間違っていますか。 Decode できなかったというだけで認証とは違います。Decode できても認証が通るとは限りません(期限切れとか、発行者が違うとか)。
退会済みユーザー

退会済みユーザー

2022/12/26 08:49

ご指摘ありがとうございます。 つまり、もしエラーが起きなくても「Signature Verified (署名検証済み)と書いてあるが、認証に成功していない」ということですね。このサイトの中まで疑うことは考えていませんでした。
退会済みユーザー

退会済みユーザー

2022/12/26 09:33 編集

あなたの言う「認証」の意味が違うのでは? 普通の意味で認証というと、例えばある Web API に ID とパスワードを送信して JWT を発行してもらい、その Web API から情報を取得するためリクエストを送る際、ヘッダに JWT を含めて送信しその Web API に有効なユーザーであることを認証してもらう・・・というような話になると思うのですが。 その具体例は以下の記事を見てください。 ASP.NET Core Web API と JWT http://surferonwww.info/BlogEngine/post/2020/02/11/json-web-token-basis-authentication-in-aspnet-core-web-api.aspx
退会済みユーザー

退会済みユーザー

2022/12/26 23:34

質問者さん、その後無言ですがどうなりましたか?
退会済みユーザー

退会済みユーザー

2022/12/27 02:17

参考記事をいただきありがとうございます。 認証という表現は間違っていました。すみません。 JWTの用途として想定しているのは、署名検証による改ざん検知なので、認証ではありませんでした。 また、 https://jwt.io/ の用途はJWTの生成と中身の確認で、”別のプログラムで生成したJWTとJWT生成のために使用した鍵情報を入力すると署名の検証が行われる”という機能ではないという点に気づきました。 この質問はJWT生成アルゴリズムの理解のために作成いたしましたが、他に優先すべきことが発生したため保留とさせていただきます。SurferOnWwwさん、ご協力ありがとうございました。
退会済みユーザー

退会済みユーザー

2022/12/27 02:28 編集

保留とかでしばし放置状態になるならクローズしてください。自分で回答欄に「なになにすることにした」とか書いてそれに自己解決マークをつけてクローズ願います。
guest

回答1

0

ベストアンサー

他の優先度の高い作業のため、一旦この問題を保留にすることとしました。ご協力ありがとうございます。

投稿2022/12/27 04:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問