自衛のためのサイバー攻撃の仕組み講座(AI時代・エンジニア水準)
区分3 Webサイトとサーバーを狙う攻撃★★★HTTP は、ブラウザ(またはアプリ)とWebサーバーが話すときの約束事です。 HTTPS は、その会話を暗号で包んだ物です。今の公開サイトは、ほぼ HTTPS です。
会話は、いつも「お願い」と「返事」の1往復でできています。 お願いを リクエスト、返事を レスポンス と呼びます。
食堂の注文票で考えると分かりやすいです。 お客さんが注文票を書いて出し(リクエスト)、厨房が料理を返します(レスポンス)。 厨房は、注文票を出した人の顔を覚えていません。1枚ごとに、初めての注文として扱います。
リクエストは、次の部品でできています。
| 部品 | 何か | 例 |
|---|---|---|
| メソッド | 何をしたいか | GET(見せて)、POST(受け取って) |
| URL | どこの何か。後ろの ? 以降が「パラメータ」 |
/search?q=ことば |
| ヘッダ | 付け足しの情報。ブラウザの種類、Cookie など | Cookie: … |
| ボディ | 送る本体。フォームの入力、アップロードしたファイルなど | 入力欄の中身 |
パラメータは、URLの後ろに付けて送る「項目名=値」の組です。 入力欄に書いた文字は、この形か、ボディに入って届きます。
HTTP は、1往復ごとに完結します。サーバーは前のリクエストを覚えていません。 それなのにログイン状態が続くのは、Cookie の中のセッションIDを毎回見せているからです。
遊園地のリストバンドと同じです。 入口で身分を確かめたら、あとはバンドを見せるだけで乗り物に乗れます。 その代わり、バンドを他人に取られると、取った人がその人として扱われます。
これが No.05 で見た「セッションの盗難」の土台です。パスワードが強くても、印が盗まれれば入られます。
Cookie には、守るための3つの属性(付け足しの設定)があります。
ログイン用のCookieには、この3つを付けるのが基本です。 自分のサイトで見たいときは、ブラウザの開発者ツール(F12)の「アプリケーション」から Cookie の一覧を開くと、属性の列があります。
ブラウザの画面で、ボタンを消す、入力欄の文字数を制限する、といった工夫をしても、守りにはなりません。 リクエストは、ブラウザを通さなくても作れます。道具を使えば、制限のかかっていない値を直接送れるからです。
つまり、サーバーに届いた物は、画面の制限を通っていない可能性があると考えます。 画面側のチェックは、親切のためです。守りは必ずサーバー側でやります。
○ よくある勘違い:「入力欄に文字数制限があるから大丈夫」→ 画面の制限は、サーバーには届きません
○ 関係する単元:No.05 アカウント乗っ取りの仕組み
ブラウザには、あるサイトのページが別のオリジンのデータを勝手に読めないようにする決まりがあります。同一オリジンポリシーといいます。
たとえば、悪いサイトを開いている間に、別タブの銀行のページの中身が読まれてはいけません。この壁があるから、複数のタブを安心して開けます。 ただし、この壁は「読む」ことを止める物です。「送る」ことまでは完全には止めません。だから SameSite など別の守りが要ります。
深追いは要りません。「ブラウザが、サイトごとに壁を作っている」とだけ言えれば足ります。
「入力」というと、フォームの入力欄だけを思い浮かべがちです。 実際にサーバーが受け取るのは、次の全部です。
どれも、送る側が自由に作れます。 LINEやUTAGEからの通知を受けるあなたの仕組みも、同じです。「LINEからの通知のはず」という思い込みは、本物からの通知かどうかの確認に代わりません。
ここからが、この回の核です。 Webの代表的な弱点の多くは、同じ形をしています。
受け取った「ただの文字(データ)」が、どこかで「命令」として解釈されてしまう
| 渡した先 | 本来の役目 | 命令として読まれると |
|---|---|---|
| データベース | 条件に合う行を探す | 意図しない行の読み出し・書き換え(SQLインジェクション) |
| ブラウザのページ | 文字を表示する | 他人のブラウザで悪い JavaScript が動く(クロスサイトスクリプティング、XSS) |
| OSのコマンド | ファイル名として使う | 意図しないコマンドが動く(OSコマンドインジェクション) |
| ファイルのパス | 決まったフォルダの中を探す | 想定外のフォルダのファイルが読まれる(ディレクトリトラバーサル) |
どの行も、仕組みは「データと命令の境目が、文字の並びの中で混ざった」の一言で言えます。 読み上げ機の例で考えると分かりやすいです。「次の文を読み上げて」と頼んだのに、文の中の「やめて」で止まってしまう。命令と本文が同じ文字列に入っているから起きます。
実際に打てる攻撃用の文字列は、この講座では扱いません。 仕組みを説明できて、塞ぎ方を実装できることが目的です。
この考え方は、No.10 で扱うAIの弱点(プロンプトインジェクション。AIが「読んだ文」を命令と取り違える問題)と、そっくりな形です。先の回で見る時にもう一度思い出してください。
自作のコードや、AIに書かせたコードを見るときは、1つだけ確かめます。 外から来た値を、文字をつなげる形で、命令の文に入れていないか。
SQLなら、文字をつないで問い合わせの文を作っている所が危険信号です。 HTMLなら、受け取った値をそのままページに書き出している所です。
AIが書いたコードも、この危険信号を含むことがあります。 コードを渡されたときは「外から来た値をどこで使っているか」を聞くと、確認できます。
根本の対策は、命令の文と値を別々に渡すことです。 SQLでは、これをプレースホルダ(値を入れる穴)を使った書き方といいます。 データベース側が「命令の形」を先に確定させてから、値を後で入れます。値はどんな文字でも、ただの値のままです。
WordPress の PHP なら、次のように書きます。
// 安全な書き方:値の位置を %s(文字)や %d(整数)で示し、後から渡す
$row = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE post_author = %d AND post_status = %s",
$author_id,
$status
)
);
$wpdb->prepare() が、値を安全な形にして穴へ入れます。
一方、"... WHERE post_author = " . $_GET['id'] のように文字をつなぐ書き方は、避けます。
他の言語でも同じ考え方です。「問い合わせの文」と「値」は、別の引数で渡します。 IPA の「安全なウェブサイトの作り方」も、SQLについては、この方法を根本的な解決策に挙げています。
ページに文字を書き出すときは、HTMLで特別な意味を持つ記号を、ただの文字として表示する形に変えます。この処理をエスケープといいます。
// 安全な書き方:出す時点で、場所に合ったエスケープをかける
echo '<p>' . esc_html( $comment_text ) . '</p>';
echo '<a href="' . esc_url( $link ) . '">リンク</a>';
WordPress では、esc_html()(本文)・esc_attr()(タグの属性)・esc_url()(リンク先)が用意されています。
大事なのは、入力された時ではなく、出す時に、出す場所に合わせてかけることです。同じ値でも、本文に出す時と、リンクの中に出す時で、必要な処理が違うからです。
受け取る値の形を確かめることを、入力の検査(バリデーション)といいます。 「郵便番号は数字7桁」「並べ替えは決めた3種類だけ」のように、許す物を先に決めておき、それ以外は断ります。許可リスト方式といいます。
検査だけに頼ると、見落としが出ます。 検査は「想定外を早く断る」ための補助で、混ぜない書き方(①②)が本番の守りです。
もう1つ、保険の対策があります。 データベースに繋ぐユーザーの権限を、必要最小限にしておきます。万一破られても、被害が小さく済みます。
○ 受講生によく聞かれる質問:「WordPress なら自動で守ってくれるんですよね」
→ 答え方:本体は、これらの対策を入れて作られています。ただし、プラグインやテーマ、自作のコードは別です。ここで書き方を間違えると、本体の守りを通り抜けます(No.09)
○ 関係する単元:No.05 アカウント乗っ取りの仕組み、No.08 OWASP Top 10、No.10 プロンプトインジェクション(後で出ます)
サーバーは会話を覚えていない。ログイン状態はCookieの印で持つ。届く物は全部、画面を通っていないかもしれない。弱点の多くは「データが命令として読まれる」こと。塞ぎ方は、命令と値を分けて渡し、出す時にエスケープする。
問1 入力欄に「最大20文字」と画面側で制限をかけたサイトがあります。これだけで、長すぎる値を防げていると言えますか?
問2 Webの代表的な弱点(SQLインジェクション、XSS など)に共通する形として、正しいのはどれですか?
問3 WordPress のプラグインを自作して、記事の投稿者IDで検索したい。安全な書き方はどれですか?
出典:IPA「安全なウェブサイトの作り方」改訂第7版(https://www.ipa.go.jp/security/vuln/websecurity/about.html)/MDN「同一オリジンポリシー」(https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy)/MDN「HTTP Cookie の使用」(https://developer.mozilla.org/ja/docs/Web/HTTP/Guides/Cookies)/OWASP「SQL Injection Prevention Cheat Sheet」(https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)/WordPress 公式「Escaping Data」(https://developer.wordpress.org/apis/security/escaping/)