WebVulnerabilities

ホストヘッダインジェクション攻撃について

概要

ホストヘッダインジェクション(Host Header Injection)攻撃は、HTTPリクエストのHostヘッダーが適切に検証されていない場合に発生する攻撃です。多くのWebアプリケーションやサーバーは、Hostヘッダーの値をもとに動作を決定するため、攻撃者はこのヘッダーを悪意を持って操作することで、認証バイパス、キャッシュポイズニング、Webキャッシュ欺瞞(Web Cache Deception)、オープンリダイレクトなどの攻撃を実行できます。

脆弱性を持つコードの例と攻撃手法

PHP

脆弱なコード例:

<?php
$host = $_SERVER['HTTP_HOST'];
$url = "http://$host/reset-password.php?user=admin";
mail('admin@example.com', 'Password reset', "Click here to reset your password: $url");
?>

攻撃手法:

Python(Flask)

脆弱なコード例:

from flask import Flask, request

app = Flask(__name__)

@app.route('/reset-password')
def reset_password():
    host = request.host
    url = f'http://{host}/reset-password?token=abc123'
    return f'<a href="{url}">Reset your password</a>'

if __name__ == '__main__':
    app.run()

攻撃手法:

Node.js(Express)

脆弱なコード例:

const express = require('express');
const app = express();

app.get('/reset-password', (req, res) => {
    const host = req.headers.host;
    const url = `http://${host}/reset-password?token=abc123`;
    res.send(`<a href="${url}">Reset your password</a>`);
});

app.listen(3000);

攻撃手法:

Java(Spring Boot)

脆弱なコード例:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ResetPasswordController {

    @GetMapping("/reset-password")
    public String resetPassword(@RequestHeader("Host") String host) {
        String url = "http://" + host + "/reset-password?token=abc123";
        return "<a href=\"" + url + "\">Reset your password</a>";
    }
}

攻撃手法:


防止策

  1. ホストヘッダーの検証:
    • ホストヘッダーの値をホワイトリストに基づいて検証し、信頼できるドメインのみを許可します。

    PHPの例:

    $allowed_hosts = ['example.com', 'www.example.com'];
    if (!in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
        die('Invalid host');
    }
    

    Python(Flask)の例:

    allowed_hosts = ['example.com', 'www.example.com']
    if request.host not in allowed_hosts:
        abort(400, 'Invalid host')
    

    Node.jsの例:

    const allowedHosts = ['example.com', 'www.example.com'];
    if (!allowedHosts.includes(req.headers.host)) {
        return res.status(400).send('Invalid host');
    }
    

    Java(Spring Boot)の例:

    @GetMapping("/reset-password")
    public String resetPassword(@RequestHeader("Host") String host) {
        if (!host.equals("example.com") && !host.equals("www.example.com")) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid host");
        }
        String url = "http://" + host + "/reset-password?token=abc123";
        return "<a href=\"" + url + "\">Reset your password</a>";
    }
    
  2. 絶対URLの使用を避ける:
    • 必要でない限り、絶対URLではなく相対URLを使用することで、ホストヘッダーの影響を最小限に抑えることができます。
  3. プロキシやロードバランサの設定確認:
    • Webサーバーがプロキシやロードバランサの後ろに配置されている場合、正しいホスト情報が渡されているかを確認し、信頼できるヘッダーのみを処理するように設定します。
  4. セキュリティテストの実施:
    • Webアプリケーションに対してホストヘッダインジェクションが発生しないか、定期的にセキュリティテストを実施して確認します。

まとめ: ホストヘッダインジェクション攻撃は、WebアプリケーションがHTTPリクエストのHostヘッダーを適切に検証しない場合に発生する危険な攻撃です。攻撃者は、この脆弱性を利用して、オープンリダイレクトやフィッシング、Webキャッシュのポイズニングなどを行うことができます。ホストヘッダーの検証、相対URLの使用、プロキシ設定の確認などの防止策を講じることで、この脆弱性を効果的に防ぐことが可能です。