トップ «前の日(07-14) 最新 次の日(07-16)» 追記   RSS 1.0 FEED  

Journal InTime


2005-07-15 (Fri)

_ [Rails] 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するようにする必要がある。

_ [Rails] 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] クッキーのパス

Railsではクッキーのパスはデフォルトで/に設定されるようだ。 これは/以外の場所(たとえば/ximapd)で運用する場合は望ましくない。

変更するには以下のようにconfig/environment.rbの末尾に記述すればよい。

ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_path] = "/ximapd"

_ [Rails] セッションファイルの作成場所

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  実際には環境による。

本日のツッコミ(全1件) [ツッコミを入れる]

_ TrackBack [http://shugo.net/jit/20050716.html#p01 Journal InTime [Rub..]


2006-07-15 (Sat)

_ [Rails] 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)

_ [250DUKE] 三瓶山ツーリング

photo

三瓶山まで主に飯石ふれあい農道で行ってきた。最後穴見から波多までの区間が通行止めだったので54号に迂回した以外は快適だった。

純正のハンドルバーエンドの方が疲れないかなと思って戻してみたけど違いがよくわからず。

三瓶バーガーは人が多いので西の原の山の駅でカレーを食べたけど定食の方がおいしそうだった。