子プロセスは素晴らしいものですが、注意して使用する必要があります。ユーザー入力の受け渡しは、利用しないのでなければ、サニタイズされていなければなりません。サニタイズされていない入力がシステムレベルのロジックを実行する危険性は無限にあり、リモートコードの実行からセンシティブなシステムデータの漏洩、そしてデータ損失にまで及びます。準備のためのチェックリストは以下のようになります。
- すべての場合でユーザー入力を避け、そうでない場合は検証とサニタイズを行う
- ユーザー/グループアイデンティを利用して、親プロセスと子プロセスの権限を制限する
- 上記が機能しなかった場合の望まない副作用を防ぐために、プロセスを隔離された環境で実行する
const { exec } = require('child_process');
...
// 例として、2つのうち1つがサニタイズされていないユーザー入力であるスクリプトを考えてみましょう
exec('"/path/to/test file/someScript.sh" --someOption ' + input);
// -> ユーザー入力が '&& rm -rf --no-preserve-root /' だった場合に、何が起こるか想像してみてください
// 望まない結果に驚くことでしょう
Node.js child process のドキュメント より:
サニタイズされていないユーザー入力をこの関数に決して渡さないでください。シェルのメタ文字を含んでいるどんな入力も、任意のコマンド実行を引き起こすために利用される可能性があります。