検索
連載

これなら合格! 正しいリダイレクターの作り方HTML5時代の「新しいセキュリティ・エチケット」(4)(3/3 ページ)

えっ、まだmeta refreshとか301使ってるの? リダイレクターの作り方も時代とともに移り変わります。記事を読んだらすぐに使えるセキュリティ・エチケットを紹介しましょう。

Share
Tweet
LINE
Hatena
前のページへ |       

文字列マッチでは不十分! オープンリダイレクターを防ぐには

 ここまで見てきたように、どのようなリダイレクト方法であっても、実装方法によってはオープンリダイレクター脆弱性を作り込む可能性があります。

 対策として安易に「リダイレクト先のURLを入念に確認する」といった方法をとる場合でも、実際のURLにはさまざまな表現方法があり、安直な確認では簡単に外部サイトをURLとして指定されることもあります。

 例えばJavaScriptでのリダイレクトにおいて、URLとして「/foo」のような相対パスのみを許可するために、次のようなコードでリダイレクト先URLをチェックしていたとします。

// 問題のあるコード
if( url.match( /^\/[^\/]/ ) ){
    // リダイレクト先が「/」で始まり、2文字目が「/」以外のときのみリダイレクト
    location.href = url;
}

 このコードでは、リダイレクト先のURLの先頭文字が「/」であり、2文字目が「/」以外の場合にのみリダイレクトすることを意図しており、「/foo」「/bar」などはリダイレクトしますが、「http://evil.example.com/」などが与えられた場合にはリダイレクトしません。

 しかし、攻撃者がURLとして「/\evil.example.com/」などを指定した場合、一部のブラウザーでは「//evil.example.com/」と等価と扱われ、攻撃者のサイトへのリダイレクトが発生してしまいます。

 別の対策として「リダイレクト先として自ドメイン名を先頭に必ず付与する」という方法がとられることもあります。例えば、「/foo」「/bar」などが与えられた場合に「http://example.jp」を付与しリダイレクト先として「http://example.jp/foo」「http://example.jp/bar」などを返すことで、任意サイトへのリダイレクトを防ぐという方法です。

 このような方法の場合であっても、前述したmeta refreshによるリダイレクトでは、IE7において複数の「URL=」という文字列を含めた場合には最後尾の「URL=」以降がリダイレクト先として使用されるため、オープンリダイレクターを防ぐことは事実上不可能に近いものとなってしまいます。

オープンリダイレクター対策は「固定リスト」で決まり

 このように、「与えられた文字列を基にリダイレクト先URLを動的に生成する」という方法では、入念に確認を行っても漏れが発生する可能性があります。効果的にオープンリダイレクターの発生を防ぐための対策として、「事前にリダイレクト先を固定リストで保持しておく」という実装方法を推奨します。

 例えば、HTTPのステータスコード302でリダイレクトを行うコードをPerlで書いた場合には、以下のようにします。

use strict;
use warnings;
use utf8;
use URI::Escape;
my $app = sub {
    my $env = shift;
    my $pages = { foo=>'/foo', bar=>'/bar' };
    my $index = uri_unescape( $env->{QUERY_STRING} || '' );
    my $url = $pages->{$index} || '/notfound';
    return [ 302, ['Location' => $url ] ];
}

 このコードでは、URLとして「http://example.jp/redir?foo」がリクエストされた場合には「/foo」へ、「http://example.jp/redir?bar」がリクエストされた場合には「/bar」へ、それ以外の場合には「/notfound」へリダイレクトします。リダイレクト先はコード内に固定で保持されていますので、これら以外のURLへリダイレクトすることは原理的にあり得ません。

 また、JavaScriptによってlocationオブジェクトへ代入するリダイレクトの場合には、以下のようなコードにします。

var pages = { foo:'/foo', bar:'/bar' };
var url = pages[ location.hash.substring(1) ] || '/notfound'; 
location.href = url;

 このコードでも、URLとして「http://example.jp/redir#foo」のようにアクセスした場合には「/foo」へ、「http://example.jp/redir#bar」のようにアクセスした場合には「/bar」へ、それ以外の場合には「/notfound」へリダイレクトします。それ以外のURLへはリダイレクトすることはあり得ません。

 このように、オープンリダイレクトの対策としては、リダイレクト先を事前に固定のリストとして保持するという方法が最も確実で効果的です。


 繰り返しになりますが、サイト内での複雑なリダイレクトや、サイト間を横断しての連携などにより、Webアプリケーションにおけるオープンリダイレクター脆弱性は、これまで以上によく発見される傾向にあります。

 オープンリダイレクターは、サイトやユーザーに直接的な被害を与える脆弱性ではありませんが、信頼できるWebサイト構築のためには根絶すべき問題ではあります。

 本記事がセキュアなWebサイト構築の一助になれば幸いです。

はせがわようすけ プロフィール

http://utf-8.jp/

ネットエージェント株式会社 エバンジェリスト、株式会社セキュアスカイ・テクノロジー 技術顧問。Internet Explorer、Mozilla FirefoxをはじめWebアプリケーションに関する多数の脆弱性を発見。Black Hat Japan 2008、韓国POC 2008、2010他講演多数。


Copyright © ITmedia, Inc. All Rights Reserved.

前のページへ |       
ページトップに戻る