セッション管理について学ぶ機会がありましたのでその根本の部分になるHTTPとCookieとセッションについてまとめてみました。
自分が分かるように引用してまとめたので間違いなどがあれば指摘してください
セッション管理とは
セッション管理:クライアントとサーバ間で通信を行う際に、通信相手の特定や相手の状態の把握を行うこと。また通信相手を特定した状態の通信のことを「セッション」と呼び、セッションができるとアプリケーションとのデータのやり取りができるようになる。
多くの場合、HTTPによる通信やWebアプリケーションの構築に関して、使われることの多い用語になる。
Webアプリケーションにおけるセッション管理の方法として最も一般的なのが、Cookieを使用する方法。これはWebサーバからCookieと呼ばれる情報をWebブラウザに送り、Webブラウザ側の記憶領域に格納しておくというもの。Webブラウザは次にWebサーバにアクセスする際に、リクエストの中にCookieを埋め込んで送信する。
下記にHTTPとCookieとセッションとセッション管理の流れについて記述する
HTTPとは
HTTP : WebサーバとWebクライアントの間でデータの送受信を行うために用いられるプロトコル(通信規約)。Webページを構成するHTMLファイルや、ページに関連付けられたスタイルシート、スクリプト、画像、音声、動画などのファイルを、データ形式などのメタ情報を含めてやり取りすることができる。
HTTPはクライアントから要求(HTTPリクエスト)を送り、サーバが応答(HTTPレスポンス)を返すプル型(リクエスト/レスポンス型)の通信を基本としており、WebブラウザやWebクローラなどのクライアントから送信する要求の形式や、Webサーバからの応答の形式などを定めている。
HTTPリクエストの中身
HTTPリクエスト:ブラウザなどからURLを指定して、ネットワーク上のWEBサーバからファイルやWEBページなどを返すようにリクエスト(要求)すること。
HTTPリクエストはURLの形式で送信しますが、詳細には下記の構成で「リクエストメッセージ」として送信している。
リクエストライン | メソッド、URL、httpのバージョンを表示 |
---|---|
ヘッダー | リクエストの詳細情報を表示 |
空白行 | ヘッダーとボディを分けるためのもの。 |
ボディ | 画面の入力内容などから送信される項目と値を表示 |
POST http://example.jp/31/31-003.php HTTP/1.1 ←リクエストライン
Host: example.jp ↓ヘッダー
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
Origin: http://example.jp
Connection: keep-alive
Referer: http://example.jp/31/31-002.php
Upgrade-Insecure-Requests: 1 ↑ヘッダー
name=%E5%BE%B3%E4%B8%B8%E5%BF%A0&mail=test%40ezample.jp&gender=%E7%94%B7 ←ボディ
リクエストライン
1行目のリクエストラインにはメソッド、URL、httpのバージョンを表示し、「何を、どうしたい」が、書かれている。
POST http://example.jp/31/31-003.php HTTP/1.1
ざっくりと内容を書くと
「http: //example.jp/31/31-003.php」(URL,URI)に「HTTP/1.1」(プロトコルバージョン)で「POST」(HTTPメソッド)する
と書かれている。
ヘッダ
2行目以降のヘッダにはリクエスト内容の詳細が「ヘッダフィールド」と呼ばれる項目を改行で区切って列挙した形式で記述されている。
個々のフィールドは【フィールド名】:【内容(値)】の形式になっている。
【フィールド名】に書かれるのは「User-Agent」などで主なフィールドとしては、「Host」(送信先のドメイン名とポート番号)、「Referer」(参照元ページのURL)、「User-Agent」(クライアントソフトの識別名)、「Cookie」(ブラウザ側に保存されたサイトデータ)、「Authorization」(認証データ)、「Accept」(受信可能なデータのMIMEタイプ)、「If-Modified-Since」(指定した日付以降に更新されていたらデータの送信を要求)などがある。
【内容(値)】には、それらの項目に対する実際の値が入る。
ボディ
一番下のボディには画面の入力内容などから送信される項目と値が表示される。
必要に応じて補足情報的なことが適当な形式で書かれる。
例えばPOST通信の場合は、受け渡されるパラメータの内容がここに記述され、GET通信のように補足の必要がない場合は、特に何も書かれない。
GET http://example.jp/31/31-001.php HTTP/1.1
Host: example.jp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Referer: http://example.jp/31/
Upgrade-Insecure-Requests: 1
HTTPレスポンスの中身
HTTPレスポンス:HTTPリクエストに対するレスポンス、クライアントから送信されたデータをサーバが処理をしてクライアントに返信する応答のこと。
下記のような構成のデータが返却される。
ステータスライン | httpのバージョン、ステータスコードを表示。 |
---|---|
ヘッダー | レスポンスの詳細情報を表示 |
空白行 | ヘッダーとボディを分けるためのもの。 |
ボディ | HTMLや画像等のデータを表示 |
HTTP/1.1 200 OK ←ステータスライン
Server: nginx/1.10.3 ↓ヘッダ
Date: Sat, 20 May 2023 01:53:37 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 386
Connection: keep-alive
Vary: Accept-Encoding
X-UA-Compatible: IE=edge ↑ヘッダ
<html> ←↓ボディ
<head><title>確認</title></head>
<body>
<form action="31-004.php" method="POST">
:
:
</body></html>
ステータスライン
1行目のステータスラインにはhttpのバージョン、ステータスコードが表示され、「HTTPリクエストの結果」が、書かれている
HTTP/1.1 200 OK
この内容では
「HTTP/1.1」(プロトコルバージョン)で「200(ステータスコード) OK(テキストフレーズ)」が返ってきた
と書かれている。
【ステータスコード】は「どうだった」を表す3桁の数字で
100番台:処理が継続している
200番台:正常に処理した
300番台:リダイレクト
400番台:クライアントエラー(Webブラウザ側で何かがおかしい)
500番台:サーバーエラー(Webサーバ側で何かがおかしい)
となっている
【テキストフレーズ】はステータスコードの補足説明が書いてある。
「OK」(正常にリクエストを受け付けた)、「Not Found」(ページが見つからなかった)、「Internal Server Error」(Webサーバ側でエラー)など。
ヘッダ
2行目以降のヘッダは「HTTPステータスラインに書ききれないレスポンスの詳細情報」が書かれている場所
レスポンス内容の詳細は「ヘッダフィールド」と呼ばれる項目を改行で区切って列挙した形式で記述されている。
個々のフィールドは【フィールド名】:【内容(値)】の形式になっている。
【フィールド名】に書かれるのは「Content-Type」などで主なフィールドとしては、「Location」(リダイレクト先URL)、「Server」(Webサーバソフトの識別名)、「Age」(プロキシのキャッシュに存在する時間)、「Set-Cookie」(ブラウザ側にサイトデータを保存)、「Vary」(文字コードなど複数の選択肢がある場合にサーバが選んだものを通知)などがある。
【内容(値)】には、それらの項目に対する実際の値が入ります。
ボディ
一番下のボディにはHTMLや画像等の「相手が欲しがってたファイルの中身」が書かれているデータを表示する。つまり、HTMLファイルの中身。
HTTPはステートレスなプロトコル
ステートフルとステートレス
クライアントとサーバー間のやりとりにはステートフルとステートレスという仕組みが2通りある。
ステートとは状態という意味。
ステートフルとステートレスの違いはクライアントとサーバー間のやりとりを維持するかしないかの違い。
ステートフルとは前回のデータを保存して、データ保存した内容を処理結果に反映される仕組み。
一方、ステートレスとは前回のデータを保存しないで、前回のデータを内容に処理結果に反映させない仕組み。
HTTPはステートレスつまり状態を保持しないプロトコルである
ステートレスであることの問題点
HTTPはステートレスで直前の情報を保持しないプロトコル。
そのことでどんな問題が生じてくるかというとリクエストのたびに状態がリセットされ、状態を全く覚えていないので再度同じものを表示することができない。例えるとECサイトの買物かごに商品を入れてもサーバーに商品を入れた状態は保存されないので買い物かごは空っぽであるということがあげられる。
Cookieとは
Cookie(クッキー):正式名称は「HTTP Cookie」。クライアント(Webブラウザ)に保存されたデータ、またはデータをブラウザに保存する仕組みのこと。
WEBサイトを閲覧したときに、ユーザーが訪れたサイトや入力したデータ、利用環境などの情報(データ)が記録される。
データを記録することで、ユーザーは2度目にサイトを訪れた際に情報の再入力なしでログインできる、商品を購入する際に住所などの入力を省くことができるといった利点がある。
Cookieの特徴
・サーバーからのHTTPレスポンスのSet-Cookieヘッダー(Set-Cookie:)を使用してWebブラウザに送られ、クッキー値(Cookie:)として保存される
・保存されたCookieはクライアントからサーバーにリクエストするたびに自動送信される
・有効期限が設定されていないCookieは、Webブラウザが閉じられると一緒に削除される(「セッションCookie」とも言う)
・有効期限が設定されたCookieは、期限が過ぎるまではWebブラウザを閉じても削除されない
・「クッキー名=値」の形(1つのクッキーは4KBまで)
・ブラウザによって保持できる数が異なる
・最近のタブ型ブラウザでは、同じPC上でタブやウィンドウを複数表示してもCookieは共有される。
Cookieの仕組み
上記にも書いた様にCookieは、クライアント(Webブラウザ)に保存されたデータ、またはデータをブラウザに保存する仕組みのこと。
サーバーからのレスポンスに「Cookieファイルを作成してCookie(データ)を保存してください」という指示があれば、クライアントは指示に従い、Cookieを保存する
クライアントにCookieが保存されていれば、クライアントは、常にリクエストに「このようなCookieがあります」とサーバーに教える仕組みになっている。
具体的には、サーバーは、HTTPレスポンスにSet-Cookieヘッダを付与することで、クライアントに対して「Cookieを保存してください」と指示することが可能。
Set-Cookieヘッダには、Cookieの有効期限やCookieを送るドメイン、有効パスなどの各属性があり、; で区切って記述することでそれぞれを任意で設定する事が可能。
基本的な構文は「Cookie名=値;」で、これを並べて複数の名前と値のセットを送ることができる。
Set-Cookie: クッキー名=値;[expires=有効期間(日時)];[Path=URL相対パス];[Domain=ドメイン名];[secure];[httponly]
Set-Cookie: a=b; expires=Mon, 15-Aug-2016 12:00:00 GMT; path=/; domain=xxxx.com; secure; httponly
サーバーからの Set-Cookieヘッダの内容に従い、クライアントはCookieを保存する。
逆にクライアントは、HTTPリクエストに Cookieヘッダを付与することで、サーバーに対して「このようなCookieが保存されています」と教えることが出来る。
Cookieが存在する限り、常にリクエストに Cookieヘッダを付与する。
Cookie: クッキー名=値
Cookie: a=b
属性一覧
セッションとは
セッション:WebブラウザとWebサーバーのやりとりにおいて、ユーザーが行う一連の動作(ログインしてからログアウトするまで、HTTP通信の接続を確立してから遮断するまで)のこと。または「サーバ内に情報を保存し、複数ページ間で共有する」仕組みのこと
セッションの特徴
・HTTPのセッションは「セッションID」を使って同一のセッションを管理する
・セッションの情報はサーバーに保存されることが多い
・セッションの情報は、サーバー上のファイルとして管理される。(セッションファイル)
・セッションIDはCookieに保存し、リクエストヘッダに格納してPOSTメソッドで送受信したり、URLに埋め込んでGETメソッドで送受信したりする。
・Cookieを利用することでセッション(一連の処理)を実現できる=ステートレスをステートフルにできる
・セッションはWebブラウザを閉じるまで保存する
・リンクなどでページを移動しても内容を保持することができる
・セッションIDのやりとりはCookieを用いる方法が一般的だが、Cookieが使えるかどうかはブラウザによるため、GETパラメータを用いてやりとりするなど他の方法をとるケースもある(セキュリティ上は非推奨)
・HTTPのセッションは「セッションID」を使って同一のセッションを管理する
セッションID
ウェブサイトなどにアクセスしたユーザーのセッションを一意に識別するために、WebサーバやWebアプリケーションによって付与される情報のことである。どのデータが、どのユーザーと関連するかはブラウザに発行されたクッキーのセッションIDを使用して判断している。
セッションIDはWebサーバーがブラウザから初めてリクエストを受けたタイミングで発行される。通常は、Cookieとしてブラウザに対して付与(保存)されるが、Cookieを無効にしているユーザーにも対応するために、URLのリクエストパラメータの一部に付与される場合もある。
Webサーバーはこのリクエストに付いているセッションIDを確認することで、誰からのリクエストなのかがわかる仕組みになっている。
Cookieとセッション
そもそも、なぜCookieやセッションといった技術が必要なのか
それは、HTTPは「サーバーがクライアントの情報を保持し続けられない」ステートレスなプロトコルだから
HTTPはステートレスなプロトコルであるため、Webブラウザからのリクエスト内容が同一であれば、Webサイトは毎回同じレスポンスを返すことになる。しかしこれでは、ログインしたユーザ毎に異なる処理や、複数のWebページにまたがった「一連の処理(トランザクション)」は行えない。このような処理を行うには、アクセスしてきたユーザが誰なのかを識別し、これまでにどのような処理を行ってきたのかという「状態」を把握する必要があるから。
そこでCookieとセッションの機能を使ってHTTPが持つ「ステートレス」という性質を補填して状態を保持させる(ステートフルにする)
もう少し噛み砕いて書くと、
・Aさんがログインしていること
・Bくんが商品Pをカートに入れていること
このようなアプリケーションの状態(セッション状態とも言う)を維持できるようになる。
クライアントとサーバ間で通信を行う際に、通信相手の特定や相手の状態の把握、保持を行うことをセッション管理という。
簡単な流れを書くとCookieに一意の値(セッションID)を入れ、リクエストするときにCookieにある値も一緒に送ってもらうことで、識別可能になり、一連の処理として扱えるようになる。
セッション管理を開始する方法
PHPでセッションを開始するには session_start() 関数を利用する。
session_start();
session_start()を記述すると、セッションが開始され、自動でセッションIDを発行してくれる。
セッションIDを発行するときに、セッションIDごとにセッションファイルをサーバーに作成する。
(作成されたセッションファイルには、任意の値を入れることが可能。)
session_start()は、リクエストにセッションIDがあるか無いかで挙動が変わる。
リクエストにセッションIDがない場合
・セッションIDがなければ、セッションIDを発行し、セッションIDをCookieに保存するようにレスポンスを送信
・セッションIDを発行するときに、サーバー側では、セッションIDごとにセッションファイルを作成
リクエストにセッションIDがある場合
・セッションIDがあれば、該当するセッションファイルにある情報を参照
セッション管理の流れ
以下の流れは「WebアプリケーションがA君がログインしているという状態を維持する」というシチュエーション。
①セッションファイルを作成する
まずはA君がユーザーIDが「1」として初回ログイン(HTTPリクエスト)をする。ログインに成功するとWebアプリケーションはサーバーにセッションファイルを作成し、セッションIDとログインしたユーザー(A君)の情報をセッションファイルに記録する。セッションIDはWebサーバーがブラウザから初めてリクエストを受けたタイミングで発行される。
(今回はユーザーIDのみ)
②クラアイントにCookieを保存する
リクエストを受けたサーバーはクライアント(Webブラウザ)にHTTPレスポンスを返す。この時にレスポンスヘッダーの「Set-Cookie:」を使って、sessionidという名前で値がセッションIDである9reifwjgkrnrqfuvoijqfiのCookieをWebブラウザに保存するように指示する。
(Cookieの名前は例です。セッションIDも適当に書いた乱数です)
Set-Cookie: sessionid = 9reifwjgkrnrqfuvoijqfi
レスポンスを受け取ったクライアントは指示通りCookieファイルを作成してCookie(データ)を保存する。
Cookie: sessionid = 9reifwjgkrnrqfuvoijqfi
名前:sessionid
値:9reifwjgkrnrqfuvoijqfi
ドメイン:
有効パス:
有効期限:
セキュア:
③サーバーでリクエストしたユーザーを判別する
WebブラウザにCookieを保存した状態で再度サーバーにリクエストするとCookieも自動的に送られる。リクエストを受け取ったサーバーはCookieからセッションIDを取り出し、セッションファイルに照合をかけ、ユーザーの判別(A君であること、ログイン済みであること)をする。
このようにしてセッションとCookieを使うことでWebアプリケーションが「ユーザーがログインしている」という状態を維持することが出来る。
この一連の流れがCookieとセッションという技術でHTTPを「ステートフル」にしている。
参考記事と書籍
書籍「体系的に学ぶ安全なWebアプリケーションの作り方」