net/http で Rails application の動作チェックをする ; POST
rb ファイルを使って Rails app に POST した時の挙動をチェックする
セキュリティ的にズル抜けなので、参考になる部分は薄いと断言
前提条件
rails g scaffold name:string email:string password:string rake db:migrate
がされている。
次のレコードも用意されている。
name | password | |
---|---|---|
matsu | matsu@matsu.jp | ustam |
sqlite> select name, email, password from users; matsu|matsu@matsu.jp|ustam
次のレコードを rb ファイルで POST して app 側で save してもらう
name | password | |
---|---|---|
mat5L1 | mat5L1@matsu.jp | what |
controller の準備
application_controller で、authenticity_token の verify を skip する。
これをしないと HTTP セッション がリセットされてしまう[1]
app/controller/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery with: :exception skip_before_filter :verify_authenticity_token end
rb ファイルの作成
次のコードを書いて、実行する。
実行した結果
sqlite> select name, email, password from users; matsu|matsu@matsu.jp|ustam mat5L1|mat5L1@matsu.jp|what
コードの中で大まかにやっていることは以下の通り
- URI の Parse
- GET /users (index) 処理 (これを通さないと、POST できない <= session に token が無いから)
- Cookie 中の、Session に関る部分を取ってくる
- header に Cookie 情報など諸々入れる。
- POST /users (create) 処理
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'net/http' require 'uri' getAndPostUri = 'http://localhost:3000/users' # 1 uri = URI.parse(getAndPostUri) res = Net::HTTP.start(uri.host, uri.port) { |http| response, data = http.get(uri.request_uri) # 2 cookie = response.response['set-cookie'] # 3 ###### body = 'user[name]=mat5L1&user[email]=mat5L1@matsu.jp&user[password]=what' headers = { # 4 'Cookie' => cookie, 'Referer' => getAndPostUri, 'Content-Type' => 'application/x-www-form-urlencoded', } http.post(getAndPostUri, body, headers) # 5 }
[1]
何らかの突貫チェックぐらいなら、一時的にはいいかもしれない。
全コントローラに渡って verify_authenticity_token を skip しているので、色々とマズい。
ruby-2.0.0-p353\@mygemset/gems/actionpack-4.0.2/lib/action_controller/metal/request_forgery_protection.rb の中を見ると,次のようにすれば上手くいくらしい
"header に X-CSRF-Token が あり、それが form_authenticity_token と合致していること"
試行錯誤した物の(X-CSRF-Token に Base64.decode64/Marshal.load したりと)上手くいかず、結局こうなった
以下、そのコード
ruby-2.0.0-p353\@mygemset/gems/actionpack-4.0.2/lib/action_controller/metal/request_forgery_protection.rb 173 # The actual before_action that is used. Modify this to change how you handle unverified requests. 174 def verify_authenticity_token 175 unless verified_request? 176 logger.warn "Can't verify CSRF token authenticity" if logger 177 handle_unverified_request 178 end 179 end 180 181 # Returns true or false if a request is verified. Checks: 182 # 183 # * is it a GET or HEAD request? Gets should be safe and idempotent 184 # * Does the form_authenticity_token match the given token value from the params? 185 # * Does the X-CSRF-Token header match the form_authenticity_token 186 def verified_request? 187 !protect_against_forgery? || request.get? || request.head? || 188 form_authenticity_token == params[request_forgery_protection_token] || 189 form_authenticity_token == request.headers['X-CSRF-Token'] 190 end
参考
CSRF
http://qiita.com/naoty_k/items/b40b13735fd7f06f8cb7
session/cookie
http://qiita.com/labocho/items/32efc5b7c73aba3500ff
net/http