evalを使うとrubocopから以下の警告が出る
C: Security/Eval: The use of eval is a serious security risk.
evalの動作
evalとはそもそもどんな動作をするのか?
文字列 expr を Ruby プログラムとして評価してその結果を返します。
module function Kernel.#eval より
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/eval.html
evalの引数に与えた文字列をrubyプログラムとして実行してくれる。
a = nil
eval('a = RUBY_RELEASE_DATE')
p a #=> "2007-03-13"
便利。
なぜevalを使うことがリスクなのか(私的解釈)
rubocopから「The use of eval is a serious security risk.」の警告をもらった時は、なにがリスクなのか分からなかった。
しかし、よくよく考えてみると以下のことをリスクと言っているのではないかと思ったのでまとめる。
読みにくい
evalを使う場合と使わない場合を比較してみる。
def fuga
p 777
end
# 実行
fuga
=> 777
eval('def fuga;p 777 end')
fuga #=> 777
普通に書いてある方が読みやすいように思う。
悪意あるコードが生成される可能性がある
外部のファイルを読み込むeval
eval('raise RuntimeError', binding, 'XXX.rb', 4)
#=> XXX.rb:4: RuntimeError (RuntimeError)
# from ..:9
外部のデータからコードを生成し実行する場合、悪意あるコードが生成されないように細心の注意を払う必要がある。
上記は外部のファイルを読み込んでいるが、他にもDBとかユーザの入力とか、外部のデータからコードを生成して実行することもできる。
しかし、evalを使わないで書く場合と比べて読みにくいので、どのデータがどのように加工されるか覚えておいたり理解したりは難しい。なので悪意あるコードが実行される可能性が高くなる。
まとめ
evalを使ったコードは、多彩な動きができるためその動きを把握しにくいので悪意あるコードが生成される可能性があること、また読みにくいのでそれに気付きにくいということが「リスク」なんだと考えた。
evalを使わずに済むなら使わないで実装を行いたい。