日々のコンピュータ情報の集積と整理

Dr.ウーパのコンピュータ備忘録

2015年2月27日金曜日

JavaScript:element.setAttributeしたときの、HTMLはどうなっているか?

本投稿の要約

setAttribute を使用することで、HTML 構造の破壊を防ぐことはできますが、危険な値そのものが入り込むことは防ぐことはできません。

別途、危険な値が入り込まないような仕組み(そもそも設定しない、値のエスケープ処理等)を実装する必要があります。


イントロダクション

JavaScript にて、「DOM Based XSS」の脆弱性を埋め込むのを防ぐためには、document.write や element.innerHTML などを使うのではなく、以下のように DOM 操作用メソッドを使用すると良いとされています。

入力されたテキストをブラウザに表示されているドキュメントの要素の属性に設定:
element.setAttribute(attribute, input_text);

attribute : 設定する属性の名前
input_text : 入力されたテキスト
element : 属性を設定する要素(element オブジェクト)


このとき、入力されたテキストを属性値として設定した要素の HTML が、入力されたテキストによってどうなるのか気になりませんか?

そこで、実際に JavaScript でコードを作成して試してみました。

element.setAttribute(attribute, input_text)のHTMLはどうなるか?


element.setAttribute(attribute, input_text) の HTMLがどうなるのかを確かめるため、次の検証用 JavaScript コードを作成しました。


実験用コード:

<form onsubmit="return false;">
<b>input_text:</b><br />
<textarea id="input-text" rows="4" cols="80">
&quot;>Hello!</textarea><br />

例)&quot;>Hello!<br />

<input type="button" value="実行" onclick="runTest_setAttribute_outerHTML();" /><br />

</form>
<br />

<b>element.setAttribute("title", input_text)のouterHTML:</b><br />
<textarea id="output-html" rows="4" cols="80">
ここにデータ出力
</textarea><br />

<b>input_text(確認用):</b><br />
<textarea id="input-text-viewer" rows="4" cols="80">
ここにデータ出力
</textarea><br />

<script type="text/javascript">
<!--

    function runTest_setAttribute_outerHTML() {
        var input_text = document.getElementById("input-text").value;

        var obj = document.createElement("div");
        obj.setAttribute("title", input_text);

        document.getElementById("output-html").value = obj.outerHTML;
        document.getElementById("input-text-viewer").value = input_text;
    }

//-->
</script>

textarea に入力されたテキストデータ(input-text)に対して、obj.setAttribute("title", input_text) を実行し、その outerHTML を textarea (output-html)に出力しています。

また、入力されたテキストデータ(input-text)が何らかの要因によって、勝手に変換されていないことを確認するために、最後に 入力されたテキストデータ(input-text) を textarea (input-text-viewer)に出力しています。


実験結果:

次のテキストデータを入力した時の、obj.setAttribute("title", input_text) の outerHTML を見てみます。

入力テキストデータ(input-text):
">Hello!

element.setAttribute("title", input_text)のouterHTML:
<div title="&quot;>Hello!"></div>

input_text(確認用):
">Hello!


このように、入力されたテキストデータにダブルクォーテーション(")が入っていたとしても、title 属性の値に設定されるときに、エスケープ処理されていることが分かります。

従って、意図しない属性値の終端によって、HTML の構造を破壊するような DOM Based XSS を防止することができます。

JavaScript にて、「DOM Based XSS」の脆弱性を埋め込むのを防ぐためには、このような DOM 操作用メソッドを使用すると、確かに HTML 構造の破壊からは、安全に入力データを扱うことができることが分かりました。


ただし、この方法によって防ぐことが出来るのは、意図しない HTML 構造の破壊だけです。

外部から入力されたデータを、属性値に設定する場合には、別途そのデータが属性値に設定しても安全かどうか検証する必要があります。

そもそも、その属性に外部からのデータを設定しても良いのかも、検証が必要です。

例:href 属性に設定する場合など
入力値として、

javascript:任意のスクリプト
 例)javascript:alert("hello!");

が与えられた場合、element が a タグの場合には、

element.setAttribute("href", input_text);

を実行すると、クリックしたときに任意のスクリプトを実行する危険なリンクを作成してしまいます。

element.setAttribute("href", input_text)のouterHTML:
<a href='javascript:alert("hello!");'>Click!</a>


そもそも、a タグの href に、外部からのデータがそのまま入り込むような実装は避けなければなりません。(外部からのデータをURLのクエリパラメータに含めたい場合などには、慎重なエスケープ処理が必要です。)
スクリプトの実行だけでなく、意図せぬページへリンクさせられてしまいます。

この例では、href 属性に着目しましたが、他の属性についても、値を設定する場合には、セキュリティ上の脆弱性が生じないかどうか慎重に検討する必要があります。


なお、実際に動作する上記のプログラムを、以下に設置しておきましたので、試したいデータがあれば、試してみてください。


実験用プログラム:

input_text:

例)">Hello!


element.setAttribute("title", input_text)のouterHTML:

input_text(確認用):



関連記事

セキュリティ対策:JavaScriptでHTML操作をする人は必読!IPAテクニカルウォッチ 『DOM Based XSS』に関するレポート
http://upa-pc.blogspot.com/2015/02/javascript-dom-based-xss-ipa.html

JavaScript:document.createTextNodeをappendChildしたときの、HTMLはどうなっているか?
http://upa-pc.blogspot.com/2015/02/javascript-dom-based-xss-protect-createTextNode.html





関連記事

関連記事を読み込み中...

同じラベルの記事を読み込み中...