こんにちは!Web開発やインフラの管理、毎日本当にお疲れ様です。
新米のIT担当者として奮闘している方や、これからセキュリティの勉強を始めようとしている方にとって、ネットの海には難しい用語があふれていて、頭が痛くなりますよね。
「なんだかよく分からないけれど、サーバーのセキュリティ対策をしないといけない……」
そんなあなたに向けて、今回は最近のサイバー攻撃でよく狙われる「SSRF(サーバーサイドリクエストフォージェリ)」という攻撃について、身近な防犯の例えを交えながら、一歩ずつ優しく紐解いていきたいと思います。
専門用語はなるべく噛み砕いてお話ししますので、美味しいコーヒーでも飲みながら、リラックスして読んでいってくださいね!
—
1. 家の鍵と泥棒に例える「SSRF(サーバーサイドリクエストフォージェリ)」の正体
まずは、難しそうな名前の「SSRF」が一体どんなものなのか、私たちの身近な「お家と宅配便」に例えて考えてみましょう。
皆さんのご自宅には、頑丈な玄関の鍵がありますよね。外からの泥棒が勝手に入ってこないように、鍵をしっかり閉めているはずです。
では、あなたが「ネット通販で買った大きな家具」を受け取る場面を想像してください。あなたは自宅にいながら、宅配業者さんに「〇〇の倉庫にある荷物をうちまで持ってきてください」と電話で依頼しますよね。
さて、もしここに「悪意を持った偽の宅配業者」がいたらどうなるでしょうか?
泥棒があなたの家のインターホンを鳴らし、こう言いました。
「すみません、ご近所の警察署(あるいは、あなたの家の金庫室)の裏口から、特別な荷物を勝手に持ってきてくれませんか?」
もし、あなたの家(サーバー)がとても親切で、「頼まれたものなら、何でも外に行って取ってきてあげるよ!」という性格だったらどうでしょう?
サーバーは疑うことを知らず、あなたの代わりに警察署の裏口や金庫室へ行き、本来なら絶対に一般人が見られないはずの秘密の書類(クラウドの重要データ)を持ち帰り、泥棒に渡しちゃうかもしれないのです。
これが、SSRF(サーバーサイドリクエストフォージェリ)の仕組みです。
「サーバー(代理人)に、意図しない裏側の場所へリクエスト(お使い)に行かせてしまう攻撃」という意味なんですね。
—
2. クラウドの「合鍵(メタデータ)」が狙われる理由
最近のシステムは、AWSやGoogle Cloudといった「クラウドサービス」の上で動いていることが多いですよね。
これらのクラウド環境には、「インスタンスメタデータサービス(IMDS)」という、サーバー自身の設定や管理者情報が詰まった特別な「秘密の小部屋(URL)」が用意されています。
例えば、AWSの場合、サーバーの中から http://169.254.169.254/latest/meta-data/ という特別な住所にアクセスすると、そのサーバーを管理するための強力な「合鍵(一時的なアクセスキー)」が簡単に手に入ってしまいます。
本来、この小部屋に入れるのは「サーバーの中の人」だけのはずです。しかし、アプリにSSRFの弱点(脆弱性)があると、外にいる攻撃者がアプリを踏み台にして、このクラウドの秘密の小部屋へこっそり侵入できてしまうのです。
—
3. 実際のコードで見る「危ないプログラム」と「安全なプログラム」
それでは、開発の現場でどんなコードが危なくて、どう直せばいいのかを具体的に見ていきましょう。
ここではよく使われるPHPを例に挙げてみますね。
【危ないコード例】
ユーザーが入力したURLを、そのままサーバーがフェッチ(取得)してしまう機能があるとします。
<?>
// ユーザーが入力したURLをそのまま受け取る(危険!)
$target_url = $_GET['url'];
// サーバーが自らそのURLへアクセスしに行ってしまう
$response = file_get_contents($target_url);
// 結果を表示する
echo "取得結果: " . htmlspecialchars($response, ENT_QUOTES, 'UTF-8');
?>
このコードの何が問題か分かりますか?
もしユーザーが url パラメータに http://169.254.169.254/latest/meta-data/ なんて入力してアクセスしたら、サーバーは素直にそれを読みに行ってしまい、クラウドの秘密情報を外に漏らしてしまうのです。
【安全なコード例:ホワイトリスト方式を取り入れよう】
「うちのサーバーは、決まった安全な場所(例えば自社の画像サーバーなど)にしかお使いに行きません!」というルール(ホワイトリスト)を決めましょう。
<?>
// ユーザーからの入力をそのまま信用せず、許可されたドメインのリストを作る
$allowed_domains = ['api.example.com', 'images.example.com'];
$target_url = $_GET['url'];
$parsed_url = parse_url($target_url);
// ホスト名が許可リストに含まれているかチェックする
if (isset($parsed_url['host']) && in_array($parsed_url['host'], $allowed_domains, true)) {
// 安全が確認できた場合のみアクセスを実行
$response = file_get_contents($target_url);
echo "取得結果: " . htmlspecialchars($response, ENT_QUOTES, 'UTF-8');
} else {
// 許可されていない宛先の場合はエラーにする
http_response_code(403);
echo "エラー: そのURLへのアクセスは許可されていません。";
}
?>
このように、「誰の言うことでも聞く」のではなく、「あらかじめ決めた安全な相手の言うことしか聞かない」というガードを一枚挟むだけで、SSRFのリスクをぐっと減らすことができます。
—
4. クラウド側の防御策:IMDSv2で「合鍵」の持ち出しを防ぐ
アプリケーションのコードだけでなく、インフラ(クラウド)側でもしっかり守りを固める必要があります。
例えばAWSでは、従来の「IMDSv1」から、より安全な「IMDSv2」への移行が推奨されています。
IMDSv2では、メタデータにアクセスする際に「トークン(特殊な通行手形)」を事前に発行させ、その手形がないと中の情報を覗けない仕組みになっています。
悪意あるユーザーが単純なSSRFの技を使っても、この「通行手形」をうまく奪うことができないため、クラウドの秘密を守り抜くことができるのです。
インフラを構築する際は、Terraformなどの設定ファイルで以下のようにIMDSv2を強制する設定を入れておきましょう。
# AWS EC2インスタンスの設定例
resource "aws_instance" "secure_server" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
# メタデータサービスのセキュリティ設定を強制する
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # 「required」にすることでIMDSv2を強制!
http_put_response_hop_limit = 1 # ルーターを跨いだアクセスを禁止
}
}
この http_tokens = "required" という設定が、まるで「合鍵を作るのに本人確認書類を必須にする」ような強力な防犯ロックの役割を果たしてくれます。
—
一歩ずつ、確実なセキュリティ対策を
今回は、サーバーサイドリクエストフォージェリ(SSRF)の仕組みと、その防ぎ方についてお話ししました。
- サーバーに勝手なお使いをさせない(ユーザー入力をそのままURLに使わない)
- 行先をホワイトリストで厳しく制限する
- クラウドのメタデータサービスにはIMDSv2で鍵をかける
最初は覚えることが多くて大変に感じるかもしれませんが、セキュリティの基本は「疑うこと」と「ルールをきっちり決めること」の繰り返しです。
日々の開発やインフラ設定の中で、少しずつこの意識を取り入れていけば、あなたの作るシステムは確実に鉄壁に近づいていきますよ。
焦らず、一歩ずつ安全なエンジニアへの階段を登っていきましょう!応援しています!
コメント