MENU

コードインジェクション(Code Injection)とは?eval・exec関数の危険性と動的コード実行の脆弱性をわかりやすく解説

コードが動くべき部分に、利用者の入力した文字がそのままプログラムとして実行されてしまう。PHPやPython、JavaScriptで「eval()を使えば手軽に実装できる」と考えた経験がある開発者は少なくないでしょう。しかしそのeval()こそが、コードインジェクションの入口になりえます。

この記事では、コードインジェクション(Code Injection)の仕組み・代表的な発生パターン・防御手順を、現場で使えるレベルで解説します。PHPやPython・JavaScriptでの具体的な発生条件と、設計段階からできる根本的な対策まで取り上げます。

コードインジェクション(Code Injection)とは?eval・exec関数の危険性と動的コード実行の脆弱性をわかりやすく解説 - 解説

目次

コードインジェクションとは?なぜ危険なのか

コードインジェクション(Code Injection)とは、外部から受け取った文字列をアプリケーションが「コード」として解釈・実行してしまう脆弱性です。攻撃者はこの隙間を使い、本来実行されるはずのない処理をサーバー上で動かします。

攻撃が成立するカギは、「動的コード実行関数」の存在です。PHPのeval()、Pythonのexec()/eval()、JavaScriptのeval()などがその代表例で、これらは渡された文字列をそのままプログラムとして解釈します。

なぜ危険なのでしょうか。コードインジェクションが悪用されると、攻撃者はサーバー上で任意のコマンドを実行したり、ファイルを読み書きしたり、バックドアを設置したりできます。影響はリモートコード実行(RCE)と実質的に同等であり、発見・悪用された場合の被害は深刻です。

攻撃の仕組み(敵を知る)

コードインジェクションが成立する3つの条件

コードインジェクションが起きるには、次の3条件が揃う必要があります。

・動的コード実行関数が使われている:eval()、exec()、create_function()(PHP旧式)など
・実行内容にユーザー入力が混入する:GETパラメータ・POSTデータ・Cookieなど
・入力値が検証・サニタイズされていない:そのまま関数に渡される状態になっている

【想定例】PHPのeval()を使った脆弱な実装パターン

以下は教育目的の架空の想定例です。実際にこのようなコードを書いてはいけません。

あるWebアプリケーションが「簡易計算機能」をeval()で実装していると仮定します。

# 【想定例・脆弱なコード】実装してはいけないパターン # $input = $_GET['expr']; // 例: ユーザーが "2+3" を送信する想定 # eval("$result = " . $input . ";"); # echo "計算結果: " . $result; # # → 攻撃者が expr=0; system('cat /etc/passwd'); を送信すると # サーバー上でコマンドが実行される

この想定例では、攻撃者がURLパラメータにexpr=0; system('id');を送るだけで、サーバー上の任意コマンドが実行されます。表示上の計算結果は壊れますが、コマンドの出力が攻撃者に届く経路を別途作られると情報が漏れます。

【想定例】PythonのexecとJavaScriptのevalでも同様に発生する

・Python exec():Webフレームワーク上でユーザー入力をexec(input_str)に渡すと、__import__('os').system('id')のような文字列で任意コマンドを実行できる(想定例)
・JavaScript eval()(Node.js):サーバーサイドのNode.jsアプリでevalにリクエスト値を渡した場合、require('child_process').execSync('id')などで同様の攻撃が成立しえる(想定例)
・PHPの旧式preg_replace /eフラグ:PHP 5系で使えたpreg_replace('/.../e', $input, $str)は置換後の文字列をevalする仕様だったため同種の危険があった(PHP 7.0で廃止済み)

OSコマンドインジェクションとの違い

OSコマンドインジェクションはシェルを呼び出す関数(system、exec、shell_execなど)に悪意のある引数を渡す攻撃です。コードインジェクションは言語ランタイム自体にコードを食わせる点が異なりますが、最終的にOSコマンドを実行させるという「結果」は重なることが多く、どちらも同等の危険性を持ちます。

具体的な防御手順

1. eval・execを設計段階から排除する

最も効果的な対策は、動的コード実行関数を最初から使わない設計にすることです。多くの場合、eval()を使いたくなる場面には、より安全な代替手段があります。

・PHPで数式を計算したい場合:数式パーサーライブラリ(mossadal/math-parserなど)を採用する
・PHPで動的に関数を呼びたい場合:call_user_func()と許可リスト(ホワイトリスト)を組み合わせて、実行できる関数を事前に限定する
・Pythonで設定ファイルを読み込む場合:Pythonコードをexecで読み込む代わりにjson/yamlモジュールで設定を管理する
・JavaScriptでJSONを解析する場合:eval('(' + json + ')')は使わず、JSON.parse()を使う

2. 入力値の厳格なバリデーション

どうしても動的処理が必要な場合は、入力値を厳しく制限します。

