SinatraとcurlでSessionやCookieに関する調査をした時のメモ

CookieやSessionに関する調査を行うときにcurlやSinatraでテスト用アプリを構築すると便利だったのでメモ。

# 参考

+ [Sinatraの使い方あれこれ](http://qiita.com/weed/items/7c83a795e37bdf52cfef)

# そもそもsessionとかcookieってなんだ?

[セッションとクッキーの違い](http://ohs30359.hatenablog.com/entry/2015/09/04/235027)

+ 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ポートで起動します。

```bash
$sudo su
$gem install --no-ri --no-rdoc sinatra
$nohup ruby index.rb &
```

# クライアント側

クライアントから先ほどのサーバーに対してHTTPリクエストを送って確認してみます。curlを使って行います。

```bash
# 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`というファイルでローカルに保存しています。

```bash
# 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オプションを利用しています。

```bash
$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の仕様については以下を参考にさせて頂きました。

[Cookie仕様 日本語訳](http://www.futomi.com/lecture/cookie/specification.html)


上記のようにサーバークライアント間ではrack.sessionという情報のみをCookieとして共有し、必要な情報(今回の場合にはnameの値)についてはサーバー側でsession情報をとして保持していることが確認できました。