LoginSignup
3
0

More than 3 years have passed since last update.

Rubyで外部コマンドを実行する

Last updated at Posted at 2020-08-04

概要

Rubyで外部コマンドを実行するときの関数について、それぞれ実行して試しました。
自分用メモです。

動機

安全なWebアプリケーションの作り方 のOSコマンド・インジェクションの項で、
Rubyの場合どうなるか興味を持った

実行環境

Ruby2.5.1

試してみた

  • Kernel.#system

systemはsystem(コマンド)のように直接コマンドを打つことと、
system(コマンド, パラメータ)のように指定することができる

子プロセスが終了ステータス 0 で終了すると成功とみなし true を返します。それ以外の終了ステータスの場合は false を返します。コマンドを実行できなかった場合は nil を返します。

引数のコマンドをサブプロセスで実行するのが特徴。

$system("echo test")
test
=> true

$system("echo test ; echo test2")
test
test2
=> true
$system("/bin/echo","test")
test
=> true

$system("/bin/echo","test; echo test2")
test; echo test2
=> true

後者の場合、パラメータ内のセミコロンが文字列として処理されている。
OSコマンドインジェクションの対策に有効。

  • Kernel.#exec

systemと似ている。

プロセスの実行コードはそのコマンド(あるいは shell)になるので、起動に成功した場合、このメソッドからは戻りません。

こちらは実行中のプロセスが置き換わるので、返り値を持たない。

$exec("echo test ; echo test2")
test
test2
$exec("/bin/echo","test; echo test2")
test; echo test2

外部コマンドが実行できる(できてしまう)例

他の関数で外部コマンドを実行することはあるのだろうか?

  • Kernel.#open
$open('|/bin/echo test;').read
=> "test\n"

このように、引数の中にパイプを組み込むことで外部コマンドを実行できてしまう。

File.openを使えばエラーが出る。

$File.open('|/bin/echo test;').read
Errno::ENOENT: No such file or directory @ rb_sysopen - |/bin/echo test;

まとめ

systemやexecといった関数を使うときはOSコマンドインジェクションに配慮して実装をする
→外部から入力された文字列をコマンドラインのパラメータに渡さない
→system関数に第二引数を追加する

open関数は外部コマンドを実行される危険があるので、File.openに置き換えるのが望ましい

参考ページ

Ruby リファレンスマニュアル
https://docs.ruby-lang.org/ja/latest/doc/index.html

Rails セキュリティガイド
https://railsguides.jp/security.html

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0