2026年3月29日日曜日

🚫eval関数がどれだけ危険だというのか?

 

危険と言われているのはEVAL Injection 動的評価コードにおける「ディレクティブの不適切な中和」が原因とされる

ソフトウェアが上流コンポーネントから入力を受け取るが、動的評価呼び出し(evalなど)で入力を使用する前にコード構文を中和(neutralizes)していない、または誤って中和している。

中和とはこういうやつか

インジェクションの問題は、多種多様な問題を含んでいます。このため、これらの弱点について議論する最も効果的な方法は、それらをインジェクションの弱点として分類する明確な特徴に注目することです。最も重要な問題は、すべてのインジェクション問題には共通点があるということです--すなわち、制御プレーンのデータをユーザーが制御するデータプレーンにインジェクションすることができるということです。
つまり、正当なデータ・チャネルを通してコードを送り込むことで、プロセスの実行を変更することができるのです。
バッファオーバーフローや他の多くの欠陥が、実行を得るために何らかの問題をさらに利用することを伴うのに対し、インジェクション問題はデータを解析するだけでよい。このカテゴリーの弱点の最も古典的な例は、SQLインジェクションとフォーマット文字列脆弱性である。

https://cwe.mitre.org/data/definitions/94.html

たくさんあるインジェクション

CVE-2022-2054
Python コンパイラが eval() を使って悪意のある文字列を Python コードとして実行する
CVE-2021-22204
チェーン: EXIF プロセッサコードの正規表現が文字列の終端を正しく決定しておらず (CWE-625)、eval インジェクション (CWE-95) を可能にしていました。
CVE-2021-22205
連鎖: バックスラッシュの後に改行が続くと、検証ステップ(CWE-20)がバイパスされ、evalインジェクション(CWE-95)が可能になる。
CVE-2008-5071
PHP プログラムにおける eval インジェクション。
CVE-2002-1750
Perl プログラムにおける eval インジェクション。
CVE-2008-5305
Perl プログラムにおける、ハイフンと数字のみを含むべき ID を使用した Eval インジェクション。
CVE-2002-1752
Perl の eval 関数へのダイレクトコードインジェクション。
CVE-2002-1753
Perl プログラムへの eval インジェクション。
CVE-2005-1527
Perl eval 関数へのダイレクトコードインジェクション。
CVE-2005-2837
Perl eval 関数への直接コードインジェクション。
CVE-2005-1921
MFV. ネストされるべきではないネストされた構造を使用した、PHP eval 文へのコードインジェクション。
CVE-2005-2498
MFV. ネストされるべきではないネストされた構文を使用した、PHP eval 文へのコードインジェクション。
CVE-2005-3302
フォーマットされたファイルのフィールドから Python の eval 文へのコードインジェクション。
CVE-2007-1253
Python プログラムにおける eval インジェクション。
CVE-2001-1471
チェーン: eval インジェクションの結果。無効な値によって変数の初期化が妨げられ、攻撃者によって変更され、 後で PHP の eval 文にインジェクションされる可能性があります。
CVE-2007-2713
チェーン: リダイレクト後の実行が eval インジェクションを誘発する。

javascriptではハッキリと「eval() は危険だから使わないでください!」とまで言っている。

eval() は呼び出し元の権限で渡されたコードを実行する危険な関数です。悪意のある第三者に影響を受ける可能性のある文字列で eval() を実行すると、あなたのウェブページ / 拡張機能の権限でユーザーのマシン上で悪意のあるコードを実行してしまう可能性があります。

たばこの注意書きのようにあからさま、じゃなぜ存在するんだ?必要悪?

たばこの煙は、あなたや周りの人が肺がん、虚血性心疾患、脳卒中になる危険性を高めます。

https://www.marlboro.jp/login.html?resource=%2Fcontent%2Fpmj%2Fmarlboro%2Fhome.html&$$login$$=%24%24login%24%24&j_reason=unknown&j_reason_code=unknown

eval「俺に触れるんじゃねえ」( 力を封印している)

ほとんど、「あなたの事食べちゃうから逃げなさい」という森のくまさんのような矛盾した存在のeval。もしくは自意識過剰。

主人公が森を出る途中にばったりと熊に出会い、(お互いに見合ってという部分がある歌詞もある)君は逃げないのか? 銃を持っていないようだけどと熊から言われて、主人公が走り出して熊が追いかけてくる。

「漆黒の翼」というキャラを演じる、「中二病」の男子生徒。オカルト部所属。水色の髪に小柄で華奢な体格が特徴で、腕にはファッションで包帯を巻く(本人曰く力を封印している)。

そもそもの話、LISPから登場したeval

LISPはevalが最初に登場した言語である。evalの実装によって、最初のLISPインタプリタが現れたのである。それ以前は、LISPの式はコンパイルされていた。しかし一度evalが実装されると、それは単純な入力・評価・出力のループ (REPL) の一部として使われるようになり、最初のLISPインタプリタの基礎を形作った。LISPの後のバージョンのevalはコンパイラとしても実装されている。

悪いのはEvalなんだろうか?

Rubyはevalにスコープ要素を入れることで何かを免罪(包帯をまく)しようとしている。

