# 6.1 sessionとcookie
sessionとcookieの2つはホームページの閲覧の中で比較的よくみかける概念です。これらはまた区別するのが難しい概念でもあります。しかし認証の必要なサービスやページの統計では相当重要になってきます。まずsessionとcookieがいったいどういうものか理解していくことにしましょうこのような問題を考えます：

浏览器
どのようにしてアクセスに制限のあるページをスクレイピングすればよいでしょうか？例えば新浪マイクロブログの友達のメインページや個人のマイクロブログのページ等です。

当然ブラウザから主導でユーザ名とパスワードを入力し、ページにアクセスすることができます。いわゆる"スクレイピング"とはプログラムを使って同じような作業を行うことを言います。そのため、"ログイン"の課程で何が発生しているのか理解する必要があります。

ユーザがマイクロブログのログイン画面にきた時、ユーザ名とパスワードを入力した後、"ログイン"をクリックするとブラウザが認証情報をリモートのサーバに送信します。サーバは検証ロジックを実行して、もし検証がパスすれば、ブラウザはログインしたユーザのマイクロブログのトップページにリダイレクトします。ログインが成功した後、サーバはどのように我々がその他の制限のあるページへのアクセスを検証するのでしょうか？HTTPプロトコルはステートレスですので、サーバは我々が前のHTTPリクエストの中で検証をパスした事を知る由もありません。当然、もっとも簡単な解決方法はすべてのリクエストにユーザ名とパスワードを含めることです。これでも構いませんが、サーバの負荷を非常に高めてしまいます。（毎回のリクエストがすべてデータベースでの検証を必要とします。）ユーザのエクスペリエンスも低下します。（すべてのページで再度ユーザ名とパスワードを入力しなければなりません。すべてのページにログインフォームが出てきます。）直接リクエストの中にユーザ名とパスワードを含めるわけにはいかないのでサーバかクライアントに身分を示す情報のようなものを保存するしかありません。cookieとsessionはそのためにあります。

cookieとは、簡単に言えばローカルマシンに保存されたユーザの操作の履歴情報です（当然ログイン情報を含みます）。またユーザが再度このページにアクセスした際ブラウザはHTTPプロトコルを通してローカルのcookieの内容をサーバに送信し、検証を行います。または継続して前の操作を行います。

![](images/6.1.cookie2.png?raw=true)

図6.1 cookieの原理図

sessionとは、簡単に言えばサーバ上に保存されたユーザの操作の履歴情報です。サーバはsession idを使用してsessionを識別します。session idはサーバが生成します。ランダム性とユニーク性を保証し、ランダムな秘密鍵に相当します。ハンドシェイクやデータ通信中にユーザの本当のパスワードが暴露されるのを防ぎます。しかしこの方法では、依然としてリクエストを送信したクライアントとsessionを対応させる必要があります。そのためcookieメカニズムによってクライアントのID（session id）を取得することで、GETメソッドでidをサーバに送信することができます。

![](images/6.1.session.png?raw=true)

図6.2 sessionの原理図

## cookie
Cookieはブラウザによって維持されます。クライアントに小さな本文情報として保存されます。ユーザのリクエストと画面に沿ってWebサーバとブラウザの間でやりとりされます。ユーザがページにアクセスした際、Webアプリケーションはcookieに含まれる情報を読取ることができます。ブラウザの設定ではcookieのプライバシーデータの選択肢があります。これをオープンするとすでにアクセスしたことのあるページのcookieをたくさん閲覧することができます。下の図をご覧ください：

![](images/6.1.cookie.png?raw=true)

図6.3 ブラウザで保存されているcookie情報

cookieには有効期限があります。有効期限の違いに従って2つに分けられます：セッションcookieと持続クッキーがあります。

もし有効期限を設定しなければ、このcookieの有効期限は新規に作成されてからブラウザを閉じるまでとなり、cookieは消滅します。このような有効期限は閲覧時のセッションのセッションcookieと呼ばれます。セッションcookieは一般的にハードディスク上には保存されず、メモリに保存されます。

もし有効期限(setMaxAge(60*60*24))が設定されていると、ブラウザはcookieをハードディスクに保存します。ブラウザを閉じて再度開くと、これらのcookieは依然として設定された有効期限まで有効となります。ハードディスク上に保存されたcookieは異なるブラウザのプロセス間で共有することができます。たとえばIEを2つ開き、メモリに保存されたcookieに対し異なるブラウザは異なる処理方法をとります。
　　

