CookieやSessionに関する調査を行うときにcurlやSinatraでテスト用アプリを構築すると便利だったのでメモ。
参考
そもそもsessionとかcookieってなんだ?
- HTTPはステートレスである
- 例えばログインを要するようなサイトの場合、ユーザーがログイン済みであるか否かを管理できないと非常に困る(毎回ログイン画面になってしまう)
- 上記を補うためにHTTPヘッダにCookieという情報が設定できる。HTTPリクエストであれば
cookie: name1=value1; name2=value2
という形で、HTTPレスポンスであればSet-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
というような形で設定できる - cookieはクライアント側で値を保持し、簡単に改ざんができる。そのため、ユーザーは簡単に変更が可能。例えばログイン用のemailアドレスのみcookieで設定されている場合、emailアドレスを知っている人に変えればログインできる可能性が出てしまう(そんな使い方はしないと思われますが)
- sessionでは基本的にサーバーに必要な情報を置いておいてクライアントにはsessionidなどの一意の番号をcookieによってサーバー側に通知する
- 上記によってクライアント側で改ざんができなくなる。また、インターネット上に大切な情報などが流れることもなくなる
サーバー側の設定
OSはAmazon Linux AMI 2016.03.1を利用しましたが、Rubyがインストールされていればある程度どの環境でも良いと思います。
以下のようなプログラムを作成します。
index.rb
require 'sinatra'
set :bind, '0.0.0.0'
set :port, 80
use Rack::Session::Cookie, :key => 'rack.session',
:expire_after => 60,
:secret => Digest::SHA256.hexdigest(rand.to_s)
get '/' do
session[:name] = params['name']
"I only record your name for one minute."
end
get '/read' do
if session[:name].nil? then
"Who are you?"
else
"Welcome #{session[:name]}"
end
end
- Cookieのセッション用のIDのキー名を「rack.session」とし、有効期限は60秒
- GETメソッドでパスが「/」のHTTPリクエストの際にnameというパラメーターを取得しsessionに設定する
- GETメソッドでパスが「/read」のHTTPリクエストの際にsessionのnameから内容を取得し「Welcome hogefuga」と表示する。取得できない場合には「Who are you?」と表示する
以下で80ポートで起動します。
$sudo su
$gem install --no-ri --no-rdoc sinatra
$nohup ruby index.rb &
クライアント側
クライアントから先ほどのサーバーに対してHTTPリクエストを送って確認してみます。curlを使って行います。
# HTTPリクエスト.cookieの内容をローカルファイルに保存
$curl -c cookie.txt http://54.238.161.43?name=toshihirock
I only record your name for one minute
# cookieを指定してHTTPリクエスト
$curl -b cookie.txt http://54.238.161.43/read
Welcome toshihirock
# 有効期限が切れた
$curl -b cookie.txt http://54.238.161.43/read
Who are you?%
最初のリクエストではcurlで-cオプションを指定することでサーバーから返却されるHTTPヘッダのSet-Cookie:
の内容をcookie.txt
というファイルでローカルに保存しています。
# HTTPレスポンスヘッダの内容を表示
$curl -c cookie.txt -D - http://54.238.161.43\?name\=toshihirock
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 39
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.0.0/2015-12-16)
Date: Sat, 28 May 2016 23:50:14 GMT
Connection: Keep-Alive
Set-Cookie: rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTZkODcxNGY2MjZkOTYyYjhiMWNk%0AMzcwNGYwYzEwM2ExYTYxNmY5ZmI4NTBhOTZkM2EzOWI1NzljOGY5MGVmZDQG%0AOwBGSSIJbmFtZQY7AEZJIhB0b3NoaWhpcm9jawY7AFQ%3D%0A--6c865215f0933c3084b0a27241f95ce5080e889d; path=/; expires=Sat, 28 May 2016 23:51:14 -0000; HttpOnly
I only record your name for one minute.%
$cat cookie.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
#HttpOnly_54.238.161.43 FALSE / FALSE 1464479474 rack.session BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTZkODcxNGY2MjZkOTYyYjhiMWNk%0AMzcwNGYwYzEwM2ExYTYxNmY5ZmI4NTBhOTZkM2EzOWI1NzljOGY5MGVmZDQG%0AOwBGSSIJbmFtZQY7AEZJIhB0b3NoaWhpcm9jawY7AFQ%3D%0A--6c865215f0933c3084b0a27241f95ce5080e889d
HTTPレスポンスのヘッダの「Set-Cookie」の内容についてフォーマットは違いますが、ローカルファイルのcookie.txtに保存されていることが分かります。
HTTPリクエストでHTTPヘッダにCookieの情報を付与するためには-bオプションを利用しています。
$curl --verbose -b cookie.txt http://54.238.161.43/read 1> /dev/null
* Trying 54.238.161.43...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 54.238.161.43 (54.238.161.43) port 80 (#0)
> GET /read HTTP/1.1
> Host: 54.238.161.43
> User-Agent: curl/7.43.0
> Accept: */*
> Cookie: rack.session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTM0NGYxOTY0YWNhMjQxMTZkYWRm%0ANTQ2YTEzMzIzNzZlY2UwOTYzOWY2YjNkMjJmNThmZTExYzc0NzViNmIxMjUG%0AOwBGSSIJbmFtZQY7AEZJIhB0b3NoaWhpcm9jawY7AFQ%3D%0A--b3958804643cc39ecb1e2b87b35c8777d2fd008a
>
リクエストヘッダに「Cookie:」としてrack.sessionの値が指定されているのが確認できました。
Cookieの仕様については以下を参考にさせて頂きました。
上記のようにサーバークライアント間ではrack.sessionという情報のみをCookieとして共有し、必要な情報(今回の場合にはnameの値)についてはサーバー側でsession情報をとして保持していることが確認できました。