Server-Sent Eventsを使うとサーバーからクライアントにデータをPUSHすることができます。使い方はこの辺を参考にしてください。
node.js + expressでサーバー側を実装するとこんな感じになると思います。
1 2 3 4 |
app.get('/event', function(req, res) { res.type('text/event-stream'); res.write('data: ' + data + '\n\n'); }); |
この+ data +
部分、data変数が任意の文字列の場合簡単にインジェクションができてしまいます。では安全にdata変数を出力するにはどうすればいいかを考えてみました。
改行をなんとかする
CRLFがterminatorなのでdata変数に改行があると当然おかしくなります。
対応方法として、生文字列を渡したいのであればssl.jsのようにCRLFでsplitしてdataフィールドを複数書けばよいでしょう。またJavaScriptの場合文字列をvalidなJSONとして扱えるため、とりあえずJSONにする手も使えます。(ECMA-262JSONText -> JSONValue -> JSONString
、RFC 4627の場合はobjectとarrayのみJSON-text = object / array
)
HTMLタグをなんとかする
Server-Sent EventsのContent-Typeはtext/event-streamなので、このURLをまともなブラウザで直接表示した場合ファイルダウンロードになるなど、少なくともHTMLとして開かれることはありません。しかし以前からはせがわようすけさんらが警鐘を鳴らしているIEのContent-Type無視によってHTMLとして開かれることがあります。
例えば以下のようなサーバーにIE7で/event/a.html
を開くとalertが表示されました。
1 2 3 4 5 6 7 |
app.get('/event/:id', function(req, res) { res.type('text/event-stream'); setInterval(function() { // 任意の文字列を返している、という想定 res.write('data: <script>alert(1)</script>\n\n'); }, 1000); }); |
IE8以降であればnosniffでHTMLへの昇格を防げますが、IE7以下の対策をするとしたらJSONにした上で「/」「<」「>」「+」をエスケープするくらいでしょうか。XMLHttpRequestであれば独自のリクエストヘッダをつけたりPOSTで投げたりといった方法もありますが、EventSourceはURLの指定くらいしかできないので使えません。あとscriptタグで読み込んだときにどうなるんでしょう?JSONにしてあれば大した問題にはならなそうですが。
まあServer-Sent Events使うようなサイトをIE7で見るやつなんていねーよ、って言われたらそれまでですが。
最近のコメント