0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個別通信プロトコルと脆弱性(第4回)/HTTP前編WWW

Last updated at Posted at 2025-05-13

はじめに

  • プログラミング初学者向けに
  • まず、インターネット上の情報を閲覧・共有するためのWorld Wide Webという概念を学ぶ
    • HTML
    • URL
    • MIME-type

World Wide Webとは?

WWW(World Wide Web)は、インターネット上で情報を閲覧・共有するためのシステムで、インターネット上の情報を、文書相互の関連付けされた状態をネットワークを覆う蜘蛛の巣(Web)に見立てた名称です。

Tim Berners-Leeが提唱し、HTTP(Hypertext Transfer Protocol)を使ってハイパーテキスト文書をやり取りする仕組みとして設計されました。

Webサイトを見るという行為は、まるで「ショーウィンドウ越しに商品を見ている」ようなもの。 でもその裏では、あなたの手の動き、視線、クリックが全部記録され、しかも誰かがこっそり店内のレイアウトを変えているかもしれません。

今回は、そんな「見えているけど見えていない」HTTP通信の裏側を体験します。

4-1. WWWの基本構造( Why / What / How)

項目 内容
Why インターネット上の情報を関連付け、直感的かつ効率的に閲覧・共有すること
What 関連付け情報を持つテキストベースの統一データ形式HTMLと参照形式URLで、サーバとクライアントが文書や画像、スクリプトなどをやり取りする仕組みのこと
How リクエスト・レスポンス型のステートレスプロトコル。Webブラウザという専用ソフトウェアを使う

Webブラウザ登場以前の情報共有

もともとインターネット上で情報をやり取りする手段としては、電子メール(SMTP/POP3/IMAP)やファイル転送(FTP) が主流でした。しかし、これらには次のような課題がありました。

  • 情報共有の難しさ
    • メールやFTPでは個々のファイルを直接送受信する形態であり、
      • 文書が増えると管理が煩雑
      • リンクを介して文書を関連付ける手法が存在しなかった
    • 文書のリンクを使って、直感的に情報を辿れる仕組みが必要でした。
  • フォーマットの統一性がない
    • メールはテキスト主体であり、リッチコンテンツ(画像、表、レイアウト)が使いにくい
    • 異なるコンピュータ環境でフォーマットが崩れることが多かった
  • 多様な情報へのアクセスが不便
    • FTPサーバにアクセスし、ディレクトリ構造を辿って手動でファイルを探す必要があり、非効率
    • 情報を検索して、すぐにアクセスできる仕組みが求められた

WWWプロジェクト(1989年): HTMLとURLの発明

HTMLが情報を構造化し、URLで情報を特定し、HTTPで情報を送受信する。

  1. HyperText Markup Language( HTML ); 情報構造の統一記述言語
    • 情報を構造化した文書から体裁情報を分離し、Cascading Style Sheet(CSS)が成立(1996年)
  2. Uniform Resource Locator(URL); インターネット上の文書に一意性を与える参照形式
    • 識別子として: HTML文書内で他文書との関係を定義できる
    • 参照情報として: URLだけで必要な文書の取得が可能
  3. HyperText Transfer Protocol(HTTP); 情報を送受信するためのプロトコル
    • リクエスト・レスポンス型のステートレス通信(次回詳しくやります)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>HTML文書のひな型</title>
    <!-- 体裁情報はスタイルシートで指定 -->
    <link rel="stylesheet" href="styles.css">    
    <!-- 前のページ -->
    <link rel="prev" href="previous.html">
    <!-- 次のページ -->
    <link rel="next" href="next.html">
    <!-- 目次ページ -->
    <link rel="contents" href="index.html">
    <!-- 著者情報 -->
    <link rel="author" href="about.html">
    
</head>
<body>
  <main>
	  <p>Hello, World!</p>
  </main>
</body>
</html>
body > main > p {
  color: red;
}

  • URLとURNを包含する上位概念URI

    • URLが「場所
    • URNは「名前
  • どちらもリソースの識別子であり、状況に応じて使い分ける

  • URLの例

    • https://www.example.com/index.html
  • URNの例

    • urn:isbn:978-3-16-148410-0
  • URIの例(URLとURNの両方を含む):

    • http://example.com
    • urn:ietf:rfc:2141
  • URLの構造

URL
  href
    origin
      protocol
        scheme: http, https, mailto など
        ‘//’
    authority
      userinfo
        username
        `:`
        password
      `@` 
      host
        hostname
          subdomain
            lower
          domain
            second
            toplevel
      `:` 
      port
    resource
      pathname
        dirname
        filename
          basename
          extension
      `?`
      search
      `#`
      hash