重要な点として、IASマシンはプログラムとデータをひとつのメモリに混在させることを意図したほぼ最初の設計である。

MDNではfunctionを代わりにつかってくれという。

function looseJsonParse(obj){
   return Function('"use strict";return (' + obj + ')')();
}
console.log(looseJsonParse(
  "{a:(4-1), b:function(){}, c:new Date()}"
))

人々はなぜこれほどまでに危険といわれているevalを後世に残そうとするのか?

私達は火薬庫の中を静電気にすら注意して歩くのに、アンタたちはタバコをフカして歩けと言う。

https://amzn.to/3Gso611

LISPについては、bootstrap問題の解消ということがある。

ブートストラップ問題 (Bootstrap problem) は、コンパイラをコンパイル対象のプログラミング言語で作成した際に、そのコンパイラの最初のコンパイルをどうするかといった場合を典型的な例とする、いわゆる「鶏と卵」の形をしたセルフホスティング環境の問題を指す。これを解決するための方式をブートストラップ方式といい、この問題を何とかして最初の完備した環境を作ることをブートストラッピングという

コンパイラをコンパイラコンパイラゆうてもーキー

この本によるとjavascriptはScheme(LISP系)に影響を受けているからそのままevalも引き継いだのかもしれない

evalについても前向きに書いてある。ブレンダンアイク(通称剃刀アイク)師匠は語る

完全な動的スコープというのは入れてませんでした。ストールマンはEmacsにとって重要なものだとこだわって、Elispをそれで満たしましたが。Javascriptは概ね静的スコープを持ち、多少変則的なところがあります。非常に動的になる抜け穴があるのです。グローバルオブジェクトと、with文と、evalです。しかしmy以前のPerlのダラー変数や、Tclのupvarやuplevelみたいなのとは違います。90年代にはそんなのがたくさんあって、流行だったのです。(ブレンダン・アイク coders at workP138)

この短時間にevalの可能性をemacsとperlをディスりで挟み込むという抜群な切れ味を見せる剃刀アイク先輩。しかし、どういうつもりでjsにeval関数が残っているかは、そのあとの影響を受けた言語などからもわかる。あと創始者が認めてもmdnはevalを即廃止したい勢い。


Netscapeの経営陣はすぐに、アイクがJavaに似た構文を持ち、Schemeや他の既存のスクリプト言語に似ていない新しい言語を考案することが最良の選択肢だと判断しました。

いいぞ、ネスケ経営陣。英断だ

(define (eval-with-x prog a b)
 (let ((at-a (eval `(let ((x ',a)) ,prog)))
       (at-b (eval `(let ((x ',b)) ,prog))))
   (- at-b at-a)))

C言語にはevalはない、それはなぜか

LISPの流れをくまない限り、みんなSHELLにEVALを参考にしてevalを組み込んだのだろうか、そして、shellほど権限やコンテクストがしっかりしていないので、evalを使うなと生み出しておいて君たちは後から危険だと言うのか。シザーハンズ

C言語にはeval関数が直接的に存在しないのにはいくつかの理由が考えられます。

  1. 低レベル言語の性質: Cは低レベルの言語であり、メモリ管理や直接的なハードウェアアクセスが可能です。このような言語において、ランタイム時に任意のコードを動的に評価・実行するevalのようなメカニズムは、安全性の観点からリスクが高いです。

  2. コンパイル方式: Cはコンパイル言語であり、ソースコードは実行前に機械語にコンパイルされます。evalは通常、インタプリタ言語で頻繁に使用される機能であり、ランタイム時に動的にコードを解釈・実行することが容易なインタプリタの特性と相性が良いです。

  3. 複雑性evalを適切に実装するには、Cのランタイムにコンパイラやインタプリタの一部を組み込む必要があります。これは非常に複雑で、Cのシンプルさや効率性に影響を与える可能性があります。

  4. 安全性: 上述したように、evalを使用すると任意のコードが実行されるため、セキュリティ上のリスクが高まります。不正なコードや意図しない動作を引き起こす可能性があるため、特に低レベル言語のCにおいては、このような機能が避けられることが多いです。

  5. 特定の目的: C言語は主にシステムプログラミングや組み込みプログラムの開発のために設計されました。このような用途では、evalのような動的コード実行機能はあまり求められないことが多いです。

もちろん、特定の状況や要求に応じて、Cで自前のevalのような機能を実装することは技術的に可能です(例: 外部のコンパイラを呼び出してコードをコンパイル・実行する)。しかし、C言語の設計思想や用途を考慮すると、標準ライブラリにevalが含まれていないのは理解しやすいでしょう。

Phpは警告レベルで非推奨、でもちゃあんと使えるけどね

警告
eval() は非常に危険な言語構造です。 というのも、任意の PHP コードを実行できてしまうからです。 これを使うことはおすすめしません。 いろいろ検討した結果どうしても使わざるを得なくなった場合は、細心の注意を払って使いましょう。 ユーザーから受け取ったデータをそのまま渡してはいけません。 渡す前に、適切な検証が必要です。

Perlは禁止することはないみたいだった。

さすがラクダのperl。ね、なんでもできるでしょ、といった感じ