CRLFインジェクション攻撃について
CRLFインジェクション攻撃とは、Webアプリケーションにおいて、ユーザーが入力したデータがHTTPレスポンスヘッダーや他のプロトコルのヘッダーにそのまま挿入される場合に発生する攻撃です。CRLFは、キャリッジリターン(\r
)とラインフィード(\n
)のことで、HTTPヘッダーを終了し、新しいヘッダーやボディを開始するために使われます。この攻撃により、攻撃者は任意のヘッダーを挿入したり、レスポンスのボディを改ざんすることができます。これにより、XSS(クロスサイトスクリプティング)やHTTPレスポンススプリッティングなどの攻撃が実行可能となります。
脆弱なコード例:
<?php
$user = $_GET['user'];
header("Location: /welcome.php?user=" . $user);
?>
攻撃手法:
攻撃者が以下のようなリクエストを送信することで、HTTPレスポンスヘッダーを改ざんすることができます。
http://example.com/vulnerable.php?user=John%0d%0aSet-Cookie:%20malicious=1
このリクエストにより、Set-Cookie
ヘッダーがレスポンスに追加され、クライアントに不正なクッキーが設定されます。
header()
関数に渡される入力があまり厳密に検証されておらず、ユーザー入力をそのままHTTPヘッダーに挿入すると、CRLFインジェクションが発生しやすい状況でした。header()
関数を悪用して、HTTPレスポンスヘッダーを改ざんすることが可能でした。<?php
$user = $_GET['user'];
header("Location: /home.php?user=" . $user);
?>
user
パラメータに改行コード(%0d%0a
)を挿入することで、HTTPヘッダーに追加のヘッダーを注入することが可能です。header()
関数が入力に改行コード(\r
や\n
)を含むことを許可しないように改善されました。具体的には、ヘッダーに改行が含まれる場合、PHPが自動的に例外をスローし、攻撃を防ぐようになりました。<?php
$user = $_GET['user'];
// PHP 5.1.2以降では、次のコードが改行を含む場合にエラーを発生させます。
header("Location: /home.php?user=" . $user);
?>
user
パラメータに%0d%0a
が含まれていると、PHPがエラーをスローし、インジェクションを防ぎます。header()
関数でCRLFが検出された場合、PHPは警告を出し、そのヘッダーを送信しません。<?php
$user = $_GET['user'];
header("Location: /home.php?user=" . $user);
?>
user
に改行コードが含まれている場合、エラーが発生し、レスポンスが正しく処理されないようにしています。脆弱なコード例:
from flask import Flask, request, redirect
app = Flask(__name__)
@app.route('/redirect')
def redirect_user():
user = request.args.get('user')
return redirect(f'/welcome?user={user}')
if __name__ == '__main__':
app.run()
攻撃手法:
攻撃者が以下のようなURLを使用して、レスポンスヘッダーを改ざんします。
http://localhost:5000/redirect?user=John%0D%0AContent-Length:%200
この攻撃により、レスポンスが分割され、不正な内容が挿入される可能性があります。
Pythonの標準ライブラリ自体には、HTTPヘッダーの生成や操作に特化した関数は含まれていません。代わりに、http.client
モジュール(Python 3.x)やhttplib
モジュール(Python 2.x)を使用して、HTTPリクエストを作成したり、ヘッダーを操作することができます。CRLFインジェクションに関しては、Pythonの標準ライブラリ自体にバージョンによる大きな差異はありません。
httplib
モジュールを使用して、HTTPリクエストを生成します。CRLFインジェクションを防ぐためのバリデーションは標準で提供されていないため、開発者が入力をサニタイズする必要があります。http.client
モジュールを使用します。Python 3.xでは、HTTPヘッダーを操作する際に、改行文字(\r
や\n
)がヘッダーに含まれていると例外が発生するようになっています。これにより、CRLFインジェクションのリスクは軽減されています。PythonでWebアプリケーションを構築する際には、FlaskやDjangoなどのWebフレームワークを使用することが一般的です。これらのフレームワークでは、ユーザー入力を適切にサニタイズしないと、CRLFインジェクションのリスクがあります。
脆弱なコード例:
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route('/set_header')
def set_header():
user = request.args.get('user')
response = make_response("Setting header")
response.headers['X-User'] = user
return response
攻撃手法:
user
パラメータを送信することで、ヘッダーに不正なデータを注入する可能性があります。http://example.com/set_header?user=admin%0d%0aX-Attack:1
http.client
モジュールが改行を含むヘッダーに対して例外を発生させるため、Flaskアプリケーションが例外を処理しない限り、この攻撃は失敗します。脆弱なコード例:
from django.http import HttpResponse
def set_header(request):
user = request.GET.get('user', '')
response = HttpResponse("Setting header")
response['X-User'] = user
return response
攻撃手法:
http://example.com/set_header?user=admin%0d%0aX-Attack:1
脆弱なコード例:
const express = require('express');
const app = express();
app.get('/redirect', (req, res) => {
const user = req.query.user;
res.setHeader('Location', `/welcome?user=${user}`);
res.status(302).end();
});
app.listen(3000);
攻撃手法:
攻撃者は以下のURLを使用して、レスポンスヘッダーを改ざんします。
http://localhost:3000/redirect?user=John%0d%0aContent-Length:%200
これにより、HTTPレスポンスヘッダーが改ざんされ、予期しない動作を引き起こす可能性があります。
脆弱なコード例:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletResponse;
@Controller
public class RedirectController {
@GetMapping("/redirect")
public void redirectUser(@RequestParam String user, HttpServletResponse response) {
response.setHeader("Location", "/welcome?user=" + user);
response.setStatus(HttpServletResponse.SC_FOUND);
}
}
攻撃手法:
攻撃者が以下のようにリクエストを送信して、レスポンスヘッダーを改ざんします。
http://localhost:8080/redirect?user=John%0D%0ASet-Cookie:%20malicious=1
これにより、Set-Cookie
ヘッダーが追加され、不正なクッキーが設定されます。
\r
と\n
)をエスケープまたは削除します。PHPの例:
$user = str_replace(["\r", "\n"], '', $_GET['user']);
header("Location: /welcome.php?user=" . $user);
Python(Flask)の例:
from flask import Flask, request, redirect
import re
app = Flask(__name__)
@app.route('/redirect')
def redirect_user():
user = re.sub(r'[\r\n]', '', request.args.get('user'))
return redirect(f'/welcome?user={user}')
if __name__ == '__main__':
app.run()
Node.js(Express)の例:
const express = require('express');
const app = express();
app.get('/redirect', (req, res) => {
const user = req.query.user.replace(/[\r\n]/g, '');
res.setHeader('Location', `/welcome?user=${user}`);
res.status(302).end();
});
app.listen(3000);
Java(Spring)の例:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletResponse;
@Controller
public class RedirectController {
@GetMapping("/redirect")
public void redirectUser(@RequestParam String user, HttpServletResponse response) {
user = user.replaceAll("[\\r\\n]", "");
response.setHeader("Location", "/welcome?user=" + user);
response.setStatus(HttpServletResponse.SC_FOUND);
}
}
まとめ: CRLFインジェクションは、Webアプリケーションがユーザー入力を適切に処理しない場合に発生する攻撃です。攻撃者は、この脆弱性を利用してHTTPレスポンスヘッダーを改ざんし、不正なクッキーの設定やレスポンスの改ざんなどを行うことができます。ユーザー入力のエスケープやサニタイズ、セキュリティフレームワークの利用などの防止策を講じることで、この脆弱性を防ぐことが可能です。
CRLFインジェクションとHTTPヘッダインジェクションは密接に関連している攻撃手法であり、両者はしばしば混同されることがありますが、それぞれが焦点を当てる部分には若干の違いがあります。
概要:
Carriage Return
, \r
)」と「ラインフィード(Line Feed
, \n
)」を指します。これらは、HTTPプロトコルにおいてヘッダーフィールドを終了し、新しいヘッダーやボディの開始を示すために使用されます。CRLF
文字(\r\n
)が含まれている場合に発生する脆弱性です。これにより、攻撃者はレスポンスヘッダーを任意に操作し、新しいヘッダーを追加したり、レスポンスのボディを改ざんしたりすることが可能になります。概要:
これらの違いを理解し、両方の攻撃手法に対する適切な防御策を講じることが、Webアプリケーションのセキュリティを強化するために重要です。
CRLFインジェクションでないHTTPヘッダインジェクションの例について説明します。
HTTPヘッダインジェクションは、攻撃者が不正なデータをHTTPヘッダーに挿入することを狙った攻撃です。HTTPヘッダインジェクションの一部にCRLFインジェクションが含まれますが、ここではCRLFを用いない形のインジェクションの例について説明します。
<?php
$user = $_GET['user'];
header("X-User: " . $user);
攻撃手法:
攻撃者が以下のようなリクエストを送信します。
http://example.com/vulnerable.php?user=John<script>alert('XSS')</script>
このリクエストによって、レスポンスヘッダーが以下のように生成されます。
X-User: John<script>alert('XSS')</script>
このヘッダーがブラウザや他のシステムで表示されると、<script>
タグが解釈され、XSS攻撃が発生する可能性があります。
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
user_agent = request.args.get('user_agent')
response = app.response_class(
response='Hello, World!',
status=200,
headers={'User-Agent': user_agent}
)
return response
if __name__ == '__main__':
app.run()
攻撃手法:
攻撃者が以下のようなURLを使用します。
http://localhost:5000/?user_agent=Mozilla/5.0<script>alert('XSS')</script>
これにより、レスポンスヘッダーに不正なスクリプトが挿入される可能性があります。
User-Agent: Mozilla/5.0<script>alert('XSS')</script>
ブラウザや解析ツールがこのヘッダーを不適切に解釈した場合、XSS攻撃が成立します。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const referrer = req.query.referrer;
res.setHeader('Referrer', referrer);
res.send('Hello, World!');
});
app.listen(3000);
攻撃手法:
攻撃者が以下のようなリクエストを送信します。
http://localhost:3000/?referrer=evilsite.com<script>alert('XSS')</script>
これにより、レスポンスヘッダーに不正なスクリプトが挿入される可能性があります。
Referrer: evilsite.com<script>alert('XSS')</script>
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.stereotype.Controller;
import javax.servlet.http.HttpServletResponse;
@Controller
public class HeaderController {
@GetMapping("/set-header")
public void setHeader(@RequestParam String value, HttpServletResponse response) {
response.setHeader("X-Example", value);
}
}
攻撃手法:
攻撃者が以下のようにリクエストを送信します。
http://localhost:8080/set-header?value=foo<script>alert('XSS')</script>
これにより、以下のようなレスポンスヘッダーが生成されます。
X-Example: foo<script>alert('XSS')</script>
PHPの例:
$user = htmlspecialchars($_GET['user'], ENT_QUOTES, 'UTF-8');
header("X-User: " . $user);
Python(Flask)の例:
import html
user_agent = html.escape(request.args.get('user_agent'))
Node.jsの例:
const referrer = req.query.referrer.replace(/[^a-zA-Z0-9\-.]/g, '');
res.setHeader('Referrer', referrer);
まとめ: CRLFインジェクションはHTTPヘッダインジェクションの一種ですが、HTTPヘッダインジェクション全般には、ユーザー入力がエスケープされないままHTTPヘッダーに挿入されることで、不正な動作が発生するリスクがあります。ユーザー入力のエスケープやサニタイズ、無効な文字列の除去などの防止策を実施することで、これらの脆弱性を防ぐことができます。