React.js に XSS 対策を求めるのは間違っているだろうか

  • View
    5.224

  • Download
    45

  • Category

    Software

Preview:

Citation preview

React.js に XSS 対策を 求めるのは間違っている

だろうか

#edomaesec 2015 5/30 LT

@clariroid

くらりど

React.js

React.js

React.js

青い紐

React.js

• UI を構築する JavaScript ライブラリ

React.js

• UI を構築する JavaScript ライブラリ

• Virtual DOM

React.js

• UI を構築する JavaScript ライブラリ

• Virtual DOM

• Component Composable

React.js

• UI を構築する JavaScript ライブラリ

• Virtual DOM

• Component Composable

• Server-side Rendering

• etc ...

React.js

• UI を構築する JavaScript ライブラリ

• (省略)

React.js

• UI を構築する JavaScript ライブラリ

• XML like な JavaScript – JSX で記述

React.js – JSX

var str = "Hello, React!";

React.render(

<span>{str}</span>,

document.body

);

React.js – JSX

var str = "Hello, React!";

React.render(

<span>{str}</span>, // js 式は { } で括る

document.body

);

React.js – JSX

• JSX Transformer

• JSX を生の JavaScript に変換

React.js – JSX

var str = "Hello, React!";

React.render(

React.createElement("span", null, str),

document.body

);

React.js – JSX

• 結果として生成される HTML

React.js – JSX

<body>

<span data-reactid=".0">

Hello, React!

</span>

</body>

React.js

• エスケープは自動でしてくれる

• が、React.js が XSS 対策にどこまで責任を負うかは議論となっている

• Issue #3473 “How Much XSS Vulnerability Protection is React Responsible For?”

React.js

• ユーザが入力した文字列から生成した 新しい DOM node を挿入したい

• Ex.) Markdown から変換された文字列

React.js

```Markdown

** edomaesec! **

```HTML

<em>edomaesec!</em>

React.js

• 直に innerHTML を叩くと怒られる

• React 版 innerHTML

• dangerouslySetInnerHTML API の利用

dangerouslySetInnerHTML

dangerouslySetInnerHTML

• 公式の Tutorial でも Backdoor な API として 使っている

• こんな風に使う

dangerouslySetInnerHTML

var str = "<em>edomaesec!</em>";

var obj = { __html: str };

React.render(

<span dangerouslySetInnerHTML={obj}/>,

document.body

);

dangerouslySetInnerHTML

var str = "<em>edomaesec!</em>";

var obj = { __html: str };

React.render(

<span dangerouslySetInnerHTML={obj}/>,

document.body

);

dangerouslySetInnerHTML

• 公式の docs より抜粋・翻訳

-- 不安を感じる言葉で意図的に名付けました。 -- プロパティ値はサニタイズされたデータを示す -- ために使われることでしょう。

dangerouslySetInnerHTML

• どれほど dangerously なのか分からない

• ソースコードを追ってみた

• react.js v0.13.3 ( 全19602行 )

• デバッガ使いましょう

dangerouslySetInnerHTML

var str = "<em>edomaesec!</em>";

var obj = { __html: str };

React.render(

<span dangerouslySetInnerHTML={obj}/>,

document.body

);

dangerouslySetInnerHTML

var str = "<em>edomaesec!</em>";

var obj = { __html: str };

React.render(

React.createElement(

"span", {dangerouslySetInnerHTML: obj}

), document.body

);

dangerouslySetInnerHTML

• L: 9928 ReactElement

{ key: “span”,

_store: {

props: {

dangerouslySetInnerHTML: { __html: str }

}

}

}

dangerouslySetInnerHTML

• ( DOM更新のトランザクションを開くコードが永遠と続くので中略)

dangerouslySetInnerHTML

• L: 7641 mountComponent

return

_createOpenTagMarkupAndPutListeners

+ _createContentMarkup

+ closeTag

dangerouslySetInnerHTML

• L: 7641 mountComponent

return

_createOpenTagMarkupAndPutListeners

+ _createContentMarkup

+ </span>

dangerouslySetInnerHTML

• L: 7664 _createOpenTagMarkupAndPut…

return

<span date-reactid=".0">

+ _createContentMarkup

+ </span>

dangerouslySetInnerHTML

• L: 7641

return

<span date-reactid=".0">

+ _createContentMarkup

+ </span>

dangerouslySetInnerHTML

• L: 7711 _createContentMarkup

var innerHTML

= props.dangerouslySetInnerHTML;

return "" + innerHTML.__html;

• __html の内容について何も確認なし

dangerouslySetInnerHTML

• L: 7641

return

<span date-reactid=".0">

+ <em>edomaesec!</em>

+ </span>

dangerouslySetInnerHTML

• L: 18971 setInnerHTML

node.innerHTML = html;

// html 先程 return された文字列

Demo

• str = "<input autofocus onfocus=alert(1)>" を代入してみる

まとめ

• React.js の dangerouslySetInnerHTML API は 通常の innerHTML 挿入と等価である

• 使わないようにリスク回避で設計したい

• dangerouslySetInnerHTML を利用する際は エスケープ(場合によってはサニタイズ)した文字列を代入させる

まとめ

サニタイズって簡単に言うけれども…

• RickDOM の使用

• marked.js の sanitize parameter を true にする ( Markdown のみ)

• HTML5 sandboxed iframe で wrap しておく ( js の実行を抑制 )

参考資料

• Dangerously Set innerHTML | React – e10s https://facebook.github.io/react/tips/dangerously-set-inner-html.html

• Yosuke Hasegawa『文字列から HTML を組み立てる話』@Shibuya.XSS techtalk #5 http://utf-8.jp/public/20140807/shibuyaxss.pdf