・許可リスト(ホワイトリスト)方式:「数字と四則演算子のみ許可」など、期待する形式だけを通す。拒否リスト(ブラックリスト)では想定外のパターンを見逃す危険がある
・型チェックを徹底する:数値として扱うならis_numeric()(PHP)やstr.isdigit()(Python)で事前に検証する
・正規表現で入力を絞り込む:^[0-9+\-\*\/\(\)\.]+$のようなパターンで算術演算子以外を拒否する

ただしバリデーションはあくまで補助策です。eval()のような危険な関数を使い続けることを前提とした対策は根本解決になりません。

3. 実行環境のサンドボックス化と最小権限設定

言語レベルの対策と並行して、OS・コンテナレベルの隔離も有効な多層防御になります。

・最小権限の原則:Webサーバーの実行ユーザーを専用の低権限アカウントにする。root権限で動かさない
・コンテナによる隔離:アプリケーションをDockerコンテナ内で動かし、ホストOSへの影響範囲を最小化する
・SELinux/AppArmor:許可されたシステムコール・ファイルアクセスのみに制限する。想定外のコマンド実行を OS レベルで阻止できる
・アウトバウンド通信の制限:コードが実行されてもC2サーバーへの通信が出ていかないよう、必要な宛先のみを許可するエグレスフィルタリングを実施する

中小企業でも今日からできること

コードインジェクション対策は、高度な設定よりも「書かない・使わない」ことが最大の防御です。まず自社のコードを点検することから始めましょう。

・社内Webアプリのコードにeval()が残っていないか確認する:静的解析ツール(PHPならSASTツール)やgrepでeval(を検索し、使っている箇所を把握する
・古いPHPアプリのバージョンを確認する:PHP 5系で作られたレガシーアプリはpreg_replace()の/eフラグやcreate_function()が残っている場合がある。PHP 8系への移行を検討する
・WAFを導入する:コードインジェクションの典型パターン(eval・execなどのキーワードを含むリクエスト)を検知・ブロックできる。完全な対策にはならないが、第一道として有効
・Webアプリケーション診断を年1回以上受ける:専門家によるセキュリティ診断で、eval()を使った実装の有無やその他のインジェクション脆弱性を包括的にチェックしてもらう

なお、コードインジェクションに似た攻撃としてサーバーサイドテンプレートインジェクション(SSTI)があります。SSTIはテンプレートエンジン(Jinja2・Thymeleaf・Freemarkerなど)を経由してサーバー上でコードを実行させる攻撃で、仕組みは異なりますが被害の大きさは同等です。テンプレートエンジンを使う環境ではあわせて対策を確認しましょう。

よくある誤解と注意点

・「内部システムだから関係ない」は危険:社内向けシステムでも、一度侵害された内部端末から攻撃を受けるリスクがあります。内部システムにも同等の対策が必要です
・「入力値をエスケープすれば大丈夫」は過信:HTMLエスケープやSQLプレースホルダは、eval()に渡す文字列を安全にする目的には設計されていません。エスケープで回避できないパターンが数多く存在します
・「デバッグ用だから一時的に許容できる」は誤り:デバッグ用のeval()が本番環境に残り続けることは珍しくありません。コードレビューでeval()を発見したら、目的を問わず対処を検討してください
・「フレームワークが保護してくれる」は過信:フレームワークはSQL・HTMLの危険を自動で緩和しますが、開発者自身がeval()を呼び出した場合は保護されません

セキュアコーディングの基本原則では、eval()のような動的コード実行を避けることが「入力値を信頼しない(Never Trust Input)」の実践として明確に位置づけられています。コードを書く全員が意識すべき基礎です。

コードインジェクション(Code Injection)とは?eval・exec関数の危険性と動的コード実行の脆弱性をわかりやすく解説 - まとめ

本記事のまとめ

コードインジェクションは「動的にコードを実行する関数にユーザー入力が混入する」ことで成立します。対策の基本は「eval・execを設計から排除すること」であり、どうしても必要な場面では許可リスト方式のバリデーションと実行環境の隔離を組み合わせます。

対策 内容 優先度
eval・exec使用禁止 設計段階で安全な代替手段を採用する 最高(根本対策)
入力バリデーション(許可リスト) 期待する形式のみを通し、それ以外を拒否する 高
最小権限の実行ユーザー設定 Webサーバーを低権限で動かし被害範囲を制限 高
コンテナ・SELinux隔離 OS・ランタイムレベルで実行できる処理を制限する 高
コードレビュー・SAST導入 eval使用箇所を組織的に発見・排除する 中~高
WAF導入 インジェクション試行を検知してブロックする 中(補助策)

PR

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(徳丸浩/SBクリエイティブ)

SQLインジェクション・XSS・CSRFからコードインジェクションまで、Webアプリの脆弱性を体系的に解説した定番書。設計・開発・レビューの各段階で参照できる実践的な内容です。

関連記事をもっと読む

同じテーマの記事をまとめています。あわせて読みたい記事はこちらからご覧いただけます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次