「ユーザ参加型サービス」のもつ危険性
一般的なWebアプリケーションでは、HTMLタグとなる文字をエスケープしていれば、それがクロスサイトスクリプティング対策にもなっていました。しかし、Wikiやブログのようなユーザ参加型のサービス の場合、HTMLタグとなる文字を単純にエスケープすることはできません。ユーザに参加してもらう、つまりユーザにHTMLを記述してもらう 場合があるためです。ユーザの中には素直なユーザだけではなく、不正なスクリプトを混入させようと狙っている攻撃者も存在します。
というわけで、今回から2回に渡って、ユーザ参加型のサービスを提供しつつ、セキュリティを確保する方法について見ていきます。今回はWiki のセキュリティについて考え、次回はブログ のセキュリティを考えたいと思います。
Wikiのセキュリティ要件
基本的にWikiには認証 という考えは無く、不特定多数の人が誰でも記事を編集できるようになっています。認証が無い代わりに変更履歴として、IPアドレスと変更箇所が記録 されます。この方法のセキュリティレベルは決して高いとは言えませんが、攻撃に対して十分な抑止効果を発揮しており、セキュリティと利便性のトレードオフという観点では、バランスの取れた位置にあると思います。
Wikiを提供する際に難しいのは、クロスサイトスクリプティング対策 です。文字装飾や整形のためのHTMLタグは許可しつつ、スクリプトは許可しないようにする必要があるためです。
ここでひとつ例を挙げて考えます。
たとえば見出しを表示する場合、HTMLでは以下のように記載します。
<H2>見出し</H2>
さて、ここで入力された文字列が単なる見出しであり、スクリプトが実行されないかをチェックする必要があります。そのためには以下のような処理を行えばよいと考えられます(図1)。
HTMLを構文解析する
許可されたタグであるかをチェックする
許可された属性、属性値であるかをチェックする
図1 スクリプトチェックフロー
Wikiにおけるセキュリティ対策の問題点
それでは上記の方法でスクリプトの混入を防ぐことができるかを考えてみます。
まず、以下の2つのHTMLを見てください。どのように構文解析すればよいでしょうか。そして、スクリプトが実行されると思いますか?
1.html
<H2/</onmouseover=alert('sst')
<b>見出し</H2>
2.html
<script src=a.js?<H2>見出し</H2>
正解は表1 のようになります。
表1 ブラウザによる構文解析の違い
1.html 2.html
Internet Explorer 6 ○ ×
Internet Explorer 7 ○ ×
Firefox 2.0.0.7 × ○
Opera 9.23 × ×
Safari 3.0.3 × ×
○:実行される
×:実行されない
(バージョンは執筆時点での最新版, OSはWindows XP)
ご覧のとおり、ブラウザによって異なる結果になっています。HTMLの構文解析はブラウザによって解釈の異なる部分もあるため、解析しきれないというのが現実です。また、今後各ブラウザがいつ仕様変更されるかもわかりません。
次に以下をご覧ください。攻撃者は以下のようなHTMLを挿入してくることが考えられます。
<H2/onmouseover=alert('xss') >見出し</H2>
<H2 onmouseover=alert('xss') >見出し</H2>
<H2 style="{javascript:expression(alert('xss'))}" >見出し</H2>
<H2 style="{a:expression(alert('xss'))}" >見出し</H2>
<H2 style="{javascript:expression(alert('xss'))}" >見出し</H2>
たとえば構文解析がうまくできていなかった場合、上記1番のスクリプトが混入します。
許可された属性値であるかのチェックがうまくできていなかった場合、2~5番のスクリプトが混入します。
つまり、ブラックリスト方式では漏れなくチェックできそうにありません。実際、ブラックリスト方式を採用しているサイトでは多くの対策漏れが見つかっています。
Wiki記法
そこで多くのWikiで採用されているのがWiki記法 です。ユーザにHTMLを記述させるのではなく、Wikiの中だけで有効な命令 を定義し、その命令にもとづいてHTMLを構成していく方法です。
それでは例を見てみましょう。いろいろな種類のWikiがありますが、今回はPukiwiki を例に説明します。PukiWiki記法で見出しを表示する場合には以下のように記述します。
* 見出し
すると以下のようなHTMLが生成されます。
<H2>見出し</H2>
ハイパーリンクを作成する場合には以下のように記述します。
[[SST:http://www.securesky-tech.com]]
その結果、以下のようなHTMLが生成されます。
<A HREF="http://www.securesky-tech.com">SST</A>
ページが生成されるまでは、図2 のような流れになります。
図2 PukiWiki記法を用いた場合のページ生成フロー
HTMLを構文解析するのではなく、このようにHTMLを一から生成する ようにすることで、スクリプトが混入する可能性を低くすることができます。
しかし欠点も存在します。
表現の自由度の低下
自由にHTMLを記述できる場合に比べて、Wiki記法で定義された記述しかできないために、表現の自由度が下がります。
Wiki記法を覚えるのが面倒
Wikiには多くの種類のWikiがあるのですが、残念ながら統一のWiki記法が存在するわけではありません。ユーザがWikiごとにWiki記法を覚える必要があります。といっても、そのつどヘルプを見ればすぐ書ける程度であり、難しいことを覚える必要があるというわけではありません。
なお、Wiki記法の入力をサポートするためにWYSIWYGエディタ と呼ばれる入力支援機能が用意されているWikiもあります(図3 ) 。WYSIWYGとは、W hat Y ou S ee I s W hat Y ou G etの頭文字を取ったもので、見たままの結果を得られるという意味です。WikiのWYSIWYGエディタの場合、挿入したいHTMLタグのアイコンをクリックすると、Wiki記法で書かれたタグを挿入してくれます。そのため、WYSIWYGエディタを用意すれば、Wiki記法を覚える手間を軽減することができます。
図3 DokuWikiのWYSIWYGエディタ
このように、Wiki記法には欠点もあるのですが、Wikiという機能を十分に提供しつつ、セキュリティを確保できるという点で役に立つ手段だといえると思います。HTMLに比べて容易に書くことができるという観点もありますが、セキュリティの観点でも有用です。さらにWikiだけではなく、ユーザ参加型のサイトを構築する際には参考になる考え方です。