最近一週間ほどのえび日記
2012年4月17日(火曜日)
Content-Languageでコンテント・ネゴシエーションを行うことができるのか?
公開: 2012年5月1日8時55分頃
ウェブアクセシビリティ基盤委員会 (waic.jp)のサイトには、「WCAG 2.0 実装方法集 (waic.jp)」という文書があります。これはTechniques for WCAG 2.0 (www.w3.org)を和訳したものです。
WCAG2.0の本体には、達成するべき基準が書かれているのですが、内容は抽象的で、具体的な実装方法までは書かれていません。たとえば、「利用者に提示されるすべての非テキストコンテンツには,同等の目的を果たす代替テキストを提供しなければならない」と規定されていても、それを具体的にどのような実装にすれば良いのかまでは書かれていません。それでは分からないので、具体的な実装方法は別のドキュメントにまとめられています。それがTechniques for WCAG2.0です。
このように文書が分けられている理由はいくつかあります。WCAG2.0が特定の技術 (たとえばHTML) に依存しない、汎用的な基準を定めることを目指したという点もありますが、本体はW3C Recommendationなので、頻繁な更新ができないという事情もあります。Recommendationの更新には時間がかかるので、新しい技術の出現に対応することが難しいわけです。Techniquesの方はNoteになっていて、それなりの頻度で更新できるようになっています。
つまりどういうことかというと、Techniques for WCAG 2.0はそれなりの頻度で更新されるということです。現在のTechniquesは2012年1月版となっています。しかし、和訳の方は2008年12月版のままで、かなり古くなってしまっています。
というようなわけで、新たに追加された項目をチェックしていたのですが、実装方法にSVR5というものが増えています。
IDの「SVR」は "Server" の意味で、SVR5はサーバ側の実装例の5番目のものという意味です。SVR5では、HTTP応答ヘッダのContent-Languageで言語を指定するというテクニックが紹介されています。そこまではまあ良いのですが、読んでみると微妙な記述が……。
Content-Language HTTP header can contain a list of one or more language codes, which can be used for language negotiation between a user agent and a server. If the language preferences in a user agent are set correctly, language negotiation can help the user to find a language version of the content that suits his/her preferences.
以上、SVR5: Specifying the default language in the HTTP header (2012年1月3日版) より
"can be used for language negotiation between a user agent and a server" とあり、Content-Languageを言語によるコンテント・ネゴシエーションに使うことができると書いてあるように読めます。しかし、Content-Languageをコンテント・ネゴシエーションに使うというのは聞いたことがありません。
普通、ネゴシエーションに使われるのは、ユーザーエージェントのHTTP要求ヘッダに入っているAccept-Languageです。サーバは、ネゴシエーションにAccept-Languageが使われていることを明示するために、Vary: Accept-Languageをつけて応答することがありますが、Content-Languageは使われません。サーバは300 Multiple Choisesや406 Not Acceptableで応答することがあり、このときはユーザーエージェントの側に選択がゆだねられますが、ここでもContent-Languageがネゴシエーションに使われるわけではありません。
無理矢理考えると、サーバからマルチパートで複数の言語を含んだ応答をして、それぞれのパートにContent-Languageをつけておけば選択できるような気もしますが、それはネゴシエーションとは言わないと思います……。
というわけで、この記述は何かが間違っているのではないかという気がしていますが、あるいは私が知らないネゴシエーション方法があるのかもしれません。
ではContent-Languageは何の役に立つのかというと、HTMLの場合はhtml要素にlang属性をつけてやれば良いので、Content-Languageの出番はあまりありません。しかし、HTTPで転送されるのはHTMLだけではありません。プレーンテキストやダウンロードデータなどの場合、データ自身に言語を指定する機能はありませんので、HTTP応答ヘッダでの指定が意味を持ちます。
RFC2616の14.12 Content-Language には以下のような記述があります。
The primary purpose of Content-Language is to allow a user to identify and differentiate entities according to the user's own preferred language.
ここでは、ユーザーが設定した優先言語と違うかどうか識別できると言っています。たとえば、ユーザーの優先言語と違っていたら「このコンテンツは英語ですが自動翻訳しますか?」というアラートを出すブラウザがあります。HTML以外のコンテンツであっても、Content-Languageの指定があれば、そういった挙動ができるようになるかもしれません。
- 「Content-Languageでコンテント・ネゴシエーションを行うことができるのか?」へのコメント (2件)
2012年4月16日(月曜日)
平成24年度春期情報セキュリティスペシャリスト試験のXSS問題
公開: 2012年4月30日13時35分頃
今年の春の情報処理技術者試験の問題が公開されていますね。
- 平成24年度春期(1)試験 問題冊子・解答例・採点講評・配点割合 (www.jitec.ipa.go.jp)
面白いと思ったのは「情報セキュリティスペシャリスト試験」の午後Ⅰの問1。こういうコードがあります。
out.println("<a name=\"#\" onclick=\"alert('" + escape(word) + "')\">");
out.println("previous search word");
out.println("</a>");
以上、平成24年度 春期 情報セキュリティスペシャリスト試験 午後Ⅰ 問題 図4(続き) より
やや読みにくいですが、こんな感じのHTMLが出力されるイメージになります。
<a name="#" onclick="alert('word')">
previous search word
</a>
変数wordには入力されたキーワードが入っていて、関数escapeはこういう内容。
private static String escape(String message){
// この関数は、messageに含まれる文字を次のように置換したString型の文字列を返す。
// 「&」→「&」「<」→「<」「>」→「>」「"」→「"」
(省略)
}
以上、平成24年度 春期 情報セキュリティスペシャリスト試験 午後Ⅰ 問題 図4(続き) より
しかしこれではXSS脆弱性があるので、新たにescape2という関数を作ってそれを呼ぶことにしたそうです。
escape2関数では, 意図したスクリプトが生成されるように, まず, スクリプト言語の文法上必要なエスケープ処理を行った後, 更にescape関数でエスケープ処理を行う。
private static String escape(String message){
// この関数は、messageに含まれる文字を次のように置換したString型の文字列を生成し、
// その文字列をescape関数に渡し、その結果のString型の文字列を返す。
// 「[ d ]」→「[ e ]」「[ f ]」→「[ g ]」
(省略)
}
以上、平成24年度 春期 情報セキュリティスペシャリスト試験 午後Ⅰ 問題 図5 より
このd~gの空欄について、d,fには置換の対象文字を、e,gには置換後の文字を答えよ、というのが問題です。
結構な難問だと思います。
まずescape2という関数名を全力で却下したくなりますが、「適切な名前をつけると問題のヒントになってしまうので、あえてこうしているに違いない」と自分に言い聞かせて落ち着きましょう。
問題は、この関数がどのように使われる想定なのかよく分からないことです。汎用的に使われるのだとすると、問題の箇所でうまく動くだけでは駄目で、たとえばJavaScriptのリテラルが二重引用符で括られていた場合もうまく処理できないとまずいでしょう。
しかし回答欄を見ると、エスケープできる対象文字は2つしかありません。これでは汎用的な処理は無理なので、このコードに限定した話と考えるべきなのでしょう。つまり、escape2は「二重引用符でくくられたHTMLの属性値リテラル内の、単引用符でくくられたJavaScriptの文字列リテラル」に限定して処理できれば良いのだと割り切るわけです。
しかし、そう割り切っても、2つではちょっと足りない気がするのですね。
まずシングルクォート「'」のエスケープが必要なのは明らかです。これを「\'」や「\x27」や「\u0027」にエスケープします。
そしてバックスラッシュ「\」を「\\」や「\x5c」や「\u005c」にエスケープします。これをエスケープしないと、「\'」という文字列を入れられたときや、末尾に \ を入れられたときに不都合がおきます。
さらに、改行を「\n」などにエスケープする必要があります。これをエスケープしないと、文字列リテラルが終了していないとみなされてエラーになります。たとえばIE9の場合だと、コンソールに「終了していない文字列型の定数です。」というエラーが記録され、スクリプトは動作しません。
とはいえ、改行のエスケープを怠っても任意のスクリプトが動作するということはありません。実務上は「動かなくなる」というのは不具合とみなされると思いますが、純粋に問題への解答としては、改行のエスケープはなくても良いといえるのかもしれません。
というわけで、「このコードに限定した話」かつ「攻撃さえ防げれば良い」という立場をとり、シングルクォートとバックスラッシュのみをエスケープするのが正解……。
……と言いたいところでしたが、ちょっと待ってください。「このコードに限定した話」かつ「攻撃さえ防げれば良い」という立場を取るのだとすると、バックスラッシュのエスケープは本当に必要なのでしょうか?
シングルクォートを「\'」にエスケープするのなら、バックスラッシュのエスケープは必須になります。ユーザーが「\');alert(document.cookie)//」を入力したとき、バックスラッシュのエスケープがないと、問題箇所はこうなります。
onclick="alert('\\');alert(document.cookie)//')"
この場合、クリックすると1度「\」が表示されたあと、続けてCookieの値が (もしあれば) 表示されます。つまり、任意のスクリプトが動作します。
しかし、シングルクォートを「'\」ではなく「\u0027」にエスケープしていると、こうなります。
onclick="alert('\\u0027);alert(document.cookie)//')"
「\u0027);alert(document.cookie)//」という文字列が表示されるだけです。「'」が「\u0027」に化けて表示される不具合がありますが、任意のスクリプトが動作しているわけではありません。
シングルクォートを「\u0027」にエスケープすれば、\' を入力されても \\u0027 となって \u0027 と表示されるだけです。意図とは異なりますが、任意のスクリプトは動作させられません。文字列の末尾に \ を入力されると、リテラルの終端の ' が壊れてスクリプトエラーになりますが、これは改行を入れたときと同じ事です。「このコードに限定した話」であれば、その後はすぐに改行が出現し、改行の前にユーザーが何かを入れる余地はありません。
任意のエスケープシーケンスを入れることができるという問題がありますが、文字列リテラルの中に何があっても、スクリプトの実行には至らないはずです。何か見落としがある (突破方法がある?) かもしれませんが、どうでしょうか……?
まとめると、こういうことです。
- 「このコードに限定した話」という仮定を置かない場合、escape2は単引用符、バックスラッシュ、改行に加え、二重引用符などもエスケープする必要があるかもしれない。
- 「このコードに限定した話」と仮定し、かつ「不具合なく動作する」ことを想定した場合、escape2は単引用符、バックスラッシュ、改行をエスケープする必要がある。
- 「このコードに限定した話」かつ「攻撃さえ防げれば良く、不具合があっても良い」と想定した場合、escape2は少なくとも単引用符をエスケープする必要がある。
- 単引用符を「\'」にエスケープすれば、バックスラッシュのエスケープも必須になる
- 単引用符を「\u0027」にエスケープすれば、バックスラッシュのエスケープは必要ないかもしれない (見落としがある? 突破できる?)
通常の実装では、エスケープする文字の種類が2種類に制限されることはないと思いますので、不具合がないようにしっかり4種類エスケープすれば良いと思います。あるいは、英数字以外の全てを \uXXXX の形式にエスケープするようなアプローチでも良いでしょう。
ところで、不具合と言えば、問題のコードにはエスケープとは関係ない不具合らしき点があります。問題箇所のHTMLはこうなるのですが、
<a name="#" onclick="alert('word')">previous search word</a>
a要素にhref属性がついていません。一応クリックすればスクリプトは動きますが、特殊なスタイルを適用しなければクリックできそうな見た目になりませんし、キーボード操作もできません。name属性に "#" という値を指定するのも妙な話です。
これはまあ、hrefとnameの取り違えでしょう。出題者はこのコードを実際に動かしていないのではないでしょうか?
※ちなみにHTML4のa要素のname属性の値はIDではなくCDATAなので、"#" という値はいちおう正当です。HTML5のa要素にはname属性はありません。
2012年4月13日(金曜日)
Google Playで不正アプリが配布される
公開: 2012年4月22日16時0分頃
Google Play (play.google.com) (旧名: Android Market) で「○○ the Movie」という名前の不正アプリが配布されていたそうで。
- 「○○ the Movie」という名のAndroidアプリに注意、裏で個人情報ぶっこ抜き Google Playで複数配布されていたことが判明 (internet.watch.impress.co.jp)
問題のアプリは、「○○」の部分に「うまい棒をつくろう!」「チャリ走」「桃太郎電鉄」「けいおん」などの人気アプリ/コンテンツの名称が冠されていた。それらを入手して調査したネットエージェント株式会社によると、各アプリではそれぞれの名称に応じたそれらしい動画がストリーミング再生されるため、見かけ上は人気アプリの使い方を説明したり、人気コンテンツをまとめて紹介する動画アプリといった体裁だという。
しかしインストール時には、動画を再生するだけのアプリには不要と思われるパーミッションを要求。このうちネットエージェントが挙動を確認したあるアプリでは、スマートフォンに登録されている利用者の名前と電話番号、Android ID、電話帳に登録されている人の名前、電話番号、メールアドレスを取得し、外部サイトに送信していることがわかった。
個人情報を抜いて送信するタイプのものですね。このような不正アプリは今までにもあったと思いますが、これが Google Play で配布されていたというのが。
Androidをターゲットにしたマルウェアや悪意のあるアプリに対する防衛策として、「信頼できないサイトで配布されているアプリをインストールしないこと」などと言われるが、Google Play(旧Android Market)という公式マーケットで配布されているアプリだからといって安心できない現状がある。
ユーザーは、インストール時にどんな項目のパーミッションが求められるのか注意深く確認して判断する必要があるわけだが、アプリのメインの機能とは一見して関係なく見える情報・機能にアクセスするようなアプリもあり、一般ユーザーにはなかなか判断できないのが実情だ。
公式サイトで配布されているものならまあインストールしても大丈夫……などと言えなくなってしまったわけで、こうなってくると、普通の人はAndroidにアプリを入れるべきではないという話になりかねないですね。なかなか厳しい状況です。
- 前(古い): 2012年4月9日(月曜日)のえび日記