セキュリティ

October 27, 2010

XSSに強いウェブサイトを作る – テンプレートエンジンの選定基準とスニペットの生成手法 (第1回神泉セキュリティ勉強会発表資料)

発表資料は以下のとおり。春山様はじめECナビの皆様、ありがとうございました。

October 01, 2010

Shibuya.pm でセキュアコーディングの話をしてきた件

昨日は、Shibuya Perl Mongersテクニカルトーク#14 に参加してきました。

パネラーとしてウェブサイトのセキュリティに関するディスカッションに加えていただいて、いろいろ上から目線で大局的な話をしたり。一方、ライトニングトークでは具体的な事例として、既にブログに書いた Twitter の XSS に絡んで構造化テキストの処理手法について話をさせていただきました (参照: 構造化テキストの正しいエスケープ手法について, String::Filter っていうモジュール書いた)。

とはいえ、既にブログに書いたことを繰り返すのも芸がないので、正しい設計が何か、という切り口ではなく、どういう設計をすれば「安全」か、という話になっています。スライドは以下にありますので、興味のある方はご覧ください。

主催の shibuya.pm の皆様、パネルディスカッションに参加する機会をいただいた IPA の皆様、会場をご提供いただいた IIJ の皆様、ありがとうございました。

September 23, 2010

