メインコンテンツまでスキップ

Cookieと認証(発展)

HTTPヘッダ

HTTPにおけるリクエストとレスポンスには、ヘッダと呼ばれるKey-Value型のデータ構造が毎回付加されています。Chromeの開発者ツールでのNetworkタブで確認できるので、確認してみましょう。

HTTPヘッダ

レスポンスヘッダにSet-Cookieヘッダを含めることにより、次回以降のリクエストで、クライアントはそのデータをリクエストヘッダのCookieヘッダに入れて毎回送信します。この性質を利用することで、HTTPサーバーはクライアント毎に異なるサービスを提供できるようになります。

Cookie自体もKey-Valueのデータ構造となっているので、Set-Cookieヘッダを複数回送信することにより、複数のCookieを1つのレスポンスで送信することができます。例として、Yahoo! Japanのウェブサイトにアクセスした際に、Yahoo! Japanが送信するCookieの中身を覗いてみましょう。

Yahoo! JapanのCookie

このレスポンスヘッダを受けて、ブラウザは次のようなCookieを保存します。

保存されたCookie

ブラウザを更新することで、設定されたCookieが確かにリクエストヘッダの中に含まれて送信されていることがわかります。

リクエストに付加されたCookie

ExpressでCookieを利用する

Expressを用いてレスポンスヘッダにCookieを付加するには、express.Response#cookieメソッドを利用します。また、クライアントからのリクエストのCookieヘッダを解析するためには、cookie-parserパッケージを利用します。

npm install cookie-parser

を実行して、パッケージをインストールしましょう。Webサーバーのプログラムは次のようになります。

main.mjs
import express from "express";
import cookieParser from "cookie-parser";

const app = express();
app.use(cookieParser());

app.get("/", (request, response) => {
// Cookieの値は文字列なので数値に変換が必要
const count = parseInt(request.cookies.count) || 0;
const newCount = count + 1;
// 変更後の値をレスポンスヘッダに乗せる
response.cookie("count", newCount.toString());
response.send(`${newCount}回目のアクセスですね。`);
});

app.listen(3000);

express.Request#cookiesプロパティには、ブラウザから送信されていたCookieがオブジェクト形式で保存されています。ブラウザで表示させると、更新ボタンが押されるたびに数値が増えていることがわかります。

プログラムの流れを整理すると、次の図のようになります。

プログラムの流れ

確認問題

  • Chromeの開発者ツールを用いて、リクエストヘッダとレスポンスヘッダの内容を確認してみましょう。
  • シークレットモードでページを開くと値はどうなるでしょうか。

Cookieを用いた認証

ユーザー名とパスワードを用いて認証するタイプのアプリケーションを考えてみましょう。ユーザー名とパスワードを、そのままCookieに入れてしまうと、データが悪意のある第三者に奪われてしまうリスクが高まります。

このため、ログインが成功したタイミングで、クライアントに対してランダムなIDを発行し、Cookieに保存させておくことが一般的です(セッションIDと呼ばれる)。次回以降のアクセスでは、このセッションIDを用いて認証を行います。このフローを図にすると、次のようになります。

セッション

演習問題

ユーザーが自分のユーザー名とパスワードでログインし、プロフィールを表示できるウェブアプリケーションを作成してみましょう。

schema.prismaは次の通りとします。

schema.prisma
model User {
id Int @id @default(autoincrement())
username String @unique
password String
}

model Session {
id String @id // 一意でランダムなID
userId Int // UserのID
}