Ruby CGI で Insecure operation error

  • ????????????????????

久しぶりの ruby ネタ。以下のような ruby CGI で 500 internal error が出た。

#!/usr/bin/ruby

require "cgi"
cgi = CGI.new
params = cgi.params

open(params["filename"],"w") { |f| f.puts "hoge" }
cgi.out { "hoge" }

apache のログを見てみるとファイルを作成する部分 (open) で Insecure operation というエラーが出ている。

いろいろ調べてみると、どうやら ruby CGI で URL のパラメータを使ったパス名でファイルを書き込もうとしたことが原因のようだ。パス名に空白とか入っていると悪さができそう、ということらしい。ごもっともです。

セーフレベル

Ruby にはセーフレベルというのがあって、それに引っかかっているようなので、レベルを下げようとして

$SAFE=0

とやったら、勝手に下げちゃだめ!というエラーが出た。これを下げようと思うと、例えば httpd.conf のような設定ファイルを使って下げないとダメらしい。

汚染されていないことを宣言する String::untaint メソッド

自分だけで使う簡単な CGI だから堅いこと言わないでよ、というときは (SQL とか使うのはすこし大げさに感じる場合) は,String クラスの untaint メソッドを使うと一応解決する。

untaint というのは「汚染されてない」みたいな意味らしく、 untaint メソッドを使うことでその文字列が汚染されていないことを (プログラム作成者が) 宣言し、Insecure operation error を回避するという感じ。要するにこれは責任の所在は ruby のセキュリティーホールじゃなくて、プログラマー自身にありますよ、ということのようだ。

例えば以下のような感じらしい。もちろん、このチェックが万全かどうかは保証しません。

require "cgi"
cgi = CGI.new
params = cgi.params
filename=params["filename"]

# 適当なチェック (空白とハイフンとピリオド禁止!)
if filename.match(/^([\w.-]+)$/)
  raise "filename #{filename} has invalid characters"
end

# こうすることで Insecure operation エラーを回避可能
filename.untaint

open(params["filename"],"w") { |f| f.puts "hoge" }

もちろん、セキュリティ的にはよくなさそうなので、webに公開する場合はNGの方法だと思う。他にいい方法はないのでしょうか?

はてなブックマーク - Ruby CGI で Insecure operation error
Pocket