Node.js を Proxy サーバー兼レイアウト変更ツールとして使用すると、毎回同じ問題に遭遇するのでそれの回避方法のまとめ。
Node.js-v0.6.2 で確認。いずれ解決されてバッドノウハウになるだろうと思われる。
作成 2011.11.27
更新 2011.11.27
更新 2011.11.27
Node.js の jsdom に読み込ませる HTML を安全化するノウハウ
サンプルコード全体
管理していないサイトから取得した html を jsdom へそのまま突っ込むと、未対応コードの問題で例外が発生する場合があり、期待通りの動作をする保証がない。
現段階のバージョンでは以下の問題が判明している。
また、// ~~~ の行を無差別に削除すると、スクリプトコメント以外の文字列も削除してしまうため、これらの問題を回避するようにしている。
現段階のバージョンでは以下の問題が判明している。
- 正規表現の複数行マッチに対応していない。
- javascript コードを含んだ HTML 文字列を jsdom に読み込ませると、読み込んだ時点で文字列内の javascript コードが実行される。
- 改行コードを無害な文字列へ変換する
- javascript コードを無害な文字列へ変換し、退避する
- jsdom で処理
- jsdom の処理結果の文字列に元の javascript コードを埋め戻す
- 改行コードをもとに戻す
また、// ~~~ の行を無差別に削除すると、スクリプトコメント以外の文字列も削除してしまうため、これらの問題を回避するようにしている。
// サンプル HTML データ var str = '<html><head><script type="a"><!--\n' +'a;\n' +'//test\n' +'aa;\n' +'//---></script>\n' +'<Script type="b">b;</script>\n' +'</head><body></body></html>'; console.log('== 処理前 =='); console.log(str); var counter = 0; var scrs = new Array(); var matches; // 何度も同じ正規表現を使いまわすのでオブジェクトとして設定 var re = new RegExp('<script.+?</script>','i'); // 無害な文字列へ変換 // 現時点では RegExp.multiline の効果が無いので改行コードを消す必要がある str = str.replace(/[ \t]*[\r\n]+/g,'<!--BR-->'); while(matches = str.match(re)){ scrs[counter] = matches[0]; str = str.replace(re,'<!--SCRIPT'+counter+'-->'); counter++; } console.log('\n== 無害化処理後 =='); console.log(str); // jsdom でレイアウト変更などを処理 var jsdom = require('jsdom'); var document = jsdom.jsdom(str); var res = document.innerHTML; // 元のコードを埋め戻す。 for(var k in scrs){ res = res.replace('<!--SCRIPT'+k+'-->', scrs[k]); } res = res.replace(/<!--BR-->/g,'\n'); console.log('\n== 埋戻し後 =='); console.log(res);
実行結果
$ node sample.js == 処理前 == <html><head><script type="a"><!-- a; //test aa; //---></script> <Script type="b">b;</script> </head><body></body></html> == 無害化処理後 == <html><head><!--SCRIPT0--><!--BR--><!--SCRIPT1--><!--BR--></head><body></body></html> == 埋戻し後 == <html><head><script type="a"><!-- a; //test aa; //---></script> <Script type="b">b;</script> </head><body></body></html>
タグ: Node.js