Javascriptの文字列コードをセキュアに実行するやり方

こんにちわ。
セキュアに目がない、下駄です。
プログラミングをする以上、セキュアを追求する必要があります。
仕事で作るプログラムはもちろんですが、インターネットで公開するプログラムは、想定できるセキュアな状態にするというのがあるべき姿であることは、誰でも理解していると思いますが、
でも、セキュアって一体何?どうすればいいの?なにが危険なの???という意見もありそうなので、その答えとして、自分の知らないセキュア対応はできないという事で、やはりスキルアップしていくしかないですよね。
前回、eval関数を使ってはいけないという事をブログに書きましたが、今回は、そのeval処理を最もセキュアにする方法を追求したいと思います。
前回が、概念編だとすると、今回は実行編です。
前回のおさらい
電卓アプリなどを作っている時に、”1+1″という文字列の式を実行させたいがために、
1 2 3 |
let res = eval("1+1"); > res : 2 |
という風に記述しがちだけど、
1 2 3 |
let res = Function("return " + "1+1")(); > res : 2 |
・・・と、しましょう!と書きましたが、実はこれだけでは不十分で、簡単にページ内のグローバル変数やエレメントに対してアクセスできてしまいます。
1 2 3 |
let res = Function("console.log(window)")(); ・・・グローバル関数や変数にアクセス可能・・・ |
iframeを使えばいいじゃないか!
ページ内でiframeタグを作って、その中でjavascriptを実行して、その結果を受け取ったら、iframeを消してしまえばいい!という事を思いつきやってみた。
1 2 3 4 5 6 7 8 |
let code = "1+1"; let iframe = document.createElement("iframe"); document.body.appendChild(iframe); let res = iframe.contentWindow.Function('"use strict";return '+ code)(); iframe.parentNode.removeChild(iframe); console.log(res); > 2 |
解説すると、iframeを作って、body直下に一時的にappendします。
その後、contentWindowにアクセスして、Function関数でコードを実行します。
この時に、さらにセキュアになるように厳格モードのuse strictをセットしておきます。
結果を受け取ったら、iframeはさっさと削除。
以上です。
&nbdp;
どうですか?簡単にできましたね?
拡張して汎用性アップ
もっと汎用性を足してみましょうか。
1 2 3 4 5 6 7 8 9 10 11 |
let code = "1+1"; let iframe = document.createElement("iframe"); document.body.appendChild(iframe); try{ let res = iframe.contentWindow.Function('"use strict";return '+ code)(); console.log(res); } catch(ex){ console.log(ex.message); } iframe.parentNode.removeChild(iframe); |
お決まりのtry~catchでくくってみました。
これで、コードがjsエラーになる場合でも、プログラムが停止せずに、エラー表示をしてくれる処理がされます。
最後にお願い
iframeからparentNodeをたどると、current-windowにアクセスできるという事は今回は目をつぶってください。
どうしてもそこまで厳密に塞ぎたい場合は、parentNodeが含まれたコードでエラーを出すというようなやり方もありかもしれませんね。
どんどん膨らむプログラムにうんざりする人もいるかもしれませんが、セキュアコードは、こうして、セキュリティホールが見つけられたら、積み上げて作り込んでいくもんだと認識しないといけないかもですね。
逆に、これを突破できるコードを思いついた方は、コメントください。