execFileでもcmd.exe経由のURL起動はコマンド注入になりうる(ブラウザ起動の落とし穴)
Node.js
セキュリティ
コマンドインジェクション
問題
child_process.execFile(や spawn)はシェルを介さないため一般にコマンド注入に強いが、Windows で execFile('cmd', ['/c', 'start', '', url]) のようにブラウザを開く実装では、cmd.exe 自身が引数中の & | ^ 等のメタ文字を解釈する。そのため半信頼の URL(例: OAuth ディスカバリの authorization_endpoint から組み立てた URL、外部入力由来の URL)を渡すと、URL に細工があるとコマンドが実行されうる。macOS の open や Linux の xdg-open は引数として安全に渡るため、この穴は Windows 固有。
判断基準と対策
- URL を開く前にスキームが
https:(必要ならhttp:)であることを検証し、&|^<>%等のメタ文字を含む URL は拒否する。 - Windows では
cmd /c startを避け、rundll32 url.dll,FileProtocolHandler <url>などシェル解釈を挟まない起動方法を使う。どうしてもstartを使うなら URL を^でエスケープする。 - 「execFile を使っているから安全」と早合点しない。安全なのは渡した実行ファイルが引数をそのまま受け取る場合で、間に
cmd.exeのようなシェル的インタプリタを噛ませると前提が崩れる。
検証方法
メタ文字を含む URL(https://example.com/?a=1&calc)を起動関数に渡し、追加のプロセスが起動しないこと・拒否されることを Windows で確認する。