2005-07-15 (Fri)
_ CSRF対策
0.13.0にもCSRF対策のコードはとくにないようだ。 MLの議論を追ってなかったのだが、結局アプリケーション側で対策する べしということだろうか。
まず、ApplicationControllerとApplicationHelperに以下のような記述をしておく。
app/controller/application.rb:
class ApplicationController < ActionController::Base private def validate_session if @params[:session_id_validation] == @session.session_id return true else render(:text => SESSION_VALIDATION_FAILED_HTML, :status => "403 Forbidden") return false end end SESSION_VALIDATION_FAILED_HTML = <<EOF <html> <head> <title>403 Forbidden</title> </head> <body> <h1>403 Forbidden</h1> <p> Session validation failed. </p> </body> </html> EOF end
app/helpers/application_helper.rb:
module ApplicationHelper def secure_form_tag(*args) return start_form_tag(*args) + "\n" + hidden_field_tag("session_id_validation", @session.session_id) end end
あとは、保護が必要な各フォームでstart_form_tagの代りにsecure_form_tagを 使い、
app/views/<controller_name>/edit.rhtml:
<h1>Edit</h1> <%= secure_form_tag :action => 'update', :id => @model_name %> <%= render_partial 'form' %> <%= submit_tag 'Edit' %> <%= end_form_tag %> <%= link_to 'Show', :action => 'show', :id => @model_name %> | <%= link_to 'Back', :action => 'list' %>
各コントローラの必要なアクションにフィルタを設定する。
app/controllers/<controller_name>_controller.rb
class <ControllerName>Controller < ApplicationController before_filter :validate_session, :only => [:create, :update, :destroy] #... end
こんなもんかなあ。
あと、scaffoldはGETでdestoryするようなコードを出力するので、 確認画面を用意してPOSTでdestroyするようにする必要がある。
_ Login GeneratorのSession Fixation Attack対策
今度はSession Fixation Attack(セッション固定攻撃)対策。
RailsはデフォルトでセッションIDを発行するようになっているが、 Login Generatorが生成するコードは、どうも認証後も同じセッションID を使っているようだ。
def login case @request.method when :post if @session[:user] = User.authenticate(@params[:user_login], @params[:user_password]) flash['notice'] = "Login successful" redirect_back_or_default :action => "welcome" else flash.now['notice'] = "Login unsuccessful" @login = @params[:user_login] end end end
このため、Session Fixation Attackの危険性があると思われる。
これを回避するには以下のようにセッションをリセットしてやればよい。
def login case @request.method when :post user = User.authenticate(@params[:user_login], @params[:user_password]) if user return_to = @session[:return_to] @request.reset_session @session = @request.session @session[:user] = user @session[:return_to] = return_to if return_to flash['notice'] = "Login successful" redirect_back_or_default :controller => "page", :action => "list" else flash.now['notice'] = "Login unsuccessful" @login = @params[:user_login] end end end
_ クッキーのパス
Railsではクッキーのパスはデフォルトで/に設定されるようだ。 これは/以外の場所(たとえば/ximapd)で運用する場合は望ましくない。
変更するには以下のようにconfig/environment.rbの末尾に記述すればよい。
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_path] = "/ximapd"
_ セッションファイルの作成場所
Railsではセッションファイルの作成場所はデフォルトで/tmpになる。 *1
/tmpの直下にセッションファイルを作るのはあまり好ましくない。 なぜなら、cronなどで削除した際に、同じファイル名で偽物のセッションファイルを作成できてしまうからだ。
変更するには以下のようにconfig/environment.rbの末尾に記述すればよい。
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:tmpdir] = File.expand_path("session", RAILS_ROOT)
もちろん、ディレクトリのパーミッションには注意が必要。 現在のCGI::Sessionでは、ファイル名からセッションIDを推測できないように なっているが、Railsの実行ユーザ以外はアクセスできないようにしておいた方が いいだろう。
*1 実際には環境による。
2006-07-15 (Sat)
_ to_jsonのSafari対策
この間のコードだと、Safariで文字化けしてしまった。 やっぱり\u記法を使わないといけないようだ。
class String JSON_ESCAPED = { "\010" => '\b', "\f" => '\f', "\n" => '\n', "\r" => '\r', "\t" => '\t', '"' => '\"', '\\' => '\\\\' } def to_json return '"' + gsub(/[\010\f\n\r\t"\\]/) { |s| JSON_ESCAPED[s] }.gsub(/([\xC0-\xDF][\x80-\xBF]| [\xE0-\xEF][\x80-\xBF]{2}| [\xF0-\xF7][\x80-\xBF]{3})+/ux) { |s| s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&') } + '"' end end
もっと速く書ける?
2019-07-15 (Mon)
_ 三瓶山ツーリング
三瓶山まで主に飯石ふれあい農道で行ってきた。最後穴見から波多までの区間が通行止めだったので54号に迂回した以外は快適だった。
純正のハンドルバーエンドの方が疲れないかなと思って戻してみたけど違いがよくわからず。
三瓶バーガーは人が多いので西の原の山の駅でカレーを食べたけど定食の方がおいしそうだった。
_ TrackBack [http://shugo.net/jit/20050716.html#p01 Journal InTime [Rub..]