ホストヘッダインジェクション攻撃について
ホストヘッダインジェクション(Host Header Injection)攻撃は、HTTPリクエストのHost
ヘッダーが適切に検証されていない場合に発生する攻撃です。多くのWebアプリケーションやサーバーは、Host
ヘッダーの値をもとに動作を決定するため、攻撃者はこのヘッダーを悪意を持って操作することで、認証バイパス、キャッシュポイズニング、Webキャッシュ欺瞞(Web Cache Deception)、オープンリダイレクトなどの攻撃を実行できます。
脆弱なコード例:
<?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");
?>
攻撃手法:
攻撃者が以下のようにリクエストを送信します。
GET / HTTP/1.1
Host: evil.com
$_SERVER['HTTP_HOST']
がevil.com
になるため、攻撃者が送信したメールの中に悪意のあるリンクが含まれることになります。
Click here to reset your password: http://evil.com/reset-password.php?user=admin
被害者がこのリンクをクリックすると、攻撃者が用意したページに誘導され、フィッシングやその他の攻撃が可能となります。
脆弱なコード例:
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()
攻撃手法:
攻撃者が以下のようにリクエストを送信します。
GET /reset-password HTTP/1.1
Host: evil.com
request.host
がevil.com
になるため、返されるリンクにevil.com
が含まれることになります。
<a href="http://evil.com/reset-password?token=abc123">Reset your password</a>
ユーザーがこのリンクをクリックすると、攻撃者が用意したページに誘導され、さらなる攻撃が可能になります。
脆弱なコード例:
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);
攻撃手法:
攻撃者が以下のようにリクエストを送信します。
GET /reset-password HTTP/1.1
Host: evil.com
req.headers.host
がevil.com
になるため、レスポンスに含まれるリンクが不正なホストを含むようになります。
<a href="http://evil.com/reset-password?token=abc123">Reset your password</a>
脆弱なコード例:
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>";
}
}
攻撃手法:
攻撃者が以下のようにリクエストを送信します。
GET /reset-password HTTP/1.1
Host: evil.com
@RequestHeader("Host")
によって取得されるホストがevil.com
になるため、生成されるURLもevil.com
を含むものになります。
<a href="http://evil.com/reset-password?token=abc123">Reset your password</a>
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>";
}
まとめ:
ホストヘッダインジェクション攻撃は、WebアプリケーションがHTTPリクエストのHost
ヘッダーを適切に検証しない場合に発生する危険な攻撃です。攻撃者は、この脆弱性を利用して、オープンリダイレクトやフィッシング、Webキャッシュのポイズニングなどを行うことができます。ホストヘッダーの検証、相対URLの使用、プロキシ設定の確認などの防止策を講じることで、この脆弱性を効果的に防ぐことが可能です。