String::Filter っていうモジュール書いた - 続: (Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について

先のエントリ「(Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について」の続き。

弾さんが「404 Blog Not Found:DHTML - 構造化テキストは構造化するのがやっぱ正しい」で示されているような DOM ベースの操作を行えば、原理的に XSS 脆弱性を防ぐことができます。ただ、クライアントサイド JavaScript によるレンダリングはウェブの構造を破壊するという点で筋が悪い(テーブルと FONT タグを利用したページレイアウトが批判されていた頃を覚えていらっしゃいますでしょうか。JavaScript によるレンダリングはウェブのリンク構造も破壊するので一層たちが悪いというのが自分の考え)ですし、サーバサイドでの DOM 操作は重たいので、できれば避けたいところです。

構造化テキストの HTML への変換は、よほど複雑な記法でない限りはワンパスで処理可能ですし、であれば、わざわざ DOM のような構造を作らなくても、SAX のようにイベントベース(あるいはコールバックベース)で処理すれば済むことなのですから。

このような変換の必要は、Twitter に限らず、しばしば耳にするものです。最近自分が目にしたものだと「Template中のURLを自動で賢くアンカーテキストにしたい - すぎゃーんメモ」。このケースでは URL さえリンク化できれば良かったので tokuhirom さんのコメントのとおりでいいんですが、この URI::Find を使う手法だと URL 以外のものも処理したくなった時に対応できないんだよなーと思って見ていたのでした。

そしたらちょうど Twitter の件があったので、複数の変換ルールを合成可能な文字列変換モジュール String::Filter を書いて CPAN にアップロードしました。このモジュールを使えば、ツイートの変換ルールは下の例のように書くことができます。(@user や #hashtag の前には空白が必要といったルールも入っているため)やや長く感じられるかもしれませんが、意図は明確ですし、ルールを後から追加・変更できるので使いやすいのではないでしょうか。

このような HTML スニペット生成手法と、Text::MicroTemplateText::Xslate のような型ベースの自動エスケープ機能(詳細は「Kazuho@Cybozu Labs: Text::MicroTemplate - テンプレートエンジンのセキュリティと利便性」を参照)を備えたテンプレートエンジンを組み合わせることで、自然と、より安全なウェブアプリケーションを開発できるようになっていけばいいな、と思うところです。

use HTML::Entities (encode_entities);
use String::Filter;

# デフォルトの変換ルールを指定してフィルタオブジェクトを生成
my $sf = String::Filter->new(
    default_rule => sub {
        my $text = shift;
        encode_entities($text);
    },
);

# URL の変換ルールを登録
$sf->add_rule(
    'http://[A-Za-z0-9_\\-\\~\\.\\%\\?\\#\\@/]+',
    sub {
        my $url = shift;
        sprintf(
            '<a href="%s">%s</a>',
            encode_entities($url),
            encode_entities($url),
        );
    },
);

# @user の変換ルールを登録
$sf->add_rule(
    '(?:^|\\s)\\@[A-Za-z0-9_]+',
    sub {
        $_[0] =~ /^(.*?\@)(.*)$/;
        my ($prefix, $user) = ($1, $2);
        sprintf(
            '%s<a href="http://twitter.com/%s">%s</a>',
            encode_entities($prefix),
            encode_entities($user),
            encode_entities($user),
        );
    },
);

# #hashtag の変換ルールを登録
$sf->add_rule(
    '(?:^|\\s)#[A-Za-z0-9_]+',
    sub {
        $_[0] =~ /^(.?)(#.*)$/;
        my ($prefix, $hashtag) = ($1, $2);
        sprintf(
            '%s<a href="http://twitter.com/search?q=%s">%s</a>',
            encode_entities($prefix),
            encode_entities(uri_escape($hashtag)),
            encode_entities($hashtag),
        );
    },
);

# tweet を HTML に変換する
my $html = $sf->filter($tweet);

September 22, 2010

(Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について

昨日の Twitter の XSS 騒ぎは、まだ皆さんの記憶に新しいことと思います。いい機会なので、ツイートのような構造化テキストのエスケープ手法について触れておきたいと思います。

Twitter のメッセージは、単なる平文(プレインテキスト)ではなく、「@英数字」のような他のユーザーへの言及と「http://〜」のような URL を自動的にハイパーリンク化する構造化テキストです。

このような複数のルールをもつ構造化テキストを HTML 化する際には、どのようなコードを書けばいいのでしょう? まず「@〜」をリンク化してから、URL をリンク化すればいいのでしょうか? それだと、@〜 のをリンク化した A HREF タグの中の URL がさらにリンク化されていまいますね。

では、URL をリンク化してから @〜 をリンク化すればいいのでしょうか? それだと、@ を含む URL があった場合に、やはり HTML が壊れてしまいます。

正しいアプローチは、全てのルールを同時に適用することです。

Perl で書くなら、以下のように、「@〜」と URL を検出するパターンを単一の正規表現にまとめてトークナイズ (split) し、切り出されたトークンがどのタイプかを判定しながら処理していきます。

my $html = '';
for my $token (split m{(http://[0-9A-Za-z_\.\%\?\#\@/]+|\@[0-9A-Za-z]+)}, $tweet) {
    if ($token =~ m{^http://}) {
        $html .= '<a href="' . encode_entities($token) . '">'
            . encode_entities($token) . '</a>';
    } elsif ($token =~ m{^\@(.*)$}) {
        my $user = $1;
        $html .= '<a href="http://twitter.com/' . encode_entities($user) . '">'
            . encode_entities($token) . '</a>';
    } else {
        $html .= encode_entities($token);
    }
}

でもルールが複雑になってくると面倒なので... 続きはあとで書くString::Filter っていうモジュール書いた - 続: (Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について」に続く

July 02, 2010

Writing a Fast and Secure HTTP Parser (in the case of HTTP::Parser::XS)

In May, I had a chance to give a talk at Tsukuba.xs Beer Talks #1.  I forgot to upload the slide since then, but finally, here it comes :-p

The slide titled "HTTP::Parser::XS - writing a fast & secure XS module" covers the design and implementation of HTTP::Parser::XS: an XS HTTP Parser that is used by a number of Plack-compatible web servers, and picohttpparser: its underlying HTTP parser written in C.

My intention was to introduce to programmers who mostly use Perl the fun of writing tight (fast and beautiful) code using the C programming language.  It would be grateful if you could feel some of my addiction from the slides.  Enjoy!

PS. And if you find any security holes or bugs, please let me know. Thank you in advance.