【入門編】 OWASP Top 10:2021 A10:2021-Server-Side Request Forgery (SSRF)の防御 – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

こんにちは!セキュリティの世界へようこそ。
新人のIT担当者や、これからセキュリティの勉強を始める開発者の皆さん、日々の開発やお疲れ様です。

「セキュリティ」と聞くと、なんだか難解な暗号や、見たこともない黒い画面(CUI)を思い浮かべて身構えてしまいますよね。でも大丈夫です。セキュリティの基本は、私たちが普段暮らしている現実世界の「防犯」と全く同じなんです。

今回は、OWASP Top 10(Webアプリの脆弱性ランキング)の常連であり、クラウド環境において非常に恐ろしい被害をもたらす SSRF(Server-Side Request Forgery:サーバーサイド要求偽造) について、身近な例えを交えながら、優しく一歩ずつ紐解いていきましょう!

—

1. SSRFってなに? 家の鍵と「パシリ」に例えてみよう

まずは、SSRFという攻撃がどんなものか、私たちの日常に置き換えて考えてみましょう。

皆さんが住んでいるマンションを想像してください。そのマンションには、住人だけが知っている「超重要なお知らせ(金庫の暗証番号や住民の秘密データ)」が書かれた管理人室があるとします。この管理人室は、外部の怪しい人は絶対に中に入れません。

しかし、このマンションには「外からの頼まれごとを受けて、管理人室に書類を取りに行ってくれる、ちょっとお人好しな管理人さん(Webサーバー)」がいます。

ここに、外から悪い泥棒がやってきて、お人好しな管理人さんにこう言いました。
「ねえねえ、あそこの棚にある『秘密の書類(クラウドのメタデータ)』を取ってきてよ!」

お人好しな管理人さんは、頼まれた相手が泥棒だとは気づかずに、管理人室からその秘密の書類を持ち出して、泥棒に渡しちゃいました……。これが、SSRF(サーバーサイド要求偽造)の仕組みです。

Webアプリケーション(管理人さん)が、攻撃者(泥棒)に言われるがまま、本来外部に見せてはいけない内部のシステム(管理人室)にアクセスしてしまい、その結果を攻撃者にペロッと漏らしてしまう脆弱性を指します。

—

2. なぜクラウドだと大惨事になるのか?(メタデータの恐怖)

現代のWebシステムは、AWSやGoogle Cloud、Microsoft Azureといった「クラウド環境」の上で動いていることがほとんどですよね。

クラウドの世界には、そのサーバー自体の大切な設定情報や、一時的な「合鍵(アクセスキー)」をこっそり教えてくれる特別な住所(メタデータサービス)が存在します。たとえば、AWSではお馴染みの http://169.254.169.254/ というIPアドレスがそれにあたります。

もし、あなたが作ったWebアプリ(お人好しな管理人さん)にSSRFの穴があると、攻撃者は次のようなリクエストをアプリに送りつけます。

> 「おい、うちのサーバーの合鍵(一時クレデンシャル)の場所を教えてくれ!」

アプリがこの命令を真面目に実行してしまうと、クラウドの最高権限の合鍵が攻撃者の手に渡り、サーバー全体が乗っ取られてしまうというわけです。恐ろしいですよね……!

—

3. SSRFを防ぐための「3つの鉄則」

それでは、この厄介なSSRFから私たちのシステムを守るにはどうすればよいでしょうか?現場で使える具体的な防犯対策を3つ見ていきましょう。

鉄則1:ユーザーからの入力をそのまま信用しない(URLのホワイトリスト化)

一番やってはいけないのは、ユーザーがフォームに入力したURL(例: https://example.com/image?url=入力値)を、そのままサーバー側でアクセスしに行ってしまう実装です。

「外部の画像を取りに行きたい」という場合でも、アクセスして良いドメインを厳格に制限(ホワイトリスト化)しましょう。

鉄則2:クラウドのメタデータへのアクセスを遮断する

これが一番確実で強力な防御です。外部からのリクエストを処理するWebサーバーが、内部の特殊なアドレス(AWSの 169.254.169.254 など)に勝手にアクセスできないよう、ネットワークやアプリケーション層で遮断します。

鉄則3:最新のIMDSv2(AWSの場合)を利用する

AWSを例に挙げると、古いバージョンのメタデータサービス(IMDSv1)は、単純なSSRFのコマンドで簡単に情報を盗まれてしまいました。しかし、現在の標準である IMDSv2 では、セッショントークン(合鍵を取りに行くための事前パスワードのようなもの)が必要になるため、単純なSSRF攻撃では情報を盗み出せないようになっています。

—

4. 実装コードで見る!安全なURL取得の書き方

それでは、実際にPHPを使った簡単なコード例で、どうやって身を守ればいいのかを見てみましょう。

以下のコードは、「ユーザーが入力したURLにサーバーがアクセスする機能」を作ったときのものです。NGな例とOKな例を比較してみましょう。

【危ない実装例(NG)】

<?php
// ユーザーが入力したURLをそのまま取得してしまう(危険!)
$user_url = $_GET['url'];

// 泥棒に言われるがまま、どこへでもアクセスしに行ってしまう
$response = file_get_contents($user_url);

echo "取得したデータ: " . $response;
?>

この書き方だと、$user_url に http://169.254.169.254/latest/meta-data/ を入れられてしまった場合、クラウドの秘密情報が丸見えになってしまいます。

—

【安全な実装例(OK:ホワイトリスト検証)】

<?php
// 1. ユーザーから送られてきたURLを取得する
$user_url = $_GET['url'] ?? '';

// 2. アクセスを許可するドメインのリスト(ホワイトリスト)を定義する
$allowed_domains = [
    'images.example.com',
    'cdn.example.org'
];

// 3. 入力されたURLのホスト名(ドメイン部分)を安全に抽出する
$parsed_url = parse_url($user_url);
$host = $parsed_url['host'] ?? '';

// 4. ホワイトリストに含まれているドメインかどうかを厳格にチェックする
if (!in_array($host, $allowed_domains, true)) {
    // 許可されていないドメインの場合は処理を中断!
    http_response_code(400);
    exit("エラー: このURLへのアクセスは許可されていません。");
}

// 5. チェックを通過した安全なURLのみアクセスを許可する
// ※ さらに、プライベートIPアドレス(ローカルIP)へのアクセスではないかのチェックも行うと完璧です!
$response = file_get_contents($user_url);

echo "安全に取得したデータ: " . $response;
?>

このように、「誰からのどんな頼みごとであっても、行く場所が安全リストに載っているか必ずチェックする」というルールをコードに組み込んでおくことが、現場でエンジニアが実践すべき最高の防犯対策になります。

—

5. さいごに

今回はSSRFという少し聞き慣れない脆弱性と、その防御策についてお話ししました。

セキュリティの対策は、一度覚えてしまえば日々のコーディングの習慣になります。「この入力値は、サーバーに別の場所へお使いを頼ませてしまう危険はないかな?」と、一歩立ち止まって疑うクセ(セキュリティ・マインドセット)を少しずつ育てていきましょう。

一歩ずつ、確実に安全なシステムを作れるエンジニアになっていきましょうね!それではまた次回の記事でお会いしましょう。

コメント

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