/*
                                                           href
                   ┌────────────────────────────────────────┴──────────────────────────────────────────────┐
                origin                                                                                     │
      ┌────────────┴──────────────┐                                                                        │
      │                       authority                                                                    │
      │           ┌───────────────┴───────────────────────────┐                                            │
      │           │                                         host                                       resource
      │           │                                ┌──────────┴─────────────────┐             ┌────────────┴───────────┬───────┐
      │           │                             hostname                        │          pathname                    │       │
      │           │                 ┌──────────────┴────────────┐               │      ┌──────┴───────┐                │       │
  protocol     userinfo         subdomain                    domain             │      │           filename            │       │
   ┌─┴──┐     ┌───┴────┐            │                  ┌────────┴───────┐       │      │          ┌───┴─────┐          │       │
scheme  │username password lowerleveldomains secondleveldomain topleveldomain port  dirname    basename extension    search   hash
┌──┴───┐│┌──┴───┐ ┌──┴───┐ ┌──┬─┬─┴─────┬───┐┌───────┴───────┐ ┌──────┴──────┐┌─┴┐┌────┴──────┐┌──┴───┐ ┌───┴───┐ ┌────┴────┐ ┌┴┐
│      │││      │ │      │ │  │ │       │   ││               │ │             ││  ││           ││      │ │       │ │         │ │ │
scheme://username:password@test.abcdedgh.www.secondleveldomain.topleveldomain:1234/hello/world/basename.extension?name=ferret#hash
*/

4-2. 実習1: HTTP通信の基礎

nodejsによるWebサーバ

以下は、Node.jsで簡単なWebサーバ(HTTP通信をするサーバ)を構築するコードです。

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;                   // HTTPステータスコード(1)
  res.setHeader('Content-Type', 'text/plain');  // MIME-type(2)
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

説明

  • httpモジュールの利用:Node.jsに組み込まれている標準モジュールを使用
  • createServer関数:リクエストを受け取り、レスポンスを返すサーバを生成
  • res.statusCode:HTTPステータスコードを設定(200 OK)
  • res.setHeader:レスポンスのヘッダーを設定(Content-Type: text/plain)
  • res.end:クライアントにレスポンスを送信し、接続を終了
  • server.listen:指定したホスト名とポートでサーバを待機

実行方法

  1. VSCodeで新しいワークスペースを開く

    • ファイル>名前を付けてワークスペースを保存> httpserverで保存
  2. ファイルを編集する

    • ファイル>新規ファイル
  3. server.jsで保存する

  4. nodejsプログラムの実行;

    • 実行>デバッグの開始>Node.js
  5. 戻ってWebサーバプログラムの停止; 右端の四角を押下

    image.png

  6. 先ほどの新たなタブに戻ってリロードすると、アクセスを拒否される

    image.png

サーバサイドデバッグ

(1) ブレークポイントの設定

(2) Webブラウザで3000ポートで開いたページに移動をすると、VSCode上で設定したブレークポイントで停止

(3) ブレークポイントからステップ実行/再開

クライアントサイドデバッグ

Webブラウザは二種類の通信をしています。Webサーバに要求した リクエスト通信と、応答するレスポンス通信です。WebブラウザChromeでは メニューボタン > その他メニュー > デベロッパーツール > Network を選んでおきます。

(1) HTTPリクエストの実体確認; Webブラウザにhttp://localhost:3000と入力 > リクエスト通信(localhost)を選択 > Headersタブを選択 > General > Request URL に注目

  • Headers > Response Headers > view source
  • Headers > Request Headers > view source

このview sourceのアンカーをクリックすると、パース前の、通信内容が確認できます。

(2) HTTPレスポンスの実体確認; Responseタブを選択

(3) HTTPステータスコード

  • おなじみの200, 404, 500などあります。詳しくはRFCを参照のこと
  • Webサーバと接続に成功して、レスポンス通信が受け取れたら200と思ってください
  • 接続に成功しても、サーバ側でエラーが生じた場合は400番台や500番台のステータスコードが返ってきます
  • 接続に失敗したら、そもそもHTTP通信が始められなかったということです

4-3. 実習2: HTTPヘッダContent-TypeとWebブラウザの解釈

server.jsを順次書き換えていくことで、HTTP通信を理解します。

Content-Type: text/plain

(1) res.write()

server.jsを書き換えたらデバッグ実行中のメニューで回転矢印のリロードボタンを押すと、デバッグプロセスの停止、ファイル保存、再読込、デバッグの開始と、一連の動作をまとめてやってくれます。

const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;                         // HTTPステータスコード(1)
  res.setHeader('Content-Type', 'text/plain');  // MIME-type(2)
  res.write('Hello World');
  res.end();
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

(2) 繰り返し

const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;                         // HTTPステータスコード(1)
  res.setHeader('Content-Type', 'text/plain');  // MIME-type(2)
  for(var i = 0; i < 5; i++)
    res.write('Hello World');
  res.end();
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

