【入門編】 サーバーサイドリクエストフォージェリ(SSRF)のAPI悪用 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!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で鍵をかける

最初は覚えることが多くて大変に感じるかもしれませんが、セキュリティの基本は「疑うこと」と「ルールをきっちり決めること」の繰り返しです。
日々の開発やインフラ設定の中で、少しずつこの意識を取り入れていけば、あなたの作るシステムは確実に鉄壁に近づいていきますよ。

焦らず、一歩ずつ安全なエンジニアへの階段を登っていきましょう!応援しています!

コメント

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