今までSocket.IOでチャットアプリを作ってきたけれども、
誰かが気軽に入力できて、他のブラウザで誰かから送信されたメッセージを表示できる。
送信時にHTMLタグを入れたらどうなるのだろう?
そこらへんはSocket.IOはどういう対応になるのだろう?
と気になったので、
<strong>で囲った文字列を投稿してみた。
※<strong>で囲まれた文字列は強調文字(太文字)で表示される。
結果は太文字で表示された。
HTMLタグはエスケープされないのね…
※エスケープとはHTMLタグを無効にすること
話は端折るけれども、<script>で囲った際もエスケープされなかった。
ということは任意のスクリプトを誰かのブラウザに挿入できるのね。
これは危ない!
ということで、
Node.jsでXSS攻撃の対策を調べてみたところ、
Yahooでxss-filtersというライブラリを作成していたみたい。
※XSS攻撃はWebサイトを攻撃する時の手法の一つ
yahoo/xss-filters: Secure XSS Filters
ということで早速使ってみる。
下記のコマンドでxss-filtersをインストール
npm install xss-filters
server.jsを改修する。
var fs = require("fs"); var http = require("http"); var server = http.createServer(); var xssFilters = require('xss-filters'); server.on("request", function(request, response){ /** 処理は省略 **/ }); server.listen(8080); var io = require("socket.io").listen(server); //namespacesを2つにしてみる ["hoge", "huga"].forEach(function(v){ // ユーザ管理ハッシュ var userHash = {}; // Namespacesを利用する var chatNS = io.of('/' + v); chatNS.on("connection", function(socket){ // WebSocketで接続の際にどのroomに参加するか? socket.join("default"); // 接続開始のカスタムイベント(接続元ユーザを保存し、他ユーザへ通知) socket.on("connected", function(name){ /** 省略 **/ }); // メッセージ送信カスタムイベント socket.on("publish", function(data){ chatNS.to(roomName).emit("publish", {value:xssFilters.inHTMLData(data.value)}); }); let nowTyping = 0; socket.on("start typing", function(){ /** 省略 **/ }); socket.on("stop typing", function(){ /** 省略 **/ }); socket.on("disconnect", function(){ /** 省略 **/ }); }); });
メッセージを送信するところで、フィルターを使用するように書き換えた後、
ブラウザを立ち上げて確認してみたところ、
HTMLタグがエスケープされた状態で表示されるようになった。