JavaScript の サニタイジング

0 件のコメント

守る資産、脆弱性、脅威の3つが揃ったとき、そこにセキュリティリスクが発生します。 ここでは、脆弱性を減らすことで、セキュリティリスクの低減を図る方法を示します。 具体的にここでは、JavaScript の サニタイジング を行うことで XSS(クロスサイトスクリプティング) を防ぐ方法をみていきます。

目次

警戒すべき出力地点

以下の場所で サニタイズ が行われているか チェック します。 適切に行われているかどうかは、 コードレビュー で チェック します。

  • スクリプトを呼び出せる部分
    • iframe.src
    • script.src
    • img.src
  • スクリプトを実行できる部分(DOM要素のイベント)
    • img.onerror 等
    • element.style の expression ( 例:<div style="z:expression(...)"></div> )
  • スクリプトを直接挿入できる部分
    • element.innerHTML
    • document.write
  • 文字列をスクリプトと解釈する部分
    • setTimeout
    • setInterval
    • eval

サニタイズ の 対象文字列

JavaScript で 特別な意味を持つ文字列 = エスケープすべき文字列 は以下の通りです。

  • < → &lt;
  • > → &gt;
  • " → &quot;
  • ' → &#39;
  • & → &amp;

サニタイズ の 方法

上記 無害化すべき対象文字列 を エスケープする関数、およびその関数の利用例を以下に載せます。

サニタイズ関数

/**
* @namespace
*/
var sanitize = sanitaize || {};

/**
* HTML, JavaScipt で特別な意味を持つ文字列を無害な文字列へ変換します。
* @public
* @param  {string}  str 変換元の文字列
* @return {string}  無害化された文字列
*/
sanitaize.encode = function (str) {
    return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
};

/**
* エスケープされた文字から元の文字列を復元します。
* @public
* @param  {string}  str 無害化された文字列
* @return {string}  無害化前の元文字列
*/
sanitaize.decode = function (str) {
    return str.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&amp;/g, '&');
};

サニタイズ関数 の 使い方

var message;

// 有害なコード
message = '<script>window.alert("foo-bar");</script>';

// エスケープして表示
document.getElementById('message').innerHTML = sanitize.encode(message);

ちなみに、上記 "使い方" の場合、わざわざ サニタイズ せず次のような コード の方が、処理速度と安全性の観点から適切だと思います。

document.getElementById('message').appendChild(document.createTextNode(message));

何が問題なのか

「任意のスクリプトが実行できる」脆弱性が問題です。 詳細は XSS(クロスサイトスクリプト)で検索いただければ、それだけで沢山の記事がでてきます。 が、ここでは「任意のスクリプトが実行できるとどのようなことが起こるか」の例を1つ挙げてみます。

脆弱性が引き起こす問題の事例

  1. サービスA は「任意のスクリプトが実行できる」脆弱性がある
  2. サービスA の脆弱性を利用して「アクセスしてきた人のログインID、パスワードを 別サーバーBへ転送するスクリプト」を埋め込む
  3. ...しばらく待つ(=サービスA 利用者の情報がサーバーBに集まるのを待つ)
  4. サーバーB に集まった ユーザーID、パスワードを利用して、サービスA を利用する(=なりすまし)

この例は、かなり単純化した上、ことごとくダメなサービスを例としています。 こんなことにならないように、注意したいものです…

今回、以下のサイトを参考にしました。