@jjlmoya/utils-developer 1.15.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +3 -1
- package/src/entries.ts +7 -1
- package/src/index.ts +4 -0
- package/src/tests/locale_completeness.test.ts +2 -3
- package/src/tests/pagespeed_best_practices.test.ts +198 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/aspectRatio/component.astro +3 -1
- package/src/tool/colorConverter/component.astro +3 -3
- package/src/tool/jwtDecoder/bibliography.astro +14 -0
- package/src/tool/jwtDecoder/bibliography.ts +12 -0
- package/src/tool/jwtDecoder/component.astro +209 -0
- package/src/tool/jwtDecoder/entry.ts +30 -0
- package/src/tool/jwtDecoder/i18n/de.ts +248 -0
- package/src/tool/jwtDecoder/i18n/en.ts +247 -0
- package/src/tool/jwtDecoder/i18n/es.ts +248 -0
- package/src/tool/jwtDecoder/i18n/fr.ts +248 -0
- package/src/tool/jwtDecoder/i18n/id.ts +248 -0
- package/src/tool/jwtDecoder/i18n/it.ts +248 -0
- package/src/tool/jwtDecoder/i18n/ja.ts +248 -0
- package/src/tool/jwtDecoder/i18n/ko.ts +248 -0
- package/src/tool/jwtDecoder/i18n/nl.ts +247 -0
- package/src/tool/jwtDecoder/i18n/pl.ts +247 -0
- package/src/tool/jwtDecoder/i18n/pt.ts +247 -0
- package/src/tool/jwtDecoder/i18n/ru.ts +248 -0
- package/src/tool/jwtDecoder/i18n/sv.ts +248 -0
- package/src/tool/jwtDecoder/i18n/tr.ts +248 -0
- package/src/tool/jwtDecoder/i18n/zh.ts +248 -0
- package/src/tool/jwtDecoder/index.ts +11 -0
- package/src/tool/jwtDecoder/jwt-decoder-parser-and-claims-inspector.css +358 -0
- package/src/tool/jwtDecoder/logic.ts +96 -0
- package/src/tool/jwtDecoder/seo.astro +15 -0
- package/src/tool/jwtDecoder/ui.ts +38 -0
- package/src/tool/llmCostCalculator/component.astro +1 -2
- package/src/tool/mobileMockupGenerator/component.astro +4 -5
- package/src/tool/placeholderGenerator/component.astro +2 -2
- package/src/tool/readabilityCalculator/component.astro +4 -4
- package/src/tool/serpPixelSimulator/bibliography.astro +14 -0
- package/src/tool/serpPixelSimulator/bibliography.ts +16 -0
- package/src/tool/serpPixelSimulator/component.astro +84 -0
- package/src/tool/serpPixelSimulator/controller.ts +323 -0
- package/src/tool/serpPixelSimulator/entry.ts +30 -0
- package/src/tool/serpPixelSimulator/i18n/de.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/en.ts +213 -0
- package/src/tool/serpPixelSimulator/i18n/es.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/fr.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/id.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/it.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ja.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ko.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/nl.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/pl.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/pt.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/ru.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/sv.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/tr.ts +214 -0
- package/src/tool/serpPixelSimulator/i18n/zh.ts +214 -0
- package/src/tool/serpPixelSimulator/index.ts +8 -0
- package/src/tool/serpPixelSimulator/logic.ts +18 -0
- package/src/tool/serpPixelSimulator/seo.astro +15 -0
- package/src/tool/serpPixelSimulator/serp-pixel-simulator.css +335 -0
- package/src/tool/serpPixelSimulator/ui.ts +33 -0
- package/src/tools.ts +3 -2
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
3
|
+
import type { JwtDecoderUI } from '../ui';
|
|
4
|
+
import { bibliography } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'jwt-decoder-parser-and-claims-inspector';
|
|
7
|
+
const title = 'JWT Decoder, Parser and Claims Inspector';
|
|
8
|
+
const description = 'JSON Web Tokenを貼り付けて、ヘッダーとペイロードを即座にデコードし、登録されたクレームを検査し、期限切れトークンを見つけ、認証フローをデバッグするためにクリーンなJSONをコピーします。';
|
|
9
|
+
|
|
10
|
+
const howTo = [
|
|
11
|
+
{
|
|
12
|
+
name: 'JWTを貼り付ける',
|
|
13
|
+
text: 'Authorizationヘッダー、Cookie、ログエントリ、またはIDプロバイダからトークンをコピーして入力フィールドに貼り付けます。',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'デコードされたヘッダーとペイロードを読む',
|
|
17
|
+
text: 'このツールはトークンをヘッダー、ペイロード、署名に分割し、JSONセグメントを別々のパネルに表示して素早く検査します。',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: '重要なクレームをチェックする',
|
|
21
|
+
text: 'アルゴリズム、発行者、オーディエンス、サブジェクト、発行時刻、有効開始時刻、有効期限を、Unixタイムスタンプを手動で変換することなく確認します。',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '必要なデータをコピーする',
|
|
25
|
+
text: 'チームとサニタイズされたデバッグスナップショットを共有する必要がある場合に、デコードされた1つのセクションまたは完全なデコード済み出力をコピーします。',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const faq = [
|
|
30
|
+
{
|
|
31
|
+
question: 'JWTをデコードすることでトークンが有効であることを証明できますか?',
|
|
32
|
+
answer: 'いいえ。デコードはbase64urlエンコードされたヘッダーとペイロードを明らかにするだけです。トークンが信頼できるのは、アプリケーションまたはIDプロバイダによって署名、発行者、オーディエンス、有効期限、および関連クレームが検証された後だけです。',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
question: 'このJWTデコーダをアクセストークンとIDトークンに使用できますか?',
|
|
36
|
+
answer: 'はい。このデコーダは、標準の3部構成のJWT形式を使用している限り、OAuthアクセストークン、OpenID Connect IDトークン、セッショントークン、サービス間トークンの検査に役立ちます。',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
question: '署名パネルがトークンを検証しないのはなぜですか?',
|
|
40
|
+
answer: 'JWT検証には、正しいシークレット、公開鍵、またはJWKS設定が必要です。このツールは、可視の署名文字列が有効性の証明であるかのように装うことなく、開発者がトークンの内容を確認できるように、意図的にデコードと検査に焦点を当てています。',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
question: 'JWTをデバッグする際に最初に何をチェックすべきですか?',
|
|
44
|
+
answer: 'exp、nbf、iss、aud、algから始めます。実際の本番環境の問題のほとんどは、期限切れトークン、クロックスキュー、誤ったオーディエンス値、予期しない発行者URL、または安全でないアルゴリズムの仮定に起因します。',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const ui: JwtDecoderUI = {
|
|
49
|
+
tokenLabel: 'JWTトークン',
|
|
50
|
+
tokenPlaceholder: 'ここにJWTを貼り付け: header.payload.signature',
|
|
51
|
+
sampleButton: 'サンプルを読み込む',
|
|
52
|
+
clearButton: 'クリア',
|
|
53
|
+
statusWaiting: 'JSONヘッダー、ペイロード、クレームをデコードするためにトークンを貼り付けてください。',
|
|
54
|
+
statusValid: 'JWTが正常にデコードされました。',
|
|
55
|
+
statusInvalid: 'これは有効な3部構成のJWTではないようです。',
|
|
56
|
+
statusExpired: 'JWTはデコードされましたが、expクレームが既に期限切れです。',
|
|
57
|
+
statusUnsigned: 'JWTはデコードされましたが、署名されていないか、alg noneを使用しています。',
|
|
58
|
+
headerTitle: 'ヘッダー',
|
|
59
|
+
payloadTitle: 'ペイロード',
|
|
60
|
+
signatureTitle: '署名',
|
|
61
|
+
claimsTitle: '登録クレーム',
|
|
62
|
+
copyHeader: 'デコードされたヘッダーをコピー',
|
|
63
|
+
copyPayload: 'デコードされたペイロードをコピー',
|
|
64
|
+
copySignature: '署名をコピー',
|
|
65
|
+
copyAll: 'すべてコピー',
|
|
66
|
+
copiedLabel: 'コピー済み',
|
|
67
|
+
invalidTokenTitle: '無効なJWT',
|
|
68
|
+
invalidTokenBody: 'トークンにドットで区切られた3つのbase64urlセグメントがあることを確認してください。',
|
|
69
|
+
invalidSegmentError: 'トークンにドットで区切られた3つのbase64urlセグメントがあることを確認してください。',
|
|
70
|
+
invalidDecodeError: 'ヘッダーまたはペイロードを有効なJSONとしてデコードできませんでした。',
|
|
71
|
+
emptyJson: '{}',
|
|
72
|
+
signaturePresent: '署名セグメントが存在します。認証レイヤーで正しいキーを使用して検証してください。',
|
|
73
|
+
signatureMissing: '署名セグメントがありません',
|
|
74
|
+
algorithmLabel: 'アルゴリズム',
|
|
75
|
+
typeLabel: 'タイプ',
|
|
76
|
+
issuerLabel: '発行者',
|
|
77
|
+
subjectLabel: 'サブジェクト',
|
|
78
|
+
audienceLabel: 'オーディエンス',
|
|
79
|
+
issuedAtLabel: '発行日時',
|
|
80
|
+
notBeforeLabel: '有効開始日時',
|
|
81
|
+
expiresAtLabel: '有効期限',
|
|
82
|
+
claimMissing: '存在しません',
|
|
83
|
+
privacyNote: 'デコードはブラウザセッション内で実行されます。セキュリティポリシーで許可されている場合を除き、本番環境のシークレットをツールに貼り付けないでください。',
|
|
84
|
+
sampleToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnYW1lYm9iLXVzZXItNDIiLCJuYW1lIjoiR2FtZUJvYiBEZXZlbG9wZXIiLCJpc3MiOiJodHRwczovL3d3dy5nYW1lYm9iLmRldiIsImF1ZCI6ImRldmVsb3Blci10b29scyIsImlhdCI6MTcxNzIwMDAwMCwibmJmIjoxNzE3MjAwMDAwLCJleHAiOjE4OTM0NTYwMDAsInJvbGUiOiJhZG1pbiJ9.demo-signature',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
88
|
+
'@context': 'https://schema.org',
|
|
89
|
+
'@type': 'FAQPage',
|
|
90
|
+
mainEntity: faq.map((item) => ({
|
|
91
|
+
'@type': 'Question',
|
|
92
|
+
name: item.question,
|
|
93
|
+
acceptedAnswer: {
|
|
94
|
+
'@type': 'Answer',
|
|
95
|
+
text: item.answer,
|
|
96
|
+
},
|
|
97
|
+
})),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const howToSchema: WithContext<HowTo> = {
|
|
101
|
+
'@context': 'https://schema.org',
|
|
102
|
+
'@type': 'HowTo',
|
|
103
|
+
name: title,
|
|
104
|
+
description,
|
|
105
|
+
step: howTo.map((step, index) => ({
|
|
106
|
+
'@type': 'HowToStep',
|
|
107
|
+
position: index + 1,
|
|
108
|
+
name: step.name,
|
|
109
|
+
text: step.text,
|
|
110
|
+
})),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
114
|
+
'@context': 'https://schema.org',
|
|
115
|
+
'@type': 'SoftwareApplication',
|
|
116
|
+
name: title,
|
|
117
|
+
description,
|
|
118
|
+
applicationCategory: 'DeveloperApplication',
|
|
119
|
+
operatingSystem: 'Any',
|
|
120
|
+
offers: {
|
|
121
|
+
'@type': 'Offer',
|
|
122
|
+
price: '0',
|
|
123
|
+
priceCurrency: 'EUR',
|
|
124
|
+
},
|
|
125
|
+
inLanguage: 'ja',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const content: ToolLocaleContent<JwtDecoderUI> = {
|
|
129
|
+
slug,
|
|
130
|
+
title,
|
|
131
|
+
description,
|
|
132
|
+
ui,
|
|
133
|
+
faqTitle: 'JWTデコーダ FAQ',
|
|
134
|
+
faq,
|
|
135
|
+
bibliographyTitle: 'JWT仕様とセキュリティリファレンス',
|
|
136
|
+
bibliography,
|
|
137
|
+
howTo,
|
|
138
|
+
schemas: [appSchema, faqSchema, howToSchema],
|
|
139
|
+
seo: [
|
|
140
|
+
{
|
|
141
|
+
type: 'title',
|
|
142
|
+
text: 'セキュリティコンテキストを失わずにJWTをデコードする',
|
|
143
|
+
level: 2,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'paragraph',
|
|
147
|
+
html: 'JSON Web Tokenはコンパクトに見えますが、署名アルゴリズム、発行者、オーディエンス、サブジェクト、発行時刻、有効開始時刻、有効期限、アプリケーション固有の認証クレームなど、認証失敗を説明する正確な詳細を含んでいることがよくあります。この<strong>JWTデコーダ、パーサ、クレームインスペクタ</strong>は、3つのトークンセグメントを読み取り可能なJSONに変換し、認証フローをより速くデバッグできるようにします。',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'diagnostic',
|
|
151
|
+
variant: 'warning',
|
|
152
|
+
title: 'デコード済みは信頼済みを意味しません',
|
|
153
|
+
html: '誰でもJWTをbase64urlデコードできます。信頼が始まるのは、アプリケーションが正しいシークレット、公開鍵、またはJWKSで署名を検証し、発行者、オーディエンス、有効期限、およびドメイン固有のクレームを検証した後だけです。このツールはデータの検査に使用し、トークンを本物として受け入れるために使用しないでください。',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: 'title',
|
|
157
|
+
text: '各JWTセグメントが教えてくれること',
|
|
158
|
+
level: 3,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
type: 'table',
|
|
162
|
+
headers: ['セグメント', '一般的な内容', 'デバッグの価値'],
|
|
163
|
+
rows: [
|
|
164
|
+
['ヘッダー', 'アルゴリズム、トークンタイプ、オプションのキーID', 'HS256、RS256、ES256など、どの検証戦略をトークンが期待しているかを示します。'],
|
|
165
|
+
['ペイロード', '登録クレームとアプリケーションクレーム', 'ID、テナント、スコープ、ロール、有効期限、オーディエンスの不一致を明らかにします。'],
|
|
166
|
+
['署名', 'base64urlエンコードされた暗号署名バイト', '署名セグメントが存在することを確認しますが、別の場所で正しいキーで検証する必要があります。'],
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
type: 'title',
|
|
171
|
+
text: '認証の不具合を通常説明するクレーム',
|
|
172
|
+
level: 3,
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: 'list',
|
|
176
|
+
items: [
|
|
177
|
+
'<strong>exp:</strong> トークンの有効期限が切れている場合、更新ロジックまたはクロック設定が間違っている可能性があります。',
|
|
178
|
+
'<strong>nbf:</strong> トークンがまだ有効でない場合、サーバーとIDプロバイダのクロックが同期していない可能性があります。',
|
|
179
|
+
'<strong>iss:</strong> 発行者URLが設定と異なる場合、トークンが間違ったテナントまたは環境から来ている可能性があります。',
|
|
180
|
+
'<strong>aud:</strong> オーディエンスがAPI識別子と一致しない場合、トークンは別のリソース用に発行されています。',
|
|
181
|
+
'<strong>alg:</strong> アルゴリズムが予期しない場合、検証ツールがトークンを拒否するか、危険な設定ミスを露呈する可能性があります。',
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
type: 'title',
|
|
186
|
+
text: '開発中のJWTパーサのユースケース',
|
|
187
|
+
level: 3,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'comparative',
|
|
191
|
+
columns: 3,
|
|
192
|
+
items: [
|
|
193
|
+
{
|
|
194
|
+
title: 'フロントエンドデバッグ',
|
|
195
|
+
description: 'ログイン後に受け取ったIDトークンとアクセストークンを検査し、スコープ、ロール、プロフィールクレームを確認します。',
|
|
196
|
+
icon: 'mdi:monitor-dashboard',
|
|
197
|
+
points: ['プロフィールクレームをチェック', 'スコープとロールを確認', 'ログイン環境を比較'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
title: 'バックエンドAPI QA',
|
|
201
|
+
description: '期待される発行者とオーディエンスの値を、Authorizationヘッダーで実際に送信されたトークンと比較します。',
|
|
202
|
+
icon: 'mdi:api',
|
|
203
|
+
highlight: true,
|
|
204
|
+
points: ['オーディエンスの形式を検証', '発行者の不一致を見つける', 'ベアラートークンを検査'],
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
title: 'IDプロバイダ設定',
|
|
208
|
+
description: 'Auth0、Azure AD、Cognito、Keycloak、またはカスタムプロバイダからのクレームが、アプリが期待する形状になっているか確認します。',
|
|
209
|
+
icon: 'mdi:account-key',
|
|
210
|
+
points: ['テナントデータを確認', 'カスタムクレームをチェック', 'プロバイダマッピングを比較'],
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
type: 'title',
|
|
216
|
+
text: 'このインスペクタで明らかになる一般的なJWTの失敗',
|
|
217
|
+
level: 3,
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
type: 'proscons',
|
|
221
|
+
title: '迅速なチェック vs 信頼の判断',
|
|
222
|
+
items: [
|
|
223
|
+
{
|
|
224
|
+
pro: '不正な形式のトークンを即座に確認できます。',
|
|
225
|
+
con: '期待するオーディエンスや発行者を知ることはできません。',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
pro: 'Unixタイムスタンプクレームを読み取り可能な日付に変換します。',
|
|
229
|
+
con: '実際のキー素材なしでは署名を検証できません。',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
pro: '発行者、オーディエンス、サブジェクト、タイプの欠落値を見つけます。',
|
|
233
|
+
con: 'スコープとロールがアプリケーションにとって安全であることを証明できません。',
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
type: 'summary',
|
|
239
|
+
title: 'ベストプラクティスワークフロー',
|
|
240
|
+
items: [
|
|
241
|
+
'クライアントまたはAPIが実際に受け取った内容を理解するためにトークンをデコードします。',
|
|
242
|
+
'アプリケーションロジックを追う前にexp、nbf、iss、aud、sub、algをチェックします。',
|
|
243
|
+
'署名と信頼の判断は認証レイヤーでのみ検証します。',
|
|
244
|
+
'機密性の高い本番JWTをチケット、ログ、スクリーンショットで共有しないでください。',
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
3
|
+
import type { JwtDecoderUI } from '../ui';
|
|
4
|
+
import { bibliography } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'jwt-decoder-parser-and-claims-inspector';
|
|
7
|
+
const title = 'JWT Decoder, Parser and Claims Inspector';
|
|
8
|
+
const description = 'JSON Web Token을 붙여넣고 헤더와 페이로드를 즉시 디코딩하며 등록된 클레임을 검사하고 만료된 토큰을 발견하며 인증 흐름을 디버깅하기 위해 깨끗한 JSON을 복사하세요.';
|
|
9
|
+
|
|
10
|
+
const howTo = [
|
|
11
|
+
{
|
|
12
|
+
name: 'JWT 붙여넣기',
|
|
13
|
+
text: 'Authorization 헤더, 쿠키, 로그 항목 또는 ID 공급자에서 토큰을 복사하여 입력 필드에 붙여넣으세요.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: '디코딩된 헤더와 페이로드 읽기',
|
|
17
|
+
text: '이 도구는 토큰을 헤더, 페이로드, 서명으로 분할한 다음 JSON 세그먼트를 별도의 패널에 표시하여 빠르게 검사합니다.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: '중요한 클레임 확인하기',
|
|
21
|
+
text: '알고리즘, 발급자, 수신자, 주체, 발급 시간, 유효 시작 시간, 만료 시간을 Unix 타임스탬프를 수동으로 변환하지 않고 검토하세요.',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '필요한 데이터 복사하기',
|
|
25
|
+
text: '팀과 정리된 디버깅 스냅샷을 공유해야 할 때 디코딩된 한 섹션이나 전체 디코딩 출력을 복사하세요.',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const faq = [
|
|
30
|
+
{
|
|
31
|
+
question: 'JWT를 디코딩하면 토큰이 유효하다는 것이 증명되나요?',
|
|
32
|
+
answer: '아니요. 디코딩은 base64url로 인코딩된 헤더와 페이로드만 보여줍니다. 토큰은 서명, 발급자, 수신자, 만료 및 관련 클레임이 애플리케이션이나 ID 공급자에 의해 검증된 후에만 신뢰할 수 있습니다.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
question: '이 JWT 디코더를 액세스 토큰과 ID 토큰에 사용할 수 있나요?',
|
|
36
|
+
answer: '네. 이 디코더는 표준 3부분 JWT 형식을 사용하는 한 OAuth 액세스 토큰, OpenID Connect ID 토큰, 세션 토큰 및 서비스 간 토큰을 검사하는 데 유용합니다.',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
question: '서명 패널이 토큰을 검증하지 않는 이유는 무엇인가요?',
|
|
40
|
+
answer: 'JWT 검증에는 올바른 시크릿, 공개 키 또는 JWKS 구성이 필요합니다. 이 도구는 눈에 보이는 서명 문자열이 유효성 증명인 것처럼 가장하지 않고 개발자가 토큰 내용을 볼 수 있도록 의도적으로 디코딩과 검사에 중점을 둡니다.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
question: 'JWT를 디버깅할 때 가장 먼저 무엇을 확인해야 하나요?',
|
|
44
|
+
answer: 'exp, nbf, iss, aud, alg부터 시작하세요. 대부분의 실제 운영 문제는 만료된 토큰, 클록 스큐, 잘못된 수신자 값, 예상치 못한 발급자 URL 또는 안전하지 않은 알고리즘 가정에서 비롯됩니다.',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const ui: JwtDecoderUI = {
|
|
49
|
+
tokenLabel: 'JWT 토큰',
|
|
50
|
+
tokenPlaceholder: '여기에 JWT 붙여넣기: header.payload.signature',
|
|
51
|
+
sampleButton: '샘플 로드',
|
|
52
|
+
clearButton: '지우기',
|
|
53
|
+
statusWaiting: 'JSON 헤더, 페이로드 및 클레임을 디코딩하려면 토큰을 붙여넣으세요.',
|
|
54
|
+
statusValid: 'JWT가 성공적으로 디코딩되었습니다.',
|
|
55
|
+
statusInvalid: '이것은 유효한 3부분 JWT로 보이지 않습니다.',
|
|
56
|
+
statusExpired: 'JWT가 디코딩되었지만 exp 클레임이 이미 만료되었습니다.',
|
|
57
|
+
statusUnsigned: 'JWT가 디코딩되었지만 서명되지 않았거나 alg none을 사용합니다.',
|
|
58
|
+
headerTitle: '헤더',
|
|
59
|
+
payloadTitle: '페이로드',
|
|
60
|
+
signatureTitle: '서명',
|
|
61
|
+
claimsTitle: '등록된 클레임',
|
|
62
|
+
copyHeader: '디코딩된 헤더 복사',
|
|
63
|
+
copyPayload: '디코딩된 페이로드 복사',
|
|
64
|
+
copySignature: '서명 복사',
|
|
65
|
+
copyAll: '모두 복사',
|
|
66
|
+
copiedLabel: '복사됨',
|
|
67
|
+
invalidTokenTitle: '유효하지 않은 JWT',
|
|
68
|
+
invalidTokenBody: '토큰에 점으로 구분된 3개의 base64url 세그먼트가 있는지 확인하세요.',
|
|
69
|
+
invalidSegmentError: '토큰에 점으로 구분된 3개의 base64url 세그먼트가 있는지 확인하세요.',
|
|
70
|
+
invalidDecodeError: '헤더 또는 페이로드를 유효한 JSON으로 디코딩할 수 없습니다.',
|
|
71
|
+
emptyJson: '{}',
|
|
72
|
+
signaturePresent: '서명 세그먼트가 있습니다. 인증 레이어에서 올바른 키로 검증하세요.',
|
|
73
|
+
signatureMissing: '서명 세그먼트 없음',
|
|
74
|
+
algorithmLabel: '알고리즘',
|
|
75
|
+
typeLabel: '유형',
|
|
76
|
+
issuerLabel: '발급자',
|
|
77
|
+
subjectLabel: '주체',
|
|
78
|
+
audienceLabel: '수신자',
|
|
79
|
+
issuedAtLabel: '발급 시간',
|
|
80
|
+
notBeforeLabel: '유효 시작',
|
|
81
|
+
expiresAtLabel: '만료 시간',
|
|
82
|
+
claimMissing: '없음',
|
|
83
|
+
privacyNote: '디코딩은 브라우저 세션에서 실행됩니다. 보안 정책에서 허용하지 않는 한 운영 시크릿을 어떤 도구에도 붙여넣지 마세요.',
|
|
84
|
+
sampleToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnYW1lYm9iLXVzZXItNDIiLCJuYW1lIjoiR2FtZUJvYiBEZXZlbG9wZXIiLCJpc3MiOiJodHRwczovL3d3dy5nYW1lYm9iLmRldiIsImF1ZCI6ImRldmVsb3Blci10b29scyIsImlhdCI6MTcxNzIwMDAwMCwibmJmIjoxNzE3MjAwMDAwLCJleHAiOjE4OTM0NTYwMDAsInJvbGUiOiJhZG1pbiJ9.demo-signature',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
88
|
+
'@context': 'https://schema.org',
|
|
89
|
+
'@type': 'FAQPage',
|
|
90
|
+
mainEntity: faq.map((item) => ({
|
|
91
|
+
'@type': 'Question',
|
|
92
|
+
name: item.question,
|
|
93
|
+
acceptedAnswer: {
|
|
94
|
+
'@type': 'Answer',
|
|
95
|
+
text: item.answer,
|
|
96
|
+
},
|
|
97
|
+
})),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const howToSchema: WithContext<HowTo> = {
|
|
101
|
+
'@context': 'https://schema.org',
|
|
102
|
+
'@type': 'HowTo',
|
|
103
|
+
name: title,
|
|
104
|
+
description,
|
|
105
|
+
step: howTo.map((step, index) => ({
|
|
106
|
+
'@type': 'HowToStep',
|
|
107
|
+
position: index + 1,
|
|
108
|
+
name: step.name,
|
|
109
|
+
text: step.text,
|
|
110
|
+
})),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
114
|
+
'@context': 'https://schema.org',
|
|
115
|
+
'@type': 'SoftwareApplication',
|
|
116
|
+
name: title,
|
|
117
|
+
description,
|
|
118
|
+
applicationCategory: 'DeveloperApplication',
|
|
119
|
+
operatingSystem: 'Any',
|
|
120
|
+
offers: {
|
|
121
|
+
'@type': 'Offer',
|
|
122
|
+
price: '0',
|
|
123
|
+
priceCurrency: 'EUR',
|
|
124
|
+
},
|
|
125
|
+
inLanguage: 'ko',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const content: ToolLocaleContent<JwtDecoderUI> = {
|
|
129
|
+
slug,
|
|
130
|
+
title,
|
|
131
|
+
description,
|
|
132
|
+
ui,
|
|
133
|
+
faqTitle: 'JWT 디코더 FAQ',
|
|
134
|
+
faq,
|
|
135
|
+
bibliographyTitle: 'JWT 명세 및 보안 참조',
|
|
136
|
+
bibliography,
|
|
137
|
+
howTo,
|
|
138
|
+
schemas: [appSchema, faqSchema, howToSchema],
|
|
139
|
+
seo: [
|
|
140
|
+
{
|
|
141
|
+
type: 'title',
|
|
142
|
+
text: '보안 컨텍스트를 잃지 않고 JWT 디코딩하기',
|
|
143
|
+
level: 2,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'paragraph',
|
|
147
|
+
html: 'JSON Web Token은 간결해 보이지만, 서명 알고리즘, 발급자, 수신자, 주체, 발급 시간, 유효 시작 시간, 만료 시간 및 애플리케이션별 인증 클레임 등 인증 실패를 설명하는 정확한 세부 정보를 담고 있는 경우가 많습니다. 이 <strong>JWT 디코더, 파서 및 클레임 인스펙터</strong>는 세 개의 토큰 세그먼트를 읽을 수 있는 JSON으로 변환하여 인증 흐름을 더 빠르게 디버깅할 수 있게 해줍니다.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'diagnostic',
|
|
151
|
+
variant: 'warning',
|
|
152
|
+
title: '디코딩이 신뢰를 의미하지는 않습니다',
|
|
153
|
+
html: '누구나 JWT를 base64url로 디코딩할 수 있습니다. 신뢰는 애플리케이션이 올바른 시크릿, 공개 키 또는 JWKS로 서명을 검증한 다음 발급자, 수신자, 만료 및 도메인별 클레임을 검증한 후에만 시작됩니다. 이 도구는 데이터 검사용으로 사용하고 토큰을 진짜로 받아들이는 데 사용하지 마세요.',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: 'title',
|
|
157
|
+
text: '각 JWT 세그먼트가 알려주는 것',
|
|
158
|
+
level: 3,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
type: 'table',
|
|
162
|
+
headers: ['세그먼트', '일반적인 내용', '디버깅 가치'],
|
|
163
|
+
rows: [
|
|
164
|
+
['헤더', '알고리즘, 토큰 유형 및 선택적 키 ID', 'HS256, RS256, ES256 또는 다른 검증 전략을 토큰이 기대하는지 보여줍니다.'],
|
|
165
|
+
['페이로드', '등록된 클레임 및 애플리케이션 클레임', '신원, 테넌트, 스코프, 역할, 만료 및 수신자 불일치를 드러냅니다.'],
|
|
166
|
+
['서명', 'base64url로 인코딩된 암호화 서명 바이트', '서명 세그먼트가 존재함을 확인하지만 다른 곳에서 올바른 키로 검증해야 합니다.'],
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
type: 'title',
|
|
171
|
+
text: '보통 인증 실패를 설명하는 클레임',
|
|
172
|
+
level: 3,
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: 'list',
|
|
176
|
+
items: [
|
|
177
|
+
'<strong>exp:</strong> 토큰이 만료된 경우 갱신 로직이나 클록 설정이 잘못되었을 수 있습니다.',
|
|
178
|
+
'<strong>nbf:</strong> 토큰이 아직 활성화되지 않은 경우 서버와 ID 공급자의 클록이 동기화되지 않았을 수 있습니다.',
|
|
179
|
+
'<strong>iss:</strong> 발급자 URL이 구성과 다른 경우 토큰이 잘못된 테넌트나 환경에서 온 것일 수 있습니다.',
|
|
180
|
+
'<strong>aud:</strong> 수신자가 API 식별자와 일치하지 않는 경우 토큰이 다른 리소스용으로 발급된 것입니다.',
|
|
181
|
+
'<strong>alg:</strong> 알고리즘이 예상치 못한 경우 검증기가 토큰을 거부하거나 위험한 구성 실수를 드러낼 수 있습니다.',
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
type: 'title',
|
|
186
|
+
text: '개발 중 JWT 파서의 사용 사례',
|
|
187
|
+
level: 3,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'comparative',
|
|
191
|
+
columns: 3,
|
|
192
|
+
items: [
|
|
193
|
+
{
|
|
194
|
+
title: '프론트엔드 디버깅',
|
|
195
|
+
description: '로그인 후 수신된 ID 토큰과 액세스 토큰을 검사하여 스코프, 역할 및 프로필 클레임을 확인하세요.',
|
|
196
|
+
icon: 'mdi:monitor-dashboard',
|
|
197
|
+
points: ['프로필 클레임 확인', '스코프와 역할 확인', '로그인 환경 비교'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
title: '백엔드 API QA',
|
|
201
|
+
description: '예상되는 발급자 및 수신자 값과 Authorization 헤더에 실제로 전송된 토큰을 비교하세요.',
|
|
202
|
+
icon: 'mdi:api',
|
|
203
|
+
highlight: true,
|
|
204
|
+
points: ['수신자 형태 검증', '발급자 불일치 발견', '베어러 토큰 검사'],
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
title: 'ID 공급자 설정',
|
|
208
|
+
description: 'Auth0, Azure AD, Cognito, Keycloak 또는 커스텀 공급자의 클레임이 앱이 기대하는 형태인지 확인하세요.',
|
|
209
|
+
icon: 'mdi:account-key',
|
|
210
|
+
points: ['테넌트 데이터 검토', '커스텀 클레임 확인', '공급자 매핑 비교'],
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
type: 'title',
|
|
216
|
+
text: '이 인스펙터가 명확하게 보여주는 일반적인 JWT 실수',
|
|
217
|
+
level: 3,
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
type: 'proscons',
|
|
221
|
+
title: '빠른 검사 vs 신뢰 결정',
|
|
222
|
+
items: [
|
|
223
|
+
{
|
|
224
|
+
pro: '잘못된 형식의 토큰을 즉시 확인할 수 있습니다.',
|
|
225
|
+
con: '예상하는 수신자나 발급자를 알 수 없습니다.',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
pro: 'Unix 타임스탬프 클레임을 읽을 수 있는 날짜로 변환합니다.',
|
|
229
|
+
con: '실제 키 자료 없이는 서명을 검증할 수 없습니다.',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
pro: '발급자, 수신자, 주체, 유형의 누락된 값을 찾습니다.',
|
|
233
|
+
con: '스코프와 역할이 애플리케이션에 안전하다는 것을 증명할 수 없습니다.',
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
type: 'summary',
|
|
239
|
+
title: '모범 사례 워크플로',
|
|
240
|
+
items: [
|
|
241
|
+
'클라이언트나 API가 실제로 받은 내용을 이해하기 위해 토큰을 디코딩하세요.',
|
|
242
|
+
'애플리케이션 로직을 추적하기 전에 exp, nbf, iss, aud, sub, alg를 확인하세요.',
|
|
243
|
+
'서명과 신뢰 결정은 인증 레이어에서만 검증하세요.',
|
|
244
|
+
'민감한 운영 JWT를 티켓, 로그, 스크린샷에 공유하지 마세요.',
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|