### Goでcookieを設定する
Go言語ではnet/httpパッケージのSetCookieを通して設定します：

	http.SetCookie(w ResponseWriter, cookie *Cookie)

wは入力する必要のあるresponse、cookieはstructです。cookieオブジェクトがどのようになっているか見てみましょう。

	type Cookie struct {
		Name       string
		Value      string
		Path       string
		Domain     string
		Expires    time.Time
		RawExpires string

	// MaxAge=0 means no 'Max-Age' attribute specified.
	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
	// MaxAge>0 means Max-Age attribute present and given in seconds
		MaxAge   int
		Secure   bool
		HttpOnly bool
		Raw      string
		Unparsed []string // Raw text of unparsed attribute-value pairs
	}

例を一つ見てみましょう。どのようにcookieを設定するかです。

	expiration := *time.LocalTime()
	expiration.Year += 1
	cookie := http.Cookie{Name: "username", Value: "astaxie", Expires: expiration}
	http.SetCookie(w, &cookie)

　　
### Goでcookieを読む
上の例ではどのようにcookieデータを設定するかご説明しました。ここではどのようにcookieを読み取るのか見てみましょう。

	cookie, _ := r.Cookie("username")
	fmt.Fprint(w, cookie)

もうひとつのロード方法は

	for _, cookie := range r.Cookies() {
		fmt.Fprint(w, cookie.Name)
	}

requestを通してcookieが非常に簡単に取得できるのがおわかりいただけるとおもいます。

## session

session、中国語ではよく「会話」と翻訳されます。本来は始めから終わりまでの一連のアクション/メッセージを意味します。たとえば電話をかける時は受話器を手にとり電話番号を押して電話を切る間の一連の過程をsessionと呼ぶことができます。しかしsessionという言葉がネットワークプロトコルと関係がある時は、往々にして"接続型通信"または/もしくは"ステートの保持"の2つの意味が含まれています。

sessionはWeb開発環境ではまた新しい意味が含まれます。クライアントサイドとサーバサイドの間でステートを保持するためのソリューションです。しばしばSessionはまたこのようなソリューションの保存構造も指します。

sessionメカニズムはサーバサイドのメカニズムです。サーバでハッシュテーブルの構造に似たもの(ハッシュテーブルを使う場合もあります)を使用することで情報を保存します。

しかしプログラムがあるクライアントのリクエストにsessionを確立する必要がある場合、サーバはまずこのクライアントのリクエストにsessionIDがあるかを検査します。サーバはsession idを参照し、このsessionを検索し(検索できなかった場合は新規に作成されます。このような状況はサーバがすでにこのユーザに対応するsessionオブジェクトを削除してしまった場合に起こり得ます、しかしユーザは人為的にリクエストのURLの後にJSESSIONの引数を追加します。)使用します。もしユーザのリクエストにsession idが含まれなければ、このユーザにsessionを作成し同時にこのsessionと関係するsession idを生成します。このsession idは今回のレスポンスにおいてクライアント側に返され保存されます。

sessionメカニズム自身は特に複雑ではありませんが、その実装と設定の柔軟性は複雑を極めます。これは一回の経験やひとつのブラウザ、サーバのみの経験でもって普遍的に通用するものではありません。

## 概要

上述の通り、sessionとcookieの目的は同じです。どちらもhttpプロトコルのステートレスであるという欠点を克服するためにあります。しかしその方法は異なります。sessionはcookieを通じてクライアントにsession idを保存します。またユーザの他のセッション情報はサーバのsessionオブジェクトに保存されます。これとは対照的に、cookieはすべての情報をクライアントに持たせる必要があります。そのためcookieにはある程度潜在的な脅威が存在します。例えばローカルのcookieに保存されたユーザ名とパスワードが解読されたり、cookieが他のホームページに収集されます（例えば：1．appAが主導的にゾーンBのcookieを設定し、ゾーンBにcookieを取得させます；2．XSS、appAでjavascriptを通じてdocument.cookieを取得し、自分のappBに送信します）。


上のいくつかの簡単な紹介でcookieとsessionの基礎的な知識をご紹介しました。これらの間の関係と区別を知り、web開発を行う前に必要な知識をあらかじめよく理解することで、対応に困窮したりbugフィックスを行う際に行き当たりばったりになったりしなくて済みます。以降のいくつかの章ではsessionに関するより細かな知識についてご紹介します。

## links
   * [目次](<preface.md>)
   * 前へ: [sessionとデータの保存](<06.0.md>)
   * 次へ: [Goはどのようにしてsessionを使用するか](<06.2.md>)

