【入門編】 ファイルアップロード脆弱性とWebシェル実行 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

ファイルアップロードの落とし穴:あなたのサーバーに「泥棒の合鍵」を作らせないために

こんにちは!今日は、Webサイトの「ファイルアップロード機能」という、便利だけど実はとっても危険な「裏口」についてお話しします。

「ユーザーが写真をアップロードできる機能を作っただけなのに、なぜかサーバーが乗っ取られた…」なんて悪夢のような話、実は珍しくありません。なぜそんなことが起きるのか、泥棒と家の鍵に例えて紐解いていきましょう!

—

1. そもそも、何が起きているのか?(泥棒の侵入経路)

想像してみてください。あなたは自分の家に「郵便受け」を作りました。ここには、郵便屋さんが手紙(画像ファイル)を投げ入れてくれます。

しかし、もし泥棒が「手紙です」と言って、「手紙のフリをした『合鍵作成ロボット』」を郵便受けに放り込んだらどうなるでしょう? そのロボットが郵便受けの中で勝手に動き出し、玄関のドアを開けてしまったら……これが「Webシェル」による攻撃の正体です。

攻撃者は、サーバーが「これはただの画像だ」と信じ込んでいる隙に、サーバーを自由に操るための小さなプログラム(Webシェル)を忍び込ませるのです。

—

2. なぜチェックをすり抜けてしまうのか?

多くの開発者は、アップロード機能に制限をかけます。たとえば「.jpg ファイルしか受け付けない」といったルールです。でも、泥棒はここを巧みに突いてきます。

よくある「甘いチェック」の盲点

  • 拡張子チェックの回避: 攻撃者は shell.php.jpg のような名前でファイルを送ります。サーバーが「最後に .jpg がついてるからOK!」と判断すると、そのファイルが実行可能な環境に置かれた瞬間、PHPとして動いてしまうことがあります。
  • MIMEタイプの偽装: ブラウザが送ってくる「これは画像です(image/jpeg)」という自己申告を、サーバーがそのまま鵜呑みにしているケースです。泥棒に「私はただの旅行者です」と自己申告させて、身分証も見ずに家に入れるようなものですね。

—

3. 防御の第一歩:鉄壁の守りを固める

では、どうすれば防げるのでしょうか? 「一歩ずつ対策を学んでいきましょう!」

対策①:ファイルの「中身」を確認する

拡張子や自己申告を信じてはいけません。サーバー側で、画像ファイルのヘッダー情報を読み取り、本当に画像データかどうかを検証します。

<?php
// アップロードされたファイルが本当に画像かチェックする例
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['upload_file']['tmp_name']);

// 許可するMIMEタイプ以外は即座に拒否!
$allowed_types = ['image/jpeg', 'image/png'];
if (!in_array($mime, $allowed_types)) {
    die("不正なファイル形式です!");
}
finfo_close($finfo);
?>

対策②:保存場所と実行権限を切り離す

最も強力な対策の一つです。アップロードされたファイルを保存するディレクトリでは、「スクリプトの実行を禁止」する設定をサーバー側(Apacheなど)で行います。

.htaccess という設定ファイルを保存先ディレクトリに置くことで、泥棒がロボットを送り込んでも「動かさない」ようにできます。

# このディレクトリ内ではPHPなどのスクリプトを実行させない
<FilesMatch "\.(php|php5|phtml|cgi|pl)$">
    Order Deny,Allow
    Deny from all
</FilesMatch>

—

4. セキュリティヘッダーで「泥棒を追い出す」

最後に、Webサーバーがブラウザに「このファイルはただの画像として扱え!」と命令するヘッダーを設定しましょう。これがないと、ブラウザが勝手に「おっ、これプログラムっぽいな、実行しちゃおうかな」と勘違いして、被害を拡大させる可能性があります。

  • X-Content-Type-Options: nosniff: これを付けると、ブラウザが勝手にファイルの中身を推測して実行するのを防げます。「書いてある通りに扱え!」と強く伝える命令です。

—

最後に:完璧な防御なんてないからこそ

セキュリティの世界に「100%安全」はありません。でも、「泥棒が侵入するコストを極限まで引き上げる」ことはできます。

1. ユーザーの入力を絶対に信用しない
2. 実行権限を最小限に絞る
3. 保存場所とプログラムの場所を分ける

この基本を守るだけで、あなたのWebサイトはずっと堅牢になります。難しそうに見えても、一つずつ設定を積み重ねていけば大丈夫です!

もし「こんな機能を作っているけど、これで本当に大丈夫?」と不安になったら、いつでもまた聞きに来てくださいね。一緒に安全なコードを育てていきましょう!

コメント

タイトルとURLをコピーしました