Laravelで学ぶCookieとSession. ~CookieとSessionを学んでCSRF対策を理解~
はじめに
本記事では、CookieとSessionについて理解を深めるための整理をしていきます。WEBアプリケーションであれば、CookieとSessionを利用していることが多いと思います。
しかし、フレームワークが良しなに処理してくれるため、意識をせずに利用している場合も多いのではないでしょうか?
今回は、Laravelを利用したハンズオン形式で、APIのリクエスト・レスポンスを通じてCookie・Sessionに対する理解を深めていきます。
使用したソフトウェア
"php": "^8.0.2",
"laravel/framework": "^9",
Cookie
Cookieとは
ウェブサイトがユーザーのブラウザに保存する小さなデータの塊です。ブラウザの機能として備わっています。
HTTPリクエストは、ステートレスなプロトコルなので、ステートフルに状態を維持・管理するために使われます。
主にユーザーの訪問履歴や設定、ログイン情報などの状態を管理するために利用されます。
参照:https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies
Cookieの仕組み
Cookieはブラウザの機能です。
HTTP通信のHeaderを通して、ブラウザとサーバー間でCookieはやりとりされます。
ブラウザへCookieを生成するためには、HTTP通信のレスポンスヘッダーに対して、Set-Cookieを利用します。
Set-Cookie: <cookie-name>=<cookie-value>
サーバーへCookieを送信するためには、HTTP通信のリクエストヘッダーに対して、Cookie
Cookie: <cookie-name>=<cookie-value>
Laravelを利用して、Cookieの送受信を確認
Laravelを利用して、確認していきます。
APIを用意します。
ルーティングを作成
Route::get('testSetCookie', 'TestController@testSetCookie')
Route::get('testGetCookie', 'TestController@testGetCookie')
Controllerを作成
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class TestController extends Controller
{
public function testSetCookie(Request $request)
{
return response()->withCookie('XXXX_id', 'value');
}
public function testGetCookie(Request $request)
{
$cookies = $request->cookies->all();
logger('cookies-all', $cookies);
return response()->json($cookies);
}
}
ブラウザへCookieを新規setする
testSetCookieメソッドで確認します。
LaravelではwithCookieメソッドを利用することで、レスポンスヘッダーにSet-Cookieを追加することが出来ます。
下記をAPIで実施することによって、ブラウザのCookieにkey:XXXX_id で value:value_XXXX_1 というCookieが生成されます。(Laravelでエンコードされるため、value_XXXX_1そのままではない)
response()->withCookie('XXXX_id', 'value_XXXX_1')
実際に確認するためには、ブラウザの検証ツールで確認することができます。
ApplicationタブのCookie項目で確認することが出来ます。
サーバーでCookieを確認する
testGetCookieメソッドで確認します。
Laravelでは、コントローラメソッドでIlluminate\Http\Requestクラスをタイプヒントすることで、現在のHTTPリクエストのインスタンスを取得することが可能です。
参照:https://readouble.com/laravel/9.x/ja/requests.html
$cookies = $request->cookies->all();
で、現在のHTTPリクエストのCookieを全て取得出来ます。
logから確認してみましょう。例えば、下記のような値が取得できます。
ここで注目したいのは、
1:XXXX_idのCookieが保存されている(取得できる)
2:valueにnullがセットされているCookieがある
{
"cookies-aii": {
"__Host-js_csrf": null,
"XXXX_id": "FM4nCijLuaekuxayLh",
"XSRF-TOKEN": "HMiKuqr0FWmhaFM4nCijLuaekuxayLhr3ZYet",
"laravel_session": "smwDGY6uEku13Fltv05EN6cGK4yNT9oInZsaQbK6"
}
}
1:XXXX_idのCookieが保存されている(取得できる)
testSetCookieでセットした処理が反映されていることが出来ました。
2:valueにnullがセットされているCookieがある
Cookieの特性として、同一ドメインにのみCookie情報を送信します。Applicationタブで確認すると分かりますが、nullになっているCookieのDomain項目は、利用しているサービスとは別のサービス(別Domain)の場合はnullとなります。
Cookieの設定はカスタマイズが可能
set-cookieを利用する場合に、Cookieの制御設定を追加出来ます。
Cookieの制限時間を設定するためには、Expires属性
Cookie へのアクセス制限を設定するためには、Secure属性、HttpOnly属性
Cookie の送信先の定義を設定するためには、Domain属性、Path属性
など、Cookieを利用用途に合わせた設定にてsetすることが出来ます。
Session
Sessionとは
ウェブアプリケーションやウェブサイト上で、ユーザーがサーバーとの間で一連の通信や操作を行う期間のことです。
期間のこと...?となるかもしれませんが、Sessionの定義としては期間のことです。そのSession(期間)に対するデータを各フレームワークが管理する仕組みを有しています。
通常、ユーザーがウェブサイトにアクセスすると、サーバーはそのユーザーに対して一意のセッションIDを生成し、セションに情報を格納していきます。
LaravelにおけるSession管理
LaravelにおけるSessionの管理方法を概略のみ記載します。
Sessionのデータはどこに保存される?
config/session.php
のファイルの中で定義されています。
デフォルトはfile管理となっており、storage/framework/sessions
の配下に作成されます。
Sessionのデータはどのように作成される?
Illuminate\Session\Middleware\StartSession
のMiddlewareで作成されます。
設定したいですが、Web通信の場合はStartSessionのMiddlewareを通ります。
Middlewareを通して、HTTP通信の度にSessionの確認や、必要であればSessionの作成なども行います。
Sessionに何が保存される?
フレームワークや、各アプリケーションでそれぞれ保存したいデータを保存します。
Laravelでは、_token(XSRFトークン)、_previous.urlなど、ユーザーを照合したり、ユーザー行動を把握するための状態管理に使います。
CookieとSessionの繋がり
CookieとSessionは別の仕組みです。必ずしも繋がりがある訳ではありません。
ただし、SessionをWEBアプリケーションで利用する場合は、CookieにSessionのデータを保持することで状態を管理をする場合が多いです。
Laravelの場合は、
Cookieに laravel_session
というkeyでsessionのIDを保持します。(SessionIdとなります。)
そして、SessionIdと同一のファイルの中身にSessionの情報が格納されます。
CSRF対策
CookieとSessionを利用して、連携することで外部攻撃を防ぐ仕組みについて紹介していきます。
CSRFとは
クロスサイトリクエストフォージェリ(CSRF)と言い、攻撃者が被害者の代わりに意図しないリクエストを送信することで、被害者のセッションを悪用する攻撃手法です。
LaravelにおけるCookieとSessionを用いたCSRF対策
CSRFトークンの生成
Laravelは、フォームリクエストやAjaxリクエストなどの各リクエストに対して、セッションに紐づく一意のCSRFトークンを生成します。
フォームにトークンの埋め込み
LaravelのBladeテンプレートエンジンを使用する場合、フォーム内に@csrfディレクティブを挿入することで、自動的にCSRFトークンが埋め込まれます。このトークンは、ユーザーのブラウザにCookieとして保存されたセッションの中のCSRFトークンと一致します。
リクエストの処理とトークンの検証
ユーザーがフォームを送信すると、リクエストにはフォームに埋め込まれたCSRFトークンが含まれます。LaravelのCSRFミドルウェアがこのトークンを自動的に検証し、リクエストに含まれるトークンがセッションに保存されたトークンと一致しない場合は、リクエストを無効にします。
おわりに
如何でしたでしょうか。普段何気なく利用している、Cookie・Sessionの仕組みの理解を深めることはできましたでしょうか?
WEBアプリケーションの開発においては、Cookie・Sessionは大事な仕組みになってくるので、実際に手を動かして直接確認してみてください。
わたしもまだまだまだまだ勉強途中です。何か不備などがあれば教えて頂けますと幸いです。
Discussion