「ファイルをアップロードしてね!」という入り口が、実は一番の落とし穴?
こんにちは。セキュリティの世界で泥臭いインシデント対応を続けていると、つくづく思うことがあります。「最強のセキュリティ対策は、最強のエンジニアが書く完璧なコードよりも、『性悪説』に基づいた疑い深い設計にある」ということです。
今日は、Webサイトでよく見かける「ファイルアップロード機能」についてお話しします。プロフィール画像やレポート提出など、便利な機能ですよね。でも、実はここ、攻撃者にとっては「あなたの家の玄関ドアの隙間に、時限爆弾を置く」のと同じくらい魅力的なスポットなんです。
一歩ずつ、防犯の仕組みを学びながら対策していきましょう!
—
攻撃者は「あなたのサーバーを乗っ取ろう」としている
想像してみてください。あなたのWebサーバーを「自分の家」だとします。アップロード機能は「郵便受け」です。
本来、郵便受けには「手紙」だけを入れてほしいですよね? でも、もし悪意のある人が、手紙のフリをして「爆弾」や「合鍵を作るための型」を放り込んできたらどうでしょう。
攻撃者は、アップロード機能を使って「Webシェル」と呼ばれる、サーバーを遠隔操作するためのプログラムを送り込もうとします。これが成功すると、サーバー内の顧客情報を盗んだり、サイトを改ざんしたりと、やりたい放題になってしまいます。
—
防御の鉄則:4つの「鍵」をかけよう
「ファイル名が `photo.jpg` だから安全だ」なんて、絶対に思わないでくださいね。攻撃者はファイルの中身を偽装するのがプロです。以下の4つのステップでガードを固めましょう。
1. 「見た目」に騙されない(MIMEタイプ検証)
ファイルには「私は画像ですよ」という自己紹介(MIMEタイプ)がありますが、これは簡単に書き換えられます。サーバー側で「中身が本当に画像か?」を厳密にチェックしましょう。
2. 「拡張子」という名の看板を信じない
`malicious.php.jpg` というファイルが送られてきたらどうしますか? 拡張子が2つあると、サーバーの設定次第では「あ、これPHP(プログラム)だ!」と勘違いして実行してしまうことがあります。ブラックリスト(`.php`を禁止する)ではなく、ホワイトリスト(`.jpg`, `.png`のみ許可する)方式を採用しましょう。
3. ファイル名は「匿名」にする
アップロードされたファイルをそのまま保存すると、攻撃者に「どこに保存されたか」を特定されます。また、ファイル名に特殊文字が含まれていると、システムが誤作動を起こす原因にもなります。
4. 「実行権限」を剥奪する
これが最も強力な防犯対策です。保存先のディレクトリには、決して「プログラムとして実行する」という権限を与えないでください。
—
実装のヒント:安全なコードの書き方(概念モデル)
PHPを例に、少しだけコードで見てみましょう。
// 1. アップロードされたファイルが本当に画像かチェック
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES[‘userfile’][‘tmp_name’]);
$allowed_types = [‘image/jpeg’, ‘image/png’];
if (!in_array($mime, $allowed_types)) {
die(“許可されていないファイルタイプです!”);
}
// 2. ファイル名をハッシュ値(ランダムな文字列)に書き換える
// 元のファイル名を捨てて、自分たちで名前を付け直すのがコツ!
$extension = pathinfo($_FILES[‘userfile’][‘name’], PATHINFO_EXTENSION);
$new_filename = bin2hex(random_bytes(16)) . ‘.’ . $extension;
// 3. 安全な場所に保存する
move_uploaded_file($_FILES[‘userfile’][‘tmp_name’], ‘/var/www/uploads/’ . $new_filename);
—
インフラレベルでの防犯:Apache/Nginxの設定
コードだけでなく、サーバーの設定でも蓋をしましょう。アップロード先ディレクトリでプログラムが動かないようにする設定です。
Apacheの場合(.htaccess):
このディレクトリ内のすべての実行を無効化する
php_flag engine off
RemoveHandler .php .phtml .php3
RemoveType .php .phtml .php3
Nginxの場合(設定ファイル内):
location /uploads/ {
# PHPなどの実行を許可しない設定
location ~ \.php$ {
deny all;
}
}
—
最後に:セキュリティは「疑うこと」から始まる
ここまで読んで、「なんだか難しそう…」と感じたかもしれません。でも大丈夫です。大切なのは、「ユーザーが送ってくるファイルは、すべて汚染されている可能性がある」という前提に立つことです。
この「疑う」という姿勢こそが、あなた自身と、あなたが守るサービスを強くする最高の防具になります。
まずは、自分の開発しているシステムのアップロード機能が「どこに保存されているか」「実行権限がどうなっているか」を確認することから始めてみてください。それが、最強のセキュリティへの第一歩ですよ!
また次回の記事で、より深い「現場の泥臭い話」でお会いしましょう!

コメント