Javascriptで文字列になった計算式の結果を求める方法

2019年10月15日

Javascript テクノロジー プログラミング

エクセルがこれほど使われている理由の大きな要因の一つに「セル内に掛ける計算式」があると思います。 これがなくて、単なる数値や文字列を書き込むだけのテーブルツールであったとしたら、エクセルはここまでビジネスに定着しなかったに違いないでしょう。 簡単な計算式や、別セルの動的な値をその場ですぐに計算して表組みに表わしてくれるこの働きっぷりは、ビジネスの現場で非常に有用なRPAとも言えるでしょう。 もしエクセルのこの機能がまだ世の中になかったら、いつも普通に電卓を叩いているサラリーマンが多かったでしょうね。

PHPのevalは危険と言われているけど便利

セキュリティ的によろしくないとされているphpのeval関数ですが、文字列で書かれたプログラムをその場で実行してくれるので、configデータとの連携や、文字列で書かれた計算式の実行などとして、非常に便利に活用できます。 ただ、URLクエリの文字列をそのまま実行するような簡易プログラムを作ってしまうと、CGIというWEBブラウザから見るとブラックボックスになっている箇所に、好きなプログラムを実行させてしまうことが可能になり、知識のある人であれば、簡単にサーバーを乗っ取ることもできます。 そうならないために、eval実行する文字列を限定的にするように精査しないと、正直言って使ってはいけないレベルの関数と言ってもいいでしょう。 実は今回、javascriptにもevel関数というのがあるのですが、これもphpと同様に脆弱ということで、使ってはいけないレベルになっているため、evalを使わずに手軽に文字列式の結果を得る方法が無いか探してみました。。

文字列数式を計算する機能

単純に言うと、エクセルの様な機能を作ろうとしていて、とある入力フォームで、数値を入れたて、自動計算して、結果を保存していくシステムで、入れる数値も、計算式にしたいという要望があり、エクセルのように"=1+1"のように=プレフィックスを入れて数値なのか計算式なのかを判別して、計算式の場合は、値を表示するという機能にしたいのですが、 javascriptには、eval以外となると、以下のような方法を使うやり方があるようです。 var calc_string = "1+2+3+4"; var result = Function('return ('+calc_string+');')(); console.log(calc_string); > 10 なんとなく非常に簡単にできて興ざめですが、普段あまり使わないFunction関数を使うことで、簡単に実現できるようです。 でも、このやり方を使っても、calc_stringに、普通にjsコードを記述すると、Function関数内で実行されてしまうので、evalと同じぐらいの脆弱である気がするのですが・・・

セキュリティ対策を考える

結局の所、Functionを使ってもevalを使っても同じぐらいの脆弱なのであれば、calc_stringの文字列部分をちゃんとチェックした方がいいという結論になり、以下のような正規表現を作ってみました。 var calc_string = "1+2+3+4"; calc_string.match(/[^0-9\+\-\*\/~\(\)\{\}\.]/g); > null var calc_string = "console.log('hoge')"; calc_string.match(/[^0-9\+\-\*\/~\(\)\{\}\.]/g); >(16) ["c", "o", "n", "s", "o", "l", "e", "l", "o", "g", "'", "h", "o", "g", "e", "'"] 数式で登場する文字列だけであれば、"null"が返り、それ以外の文字列が含まれていれば、配列が返るようになっています。 数値、加減商積、"."ピリオド以外の文字列が入るjavascriptの計算関数などを入れたい場合は、追加してもいいのですが、キリがないので、今回は数値計算のみの対応にしてみました。 これだけでも、かなりセキュリティ的には安定しますよ。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。