Webサイトを開くとき、ブラウザとサーバーの間では必ず HTTP(HyperText Transfer Protocol) という通信ルールが使われています。
しかし、実際にどんな情報が送られ、どのようにページが表示されているのかは意外と知られていません。
この記事では、
- HTTPとは何か
- ブラウザとサーバーがどんな情報をやり取りしているのか
- 開発者ツールを使った実際の通信の見方
- Cookie / Session の仕組み
- CSRF・XSS などのセキュリティ
- HTTPS(TLS)との関係
- HTTP/1.1・HTTP/2・HTTP/3 の違い
といった、Web通信の基礎から実践・セキュリティまでを、初心者にも分かりやすく丁寧に解説します。
HTTPとは何か?
HTTPとは、ブラウザ(クライアント)とWebサーバーが通信するための約束事です。
たとえば、あなたがブラウザで次のURLにアクセスしたとします。
https://example.com/index.html
このときブラウザは、
「example.comさん、index.htmlをください」
というリクエストをHTTPというルールに従って送っています。
HTTP通信の全体の流れ
HTTPの基本的な流れはとてもシンプルです。
- ブラウザがリクエストを送る
- サーバーがレスポンスを返す
- ブラウザが表示する
次のようなイメージです。
ブラウザ → HTTPリクエスト → サーバー
ブラウザ ← HTTPレスポンス ← サーバー
HTTPリクエストの中身
ブラウザが送るHTTPリクエストには、次の情報が含まれています。
メソッド(Method)
「何をしたいか」を表します。
| メソッド | 意味 |
|---|---|
| GET | データを取得したい |
| POST | データを送信したい |
| PUT | データを更新したい |
| DELETE | データを削除したい |
Webページを表示するときは、ほとんどの場合 GET が使われます。
URL(パス)
どのリソースが欲しいかを指定します。
GET /index.html HTTP/1.1
これは「/index.html をください」という意味です。
ヘッダー(Header)
追加情報です。たとえば、
- 使用しているブラウザ
- 対応できるデータ形式
- Cookie情報
などが入ります。
User-Agent: Chrome
Accept: text/html
HTTPレスポンスの中身
サーバーは、リクエストを受け取るとレスポンスを返します。
ステータスコード
リクエストの結果を表す番号です。
| コード | 意味 |
|---|---|
| 200 | 成功 |
| 301 | リダイレクト |
| 404 | ページが存在しない |
| 500 | サーバーエラー |
「404 Not Found」は特に有名ですね。
ヘッダー
レスポンス側の追加情報です。
- データの種類(HTML、JSONなど)
- 文字コード
- キャッシュ設定
ボディ(Body)
実際のデータ本体です。
HTMLページなら、ここにHTMLコードが入っています。
HTTPはステートレス
HTTPの重要な特徴として、ステートレスである点があります。
つまり、
「前の通信を覚えていない」
ということです。
ログイン状態を維持できるのは、CookieやSessionといった仕組みをHTTPの上に追加しているからです。
実際にHTTP通信を確認してみる(Edge開発者ツール)
ここからは、実際にブラウザで私のサイトhttps://kikuichige.com/index.html
へアクセスし、HTTP通信の中身を確認してみます。
使用ブラウザは Microsoft Edge です。
開発者ツールを開く
- Edgeで
https://kikuichige.com/index.htmlにアクセスする - キーボードで
F12またはCtrl + Shift + I、または、ブラウザ画面のどこかで右クリック→「開発者ツールで調査する」 - 開発者ツールが表示される
Networkタブを開く
- 上部メニューから Network を選択
- その状態で ページを強制再読み込み(Shift+F5)
F5だけの再読み込みでもいいが、その場合ステータスコードが200(正常)ではなく304になります。
304(Not Modified):Webブラウザなどのクライアントがキャッシュしているコンテンツが最新であり、サーバーからデータを再ダウンロードする必要がないことを示す、正常(成功)を示すHTTPレスポンス
毎回たくさん表示されるので、∅(Clear network log)アイコンをクリックしてログをクリアしてからShift+F5をクリックしてください。
👉 ここで ブラウザとサーバーの通信一覧 が表示されます。
HTTPリクエストを確認する
index.html の通信を探す
Network一覧の中から、1番上のログ
- Name:
index.html
または - ドメイン名(
kikuichige.com)
の行をクリックします。
Request(リクエスト)の確認方法
右側ペインで Headers タブを選択します。
Request Headers に注目
ここが、ブラウザから送られた HTTPリクエスト です。
確認できる代表的な項目:
General(Responseの内容も混ざっています。Requestの部分だけ書きます。)
- Request URL
https://kikuichige.com/index.html - Request Method
GET
Request Headers
- authority kikuichige.com
- method GET
- path /index.html
- scheme https
...
👉
「ブラウザがGETでindex.htmlを要求している」
という説明と対応します。
HTTPレスポンスを確認する
同じ画面で、今度は Response Headers を確認します。
ステータスコード
画面上部、または Headers 内に次のように表示されます。
General(Requestの内容も含まれますが、Responseだけ書きます。)
- Status Code: 200 OK
これは、
リクエストが正常に処理された
ことを意味します。
レスポンスヘッダの確認
Response Headers代表的な項目:
- Content-Type
text/html - Content-Length 40991
- Server nginx
...
👉
「サーバーがHTMLを返している」
という説明と一致します。
HTTPレスポンスボディ(HTML)を確認する
方法① Responseタブ
- 同じ通信を選択
- Response タブをクリック
👉 サーバーから返された HTML本体 が表示されます。
方法② Previewタブ
- Preview タブを選ぶと
- HTMLがレンダリングされた状態で表示されます
- この時点では、cssや画像ファイルはダウンロードされていないのでhtmlで表現されているものが表示されます。この後、html内に書かれている内容に沿って必要なファイル(css、画像など)がダウンロードされていきます。
HTTPはステートレスであることを確認する
Cookieの確認
- 同じ通信の Headers タブ
- Request Headers 内の
Cookieを確認
Cookie: xxxx=yyyy
👉 もし Cookie が送られていれば、
「ブラウザが毎回自動で送信している」
ことが分かります。
ページを再読み込みしてみる
- Shift+F5で再読み込み
- 毎回 新しいHTTPリクエスト が送られている
👉
「HTTPはリクエストごとに独立している」
=ステートレス、という説明につながります。
CookieとSessionの仕組み|HTTPが「覚えていない」問題をどう解決するか
HTTPはとてもシンプルなプロトコルですが、
その代わりに 重大な弱点 を持っています。
HTTPはステートレス(状態を保持しない)
CookieとSessionは、この弱点を補うための仕組みです。
なぜCookieとSessionが必要なのか?
HTTPでは、リクエストごとにすべてが独立しています。
1回目のリクエスト → サーバーは覚えない
2回目のリクエスト → さっきの人か分からない
そのままだと、
- ログイン状態を維持できない
- カートの中身を覚えられない
- 個人設定を保存できない
といった問題が起きます。
👉 「同じユーザーだと識別する仕組み」が必要になります。
Cookieとは何か?
Cookieは、
ブラウザに保存され、毎回のHTTPリクエストに自動で付与される小さなデータ
です。
Cookieの基本的な流れ
① サーバー → レスポンスでCookieを送る
② ブラウザ → Cookieを保存
③ 次回以降 → リクエストにCookieを自動付与
HTTPレベルで見ると、こうなります。
Set-Cookie: session_id=abc123
実際は、session_idという分かりやすい名前はついていません。
次のリクエストでは、
Cookie: session_id=abc123
が自動的に送られます。
Cookieの正体
- 保存場所:ブラウザ
- 中身:文字列(キー=値)
- 送信単位:HTTPリクエストごと
HTTPがステートレスでも、
「毎回同じ情報を送る」ことで擬似的に状態を持たせるのがCookieです。
保存されたCokkieを見る方法
Edgeの設定→「プライバシー/検索/サービス」→「cokkie」→「
すべての Cookie とサイト データを表示する」
例示した私のサイトhttps://kikuichige.com/index.htmlの場合、Googleの広告を表示するためのJavascriptが動いているため、そのcokkieが保存されます。またkikuichige.comでWordpressもやっているので、そちらを見たことがある方は、__eoiなどのcokkieが表示されると思います。
Sessionとは何か?
Sessionは、
サーバー側で状態を管理する仕組み
です。
本体データはサーバーに保存されます。
Sessionの基本構造
ブラウザ:session_id をCookieに保持している
サーバー:session_id に紐づいた実データを保持。
ブラウザから送られてきたクッキーsession_id = abc123。
サーバーでも同じ値を保持しているので、その値から実データが分かる。
↓
{
user_id: 42,
login: true,
cart: [...]
}
Sessionが必要な理由
Cookieに直接データを入れると、
- 改ざんされる
- サイズ制限がある
- 機密情報を入れられない
という問題があります。
👉 「識別子だけをCookieで渡し、実体はサーバーに置く」
これがSessionの基本思想です。
CookieとSessionの関係
よく混同されますが、役割ははっきり分かれています。
| 項目 | Cookie | Session |
|---|---|---|
| 保存場所 | ブラウザ | サーバー |
| 役割 | 識別子を運ぶ | 状態を保持 |
| HTTPとの関係 | ヘッダとして送信 | 直接は関与しない |
👉 SessionはCookieなしでは成立しない
(session_idを運ぶ手段が必要)
Secure / HttpOnly 属性
Cookieには追加属性があります。
Set-Cookie: session_id=abc123; Secure; HttpOnly
- Secure
- HTTPS通信でのみ送信される
- HttpOnly
- JavaScriptからアクセス不可(XSS対策、後述します。)
👉 TLSと組み合わせて初めて、安全性が成立します。
「ログインしている」状態の正体
多くのWebサービスでのログイン状態は、
Cookie(session_id)
↓
Session(ログイン済みフラグ)
という構造です。
- ログアウト
→ Sessionを破棄 - Cookieが残っていても
→ Sessionがなければ未ログイン
CSRFとCookieの関係|「本人が操作していないのに実行される」理由
CSRF(Cross-Site Request Forgery)は、
Cookieの仕組みを“正しく”使っているからこそ起きる攻撃です。
まず結論から言います。
CSRFは「ブラウザが自動でCookieを送る」ことを悪用した攻撃
です。
なぜCSRFが成立するのか?
Cookieの重要な性質を思い出してください。
Cookieは、条件を満たせばブラウザが自動送信する
ユーザーの意思は関係ありません。
攻撃が成立する前提条件
CSRFが成立するには、次の条件が揃っている必要があります。
- ユーザーが対象サイトにログイン済み
- 認証にCookie(Session ID)を使っている
- 攻撃者が悪意あるサイトを用意し、ユーザーが、そこを閲覧すると対象サイトにリクエストを発生させられる
👉 これ、全部「普通のWebサイト」です。
CSRF攻撃の典型例
登場人物
- 被害者:すでに銀行サイト(https://bank.example/transfer)にログイン中
- 攻撃者:悪意のあるサイトを用意(https://attacker.com)
- ブラウザ:忠実に仕事をするだけ(cokkieを保存したサイトにアクセスするときはcokkie(session_id)を付けて送信する。)
攻撃の流れ
- 被害者が銀行サイトにログイン。
Cookie: session_id=abc123がブラウザに保存される。 - そのまま攻撃者サイト“https://attacker.com/index.html”を開く
- 攻撃者サイトに仕込まれたHTMLが実行される
攻撃者サイト“https://attacker.com/index.html”の中身
<img src="https://bank.example/transfer?to=attacker&amount=100000">
<imgタグはsrcに書かれたサイトにアクセスして画像をダウンロードするためのもの。
本来の使い方
<img src="https://bank.example/transfer/画像ファイル(sample.jpgなど)
しかし、<img は、画像が置いてあるかなどはいちいちチェックせず、srcに書かれてるサイトにGETでアクセスしてるだけ。
- ブラウザは自動でCookieを送る
つまり、”https://bank.example/transfer?to=attacker&amount=100000″にcookie(session_id=abc123)付きでGETでアクセスしてしまう。
GET /transfer?to=attacker&amount=100000 HTTP/1.1
Cookie: session_id=abc123
- サーバー側はこう判断する
「正しいCookieが来た → 本人の操作だ」
結果:https://bank.example/transferは、to=attacker&amount=100000を正規の要求とし意図しない送金が実行される
重要なポイント(本質)
CSRFは、
- Cookieが盗まれたわけではない
- 認証が破られたわけでもない
👉 「正規の認証情報を、別サイトから使われただけ」
というのが本質です。
なぜ「パスワード再入力」は起きないのか?
サーバーは通常、
- Cookieがあればログイン済み
- 操作者が本人かどうかは確認しない
という設計です。
CSRFは、
「誰が操作したか」ではなく
「どのCookieで来たか」
だけを見ていることを突きます。
CSRFとXSS(後述)の違い(混同しやすい)
| 項目 | CSRF | XSS |
|---|---|---|
| 攻撃元 | 別サイト | 同一サイト(掲示板などに悪意あるコード埋め込まれる) |
| Cookie | 自動送信 | JavaScriptで盗める |
| 主な対策 | トークン | エスケープ |
👉 CSRFではCookieは盗まれない
ここは超重要です。
CSRF対策は「Cookieを信用しない」
CSRF対策の基本思想はこれです。
「Cookieが送られてきただけでは信用しない」
CSRFトークン
最も一般的な対策です。
- サーバーがランダムなトークンを生成
- フォーム(送金指示フォームなど)に埋め込む
- リクエスト時に一致を確認
<input type="hidden" name="csrf_token" value="random123">
👉 攻撃者サイトからはこの値を生成できない。つまり、正規の送金指示フォームから来たリクエストにはなれない。
SameSite Cookie
Cookie属性で送信条件を制限します。
Set-Cookie: session_id=abc123; SameSite=Lax
- Strict:完全に他サイト送信禁止(別サイトのHTMLに書かれた指示(imgタグなど)によって、被害者のブラウザが自動で送ってしまうリクエストのこと)
- Lax:一部のGETのみ許可
- None:制限なし(Secure必須)
👉 最近のブラウザは Laxがデフォルト。
Referer / Origin チェック
- 送信元ドメインを確認
- 偽装される可能性あり
- 補助的対策として使用
XSSとは何か?
XSS(Cross-Site Scripting)とは、
攻撃者が用意したスクリプト(主にJavaScript)を、
正規サイト上で実行させる攻撃
です。
ポイントは、
- 攻撃元は「別サイト」ではない
- 正規サイトのページ内で実行される
という点です。
何が危険なのか?
XSSが成立すると、攻撃者のスクリプトは:
- 正規サイトの権限で実行される
- ユーザーのブラウザ内で動く
つまり、
「そのサイトにログインしている本人として動ける」
状態になります。
XSSで何ができてしまうか
代表例です。
- Cookieの取得(
HttpOnly(JavaScriptからアクセス不可) でない場合) - フォーム内容の盗み見
- 勝手なリクエスト送信
- 画面の改ざん
- フィッシング表示
👉 CSRFより強力なケースも多いです。
XSSが起きる原因(超重要)
原因はほぼ1つです。
ユーザー入力をそのままHTMLとして出力している
例(危険):
<p>こんにちは {{ username }}</p>
もし username に
<script>alert(1)</script>
が入ると、そのまま実行されます。
XSSの3つの種類(簡単に)
Stored XSS(保存型)
- 掲示板・コメント欄など
- 悪意あるスクリプトがDBに保存
- 閲覧した全員が被害
Reflected XSS(反射型)
- URLパラメータに埋め込む
- リクエストごとに反射
- クリックした人だけ被害
DOM-based XSS
- サーバーは無関係
- JavaScriptの処理ミス
- フロントエンド由来
XSSとCookieの関係
重要な関係です。
HttpOnlyが ない Cookie
→ JavaScriptで読める- 読めたCookie
→ セッション乗っ取り
👉 XSSはSession奪取の入口になりがち。
XSS対策(最小限)
- 画面出力時エスケープ(最重要)
HttpOnlyCookieContent-Security-Policy (CSP)、後述します。- フレームワーク利用
👉 入力チェックより出力チェック。
Content-Security-Policy(CSP)とは何か?
「ブラウザに対して、どのリソースを読み込んでよいかを制限するルール」
です。
XSSは「悪意あるスクリプトが実行される」攻撃でした。
CSPは、
「そもそも実行できるスクリプトを制限する」
ことで被害を防ぎます。
なぜCSPがXSS対策になるのか?
XSSの本質は:
<script>alert('hacked')</script>
のようなスクリプトが実行されること。
CSPで、
「このサイトでは、外部の怪しいスクリプトは読み込んではいけません」
とブラウザに命令できます。
つまり、
攻撃コードがHTMLに入り込んでも、ブラウザが実行しない
という状態を作れます。
どうやって設定するの?
HTTPレスポンスヘッダーで設定します。つまりサーバーが設定する。
よく使われるディレクティブ
① script-src
Content-Security-Policy: script-src 'self';
意味:
自分のサイトのJavaScriptだけ実行可能
② style-src
CSSの読み込み制限
③ img-src
画像の読み込み元を制限
④ object-src
Flashなどを禁止(ほぼ必須)
インラインスクリプトは?
これが重要ポイントです。
通常、CSPを設定すると:
<script>alert(1)</script>
のような**HTML内に直接書いたスクリプト(inline script)**はブロックされます。
これがXSS対策として強力です。
nonce(ノンス)という仕組み
安全なインラインスクリプトだけ許可したい場合:
Content-Security-Policy: script-src 'nonce-abc123';
HTML側:
<script nonce="abc123">
console.log("安全なスクリプト");
</script>
👉 nonceが一致するものだけ実行される。
攻撃者はnonceを知らないので突破できません。
HTTPとTLSの関係|どこから暗号化され、いつHTTPが始まるのか
HTTPSは、HTTPを暗号化したものです。
| 項目 | HTTP | HTTPS |
|---|---|---|
| 通信内容 | 丸見え | 暗号化 |
| 安全性 | 低い | 高い |
| URL | http:// | https:// |
HTTPSでは、通信前に TLS(SSL) という仕組みで鍵交換を行い、安全な通信路を作ります。
現在は、ほぼすべてのWebサイトでHTTPSが使われています。
HTTPSは「HTTP + TLS」とよく説明されますが、
実際にどのタイミングで何が起きているのかは少し分かりづらいポイントです。
ここでは次の2点に絞って整理します。
- TLSハンドシェイクとHTTPはどの順番で動くのか
- HTTPはどの単位で暗号化されているのか
※ TLSの詳細な仕組みは別記事↓↓にまとめていますので、ここでは説明しません。
TLSハンドシェイクが終わった後にHTTPが始まるのか?
結論:はい。HTTPはTLSハンドシェイク完了後に始まります。
通信の流れを時系列で並べると、次のようになります。
① TCP接続確立(3-way handshake)
② TLSハンドシェイク
③ HTTPリクエスト / レスポンス(暗号化)
重要なのは、
TLSハンドシェイク中にはHTTPは一切流れない
TCP接続確立(3-way handshake)とは何か
TCPの3-way handshakeとは、
通信を始める前に、
お互いが「話せる状態か」を確認する手順
です。
いきなりデータを送り始めるのではなく、
3回のやり取りで接続を確立します。
3-way handshake の流れ(超シンプル)
登場人物は2人だけです。
- クライアント(ブラウザ)
- サーバー
SYN(接続したい)
クライアント → サーバー
「接続したいです(SYN)」
SYN-ACK(いいですよ)
サーバー → クライアント
「いいですよ+あなたの要求を確認しました(SYN-ACK)」
ACK(確認しました)
クライアント → サーバー
「確認しました(ACK)」
これで、
TCP接続が確立
します。このあとの「TLSハンドシェイク」はこちら↓↓を参照してください。
なぜHTTPはTLSの後なのか?
理由はシンプルで、
- TLSは「暗号化された通信路を作る」ための仕組み
- HTTPは「その通信路を使ってデータをやり取りする」プロトコル
だからです。
暗号鍵がまだ共有されていない状態では、HTTPを安全に送れません。
実際のイメージ
(TLSハンドシェイク=平文)
ClientHello
ServerHello
Certificate
Finished
-----------------
(ここから暗号化)
GET /index.html HTTP/1.1
HTTP/1.1 200 OK
HTTPは必ず暗号化された状態で登場します。
HTTPはどの単位で暗号化されるのか?
これも結論から言うと、
HTTPメッセージ単位ではなく、TLSレコード単位で暗号化される
というのが正確な答えです。
よくある誤解
❌「HTTPリクエスト全体が1つの暗号ブロックになる」
❌「1リクエスト = 1暗号化」
→ どちらも違います
TLSは「ストリーム」を分割して暗号化する
TLSは下位層として、
- HTTPの内容を ただのバイト列 として受け取り
- それを一定サイズに分割し
- TLSレコードとして暗号化します
HTTPデータ(バイト列)
↓
TLS Record #1(暗号化)
TLS Record #2(暗号化)
TLS Record #3(暗号化)
この分割は、
- HTTPの区切り
- ヘッダとボディ
- リクエスト境界
とは 一切関係ありません。
具体例(イメージ)
GET /index.html HTTP/1.1\r\n
Host: example.com\r\n
User-Agent: Chrome\r\n
\r\n
このHTTPリクエストが、
TLS Record A(途中まで)
TLS Record B(残り)
のように分割されて暗号化されることも普通にあります。
HTTP/1.1・HTTP/2・HTTP/3との関係
HTTP/1.1
- HTTPメッセージをそのままストリームとして送る
- TLSはそれを気にせず暗号化
HTTP/2
- HTTP自体がフレーム化されている
- ただし TLSはHTTP/2フレームの中身を理解しない
HTTP/2フレーム → バイト列 → TLSレコード
HTTP/3(補足)
HTTP/3は、HTTP/1.1 や HTTP/2 の後継となる新しいHTTPです。
大きな違いは、通信の土台が変わった点にあります。
何が変わったのか?
従来(HTTP/1.1 / HTTP/2)
HTTP
↓
TLS(暗号化)
↓
TCP(通信の仕組み)
↓
IP
HTTP/3
HTTP
↓
QUIC(暗号化+通信の仕組み)
↓
UDP
↓
IP
TCP:データを確実に届けるため、確認応答や再送を行い、Web閲覧やメールに適した高信頼性・低速度の通信です。
UDP:速度を最優先し、一方的にパケットを送るため、オンラインゲームやストリーミングなどリアルタイム性が求められる用途に適した低信頼性・高速度の通信です。
QUIC:UDP上で動く次世代トランスポート
QUICはUDPの上に TCP並みの信頼性と、TCP以上の高速性 を実現するための仕組みを追加したプロトコル。
QUICが提供する主な機能:
- 輻輳制御
- パケット番号管理
- ACK(確認応答)
- 欠落検出と再送制御
- 0-RTT接続(再接続が高速)
- ヘッドオブラインブロッキングの解消(HTTP/3の高速化に寄与)
つまり:
UDPの「送りっぱなし」を、QUICが高度な制御で補完し、TCPより高速で信頼性の高い通信を実現する。
TLS 1.3はQUICに統合されている
HTTP/1.1 や HTTP/2 では、
- 通信を始める前に
- TLSハンドシェイクを別途行う
必要がありました。
HTTP/3では、
暗号化(TLS 1.3)がQUICの中に最初から組み込まれている
という違いがあります。
👉 そのため、通信開始が速くなります。
それでも考え方は同じ
仕組みは変わっても、考え方は変わりません。
HTTPは「暗号化された通信路」の上に乗っている
という点は、HTTP/2以前と同じです。
- HTTPが暗号化しているわけではない
- 下の層(QUIC)が暗号化を担当している
まとめ
- HTTPはブラウザとサーバーが通信するための基本ルール
リクエストとレスポンスのやり取りでWebページが表示される。 - HTTPはステートレス
過去の通信を覚えないため、ログイン状態の維持には Cookie / Session が必要。 - Cookieは識別子をブラウザに保存し、毎回自動送信される仕組み
Sessionはサーバー側で状態を保持する。 - CSRFは「Cookieが自動送信される性質」を悪用した攻撃
対策には SameSite Cookie や CSRFトークンが有効。 - XSSは「ユーザー入力をそのまま出力する」ことで起きる攻撃
出力エスケープやCSPで防ぐ。 - HTTPSはHTTPをTLSで暗号化したもの
TLSハンドシェイク後にHTTP通信が始まり、内容はTLSレコード単位で暗号化される。 - HTTP/3はQUIC(UDPベース)を採用し、より高速で安定した通信を実現
QUICは輻輳制御・再送制御・暗号化を統合し、TCPの弱点を克服している。
この記事を書いたイチゲを応援する(質問でもokです)
Vプリカでのお支払いがおすすめです。
