Swiftのコマンドインジェクション

Swiftのコマンドインジェクション

説明

Process でシェルを起動し、-c の後にユーザー入力を渡すと、入力がシェルの構文として解釈され、任意のコマンドが実行されるおそれがあります。シェルを使わない場合でも、実行ファイルのパスやプログラムのオプションをユーザーが制御できると、意図しない処理につながります。

想定される影響

  • 任意のコマンドの実行。
  • ファイルの読み取り、削除、外部への送信。
  • サーバーや開発者の端末での権限の悪用。

対処方法

  1. -c によるシェル実行を避け、実行ファイルは固定のパスで指定してください。
  2. 引数を Process.arguments の配列で分離し、各値を許可リストで検証してください。
  3. シェル文字列の組み立てが避けられない場合は、実績のあるエスケープ関数を使い、実行権限を最小限にしてください。

例

変更前

swift
let command = readLine()!
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", command]

変更後

swift
import Foundation

func runGitStatus(for path: String) throws {
    let task = Process()
    task.executableURL = URL(fileURLWithPath: "/usr/bin/git")
    task.arguments = ["status", "--", path]
    try task.run()
    task.waitUntilExit()
}

解説:

  • 変更前: この設定でプロセスを実行すると、入力全体がシェルコマンドとして解釈されます。
  • 変更後: 実行ファイルとサブコマンドを固定し、ユーザーの値を -- の後に渡すことで、シェルによる解釈とオプションインジェクションを防ぎます。

参考資料