Files
build-web-application-with-…/ja/06.1.md
2016-03-13 02:37:02 +09:00

106 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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メカニズムによってクライアントのIDsession 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.Now()
expiration = expiration.AddDate(1, 0, 0)
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の後にSESSIONの引数を追加します。)使用します。もしユーザのリクエストにsession idが含まれなければ、このユーザにsessionを作成し同時にこのsessionと関係するsession idを生成します。このsession idは今回のレスポンスにおいてクライアント側に返され保存されます。
sessionメカニズム自身は特に複雑ではありませんが、その実装と設定の柔軟性は複雑を極めます。これは一回の経験やひとつのブラウザ、サーバのみの経験でもって普遍的に通用するものではありません。
## まとめ
上述の通り、sessionとcookieの目的は同じです。どちらもhttpプロトコルのステートレスであるという欠点を克服するためにあります。しかしその方法は異なります。sessionはcookieを通じてクライアントにsession idを保存します。またユーザの他のセッション情報はサーバのsessionオブジェクトに保存されます。これとは対照的に、cookieはすべての情報をクライアントに持たせる必要があります。そのためcookieにはある程度潜在的な脅威が存在します。例えばローカルのcookieに保存されたユーザ名とパスワードが解読されたり、cookieが他のホームページに収集されます例えば1appAが主導的にゾーンBのcookieを設定し、ゾーンBにcookieを取得させます2XSS、appAでjavascriptを通じてdocument.cookieを取得し、自分のappBに送信します
上のいくつかの簡単な紹介でcookieとsessionの基礎的な知識をご紹介しました。これらの間の関係と区別を知り、web開発を行う前に必要な知識をあらかじめよく理解することで、対応に困窮したりbugフィックスを行う際に行き当たりばったりになったりしなくて済みます。以降のいくつかの章ではsessionに関するより細かな知識についてご紹介します。
## links
* [目次](<preface.md>)
* 前へ: [sessionとデータの保存](<06.0.md>)
* 次へ: [Goはどのようにしてsessionを使用するか](<06.2.md>)