(3) writeしたからといって直ちに通信しているわけではない(重要)

  • res.write行にブレークポイントを仕掛けておく
  • http://localhost:3000/でアクセス
  • ブレークポイントで止まったら、ステップ実行
  • res.end()で初めてレスポンス通信が開始していることがわかるでしょう

Content-Type: text/html

(1) HTTPヘッダがtext/htmlの場合、HTTPボディの中身はHTML文書です、という意味です

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;                         // HTTPステータスコード(1)
  res.setHeader('Content-Type', 'text/html');  // MIME-type(2)
  res.write('<html><body><strong>Hello world</strong></body></html>')
  res.end('');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

WebブラウザはHTML文書として解釈して、Hello worldが強調されていますね。

(2) HTTPヘッダでMIME-typeがtext/plainなのにHTTPボディがHTMLなら...?

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;                         // HTTPステータスコード(1)
  res.setHeader('Content-Type', 'text/plain');  // MIME-type(2)
  res.write('<html><body><strong>Hello world</strong></body></html>')
  res.end('');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

HTML文書であっても、text/plainで送るとWebブラウザはHTML文書とは解釈してくれません。HTTPレスポンス通信のsetHeader()で設定されるHTTPヘッダ情報で、Webブラウザ側の挙動が変わることがこれで理解できると思います。

Content-Typeに指定するMIME-Type

MIME(Multipurpose Internet Mail Extensions) とは、もともと電子メールで異なる形式のデータを扱うために策定されたデータ形式を表現する規格です。現在では、HTTPを含む様々なプロトコルで利用されている。

  • 形式type/subtype (例:text/html , image/png , application/json
  • 目的 :データの種類をクライアントに知らせ、正しく解釈させるため
  • 実例 : HTTPレスポンスのContent-Typeヘッダで指定された形式に基づき、ブラウザがコンテンツを解釈
    • text/html → HTMLとしてレンダリング
    • text/plain → プレーンテキストとして表示
  • 誤ったMIME-Typeの影響
    • HTMLファイルがtext/plainとして送信されると、ソースコードがそのまま表示されてしまう。
    • 画像ファイルがtext/htmlとして送信されると、ブラウザが解釈できずに表示エラーが発生する。
  • よく使われるMIME-Type一覧
    • 📄 一般的な文書形式
      • text/plain:プレーンテキスト(.txt)
      • text/html:HTML文書(.html)
      • text/css:スタイルシート(.css)
      • application/pdf:PDF文書
      • application/msword:Microsoft Word(.doc)
      • application/vnd.openxmlformats-officedocument.wordprocessingml.document:Word(.docx)
    • 🖼️ 画像ファイル
      • image/jpeg:JPEG画像(.jpg, .jpeg)
      • image/png:PNG画像
      • image/gif:GIF画像
      • image/svg+xml:SVGベクター画像
      • image/webp:WebP画像
    • 🎥 音声・動画
      • audio/mpeg:MP3音声
      • audio/ogg:OGG音声
      • video/mp4:MP4動画
      • video/webm:WebM動画
    • 📦 アプリケーションデータ
      • application/json:JSONデータ
      • application/javascript:JavaScriptコード
      • application/zip:ZIPアーカイブ
      • application/x-www-form-urlencoded:フォーム送信のエンコード形式
      • multipart/form-data:ファイルアップロード時のフォーム形式
    • その他
      • application/octet-stream:汎用バイナリデータ
      • application/xml:XML文書

前編のまとめ

HTTP通信

  • テキストベースのプロトコル
  • リクエスト・レスポンス型(クライアントがリクエストし、サーバが応答)
  • ステートレス(個々の通信に状態を持たない)

WWW(Web)の正体

  • HTML、URL、MIME-typeの統合的理解

    1. HTML :文書や情報を構造化するためのマークアップ言語

    2. URL :インターネット上のリソースを特定するための住所

    3. MIME-type :リソースがどの形式であるかを明示するための識別子

  • HTTPにおける役割分担

    • URLでリソースにアクセス
    • HTTPレスポンスヘッダーでMIME-typeを指定
    • ブラウザがHTMLや画像、CSSとして解釈

次回予告

HTTP通信の続編では、フォーム入力とパラメータ解析セッション管理のためのCookie に注目し、HTTPの持つ脆弱性であるセッションハイジャック について深掘りしていきます。

おわりに

  • 本稿では、HTTPの脆弱性の前段として最低限必要なキーワードを集めてWWWの話とした
  • 中学生でもわかるよう、比喩の後、説明し、具体例とコンピュータ上での操作を念頭に構成した
  • ステートレス通信やセッションの概念は、分量が多くなったため、稿を改めることにした
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?