はじめまして、ジョニー・デップに激似の山口(@tadasy)と申します。

僕はPeXという部署で働いておりまして、
PeXpaycaグルピの運営に携わっております。

ECナビではサービスを作るときは、よくPHPを使われるのですが、
PerlやPython,Rubyなどで構築されているサービスもちょいちょいあります。

僕が所属しているPeXという部署でも、主力サービスであるPeXはPHP(symfony)で構築されていますが
payca、グルピはRuby(Ruby on Rails)で構築しました。

そのRailsのwebアプリケーションを構築・運用していく中で、セキュリティ的に気をつけたポイントを
何回かにわけて心折れるまで(おそらく2,3回)書いていこうと思います。

というわけで第1回はログファイルについてです。

ログファイルのセキュリティ?

ログファイルのセキュリティって言われてもあまりピンとこないかもしれませんが、Railsではproduction環境でもデフォルトで、HTTPのパラメータが全部ログに出力されてしまうとこです。そりゃもう全部です。
ログイン画面のパスワードはもちろん、会員情報登録画面の個人情報も当然、ログファイルの書かれます。

せっかくDBに会員パスワード情報を復号できない形でハッシュ化して保存していても、ログファイルに書かれてしまったら、もろもろ台無しです。

回避方法

action packのaction_controllerには filter_parameter_logging というクラスマクロが定義されています。
これを使うことでログファイルへの書き出しを抑止できます。

上記のように記述するとログファイルに記載される該当するパラメータ値が[FILTERED]という文字に置き換えられます。

  • filter適用前のログファイル
  Parameters: {..."user"=>{"password_confirm"=>"naisho", "last_name"=>"石鍋", "password"=>"naisho", "login"=>"loginid", "first_name"=>"太郎"}...}
  • filter適用後のログファイル
  Parameters: {..."user"=>{"password_confirm"=>"[FILTERED]", "last_name"=>"石鍋", "password"=>"[FILTERED]", "login"=>"loginid", "first_name"=>"太郎"}...}

適用後のログファイルをみると"password_confirm"というパラメータも置き換得られていることがわかります。
これは、
filter_parameter_logging :password
と書くことで
/password/i

という正規表現でパラメータ名をチェックされるためです。

詳しい使い方

詳しい使い方についてはaction_controller/base.rbにfilter_parameter_logging定義されていますので
そちらのコメント欄が参考になります。
一応コメントを引用しておきます。

# Replace sensitive parameter data from the request log.
# Filters parameters that have any of the arguments as a substring.
# Looks in all subhashes of the param hash for keys to filter.
# If a block is given, each key and value of the parameter hash and all
# subhashes is passed to it, the value or key
# can be replaced using String#replace or similar method.
#
# Examples:
#   filter_parameter_logging
#   => Does nothing, just slows the logging process down
#
#   filter_parameter_logging :password
#   => replaces the value to all keys matching /password/i with "[FILTERED]"
#
#   filter_parameter_logging :foo, "bar"
#   => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
#
#   filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
#   => reverses the value to all keys matching /secret/i
#
#   filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
#   => reverses the value to all keys matching /secret/i, and
#replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
ブロックも渡せるらしく、かなり柔軟な使い方ができそうですが
特に使い道が思いつかないので、今はシンプルに利用しています。


注意
Rails3系ではfilter_parameter_loggingはdeprecatedになっており、別の使い方が推奨されているようです。