🍪

実装で学ぶ Cookie 発行と取得(第3回)

に公開

第3回:Cookieの発行・取得 実際のコードで理解する(Java × JavaScript)

第1回では「Cookieとは何か?」
第2回では「Cookieはいつ保存・送信されるのか?」
について整理しました。

第3回では、実際に動くコードを使って Cookie を扱う方法を説明していきます。

  • Java(Servlet)で Cookie を「発行」する
  • JavaScript で Cookie を「発行」する
  • Java(Servlet)で Cookie を「読み取る」
  • JavaScript で Cookie を「読み取る」

簡単なコード付きで説明していきます。


1. Java(Servlet)で Cookie を発行する方法

私の経験をもとに、下記の流れでCookieを発行するコードを記載しました。:

  1. new Cookie で作成
  2. Path / MaxAge / HttpOnly / Secure などを設定
  3. 必要なら Domain も設定
  4. response.addCookie() で送信

▼ Cookie発行コード

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Cookie 生成
        // Cookieの名前が「cookieName」で、値が、「abcd1234」と設定している
        Cookie tokenCookie = new Cookie("cookieName", "abcd1234");

        // サイト全体で有効
        tokenCookie.setPath("/");

        // 有効期限(1時間)※秒で設定
        tokenCookie.setMaxAge(60 * 60);

        // JavaScript から参照させない
        tokenCookie.setHttpOnly(true);

        // 本番環境では true。ローカル開発では false 推奨(localhost が HTTP のため)
        tokenCookie.setSecure(false);

        // ▼ Domain を設定
        // 本来は環境変数から取得するが、サンプルでは固定値
        // 本番例:tokenCookie.setDomain("your-domain.com");
        // ローカル例:tokenCookie.setDomain("localhost");
        tokenCookie.setDomain("localhost");

        // Cookie をレスポンスに追加
        response.addCookie(tokenCookie);

        response.setContentType("text/plain; charset=UTF-8");
        response.getWriter().println("Cookie を発行しました。");
    }
}

※一部ブラウザでは localhost に Domain を付けると Cookie が正しく保存されない場合があります。
その場合は Domain を設定せず(=省略し)、Path のみ指定する方法が動作しやすいです。

▼ Domain の扱いについて

  • ローカル環境
    → localhost(または 127.0.0.1)

  • 本番環境
    your-domain.com を環境変数などで渡すのが一般的
    (Javaなら System.getenv("COOKIE_DOMAIN") など)

Domain 間違えると「保存されるのに送られない」「送られるのに読めない」などの混乱が起きやすいです。


2. JavaScript で Cookie を発行する方法

JavaScriptでは、

document.cookie = "key=value; Path=/; Max-Age=秒数; 属性...";

という 文字列代入 で設定します。

document.cookie = "cookieName=abcd1234; Path=/; Max-Age=86400; Secure";

注意

  • JavaScript から HttpOnly は付けられない
  • Secure を JS から設定した場合、HTTPSでしか送られなくなる

私は、HTTPの開発環境でSecureに設定していたので、Cookieが発行されなくて苦戦しました。。。


3. Java(Servlet)で Cookie を読み取る方法

Java では request.getCookies() で全Cookie を取得し、
その中から目的のCookieを探します。

private Cookie getCookie(HttpServletRequest request, String name) {
    // 送信された全Cookieを取得する
    Cookie[] cookies = request.getCookies();
    if (cookies == null) {
        return null;
    }

    // 取得した全Cookieから指定したの名前のCookieのみ抽出する
    for (Cookie c : cookies) {
        if (c.getName().equals(name)) {
            return c;
        }
    }
    return null;
}

▼ 使い方

Cookie tokenCookie = getCookie(request, "cookieName");
if (tokenCookie != null) {
    String token = tokenCookie.getValue();
    System.out.println("ログイントークン = " + token);
}

4. JavaScript で Cookie を読み取る方法

document.cookie は 全Cookieが1行の文字列 で返ってきます。

例:
cookieName=abcd1234; example=test; example1=test1

これをパースする必要があります。

▼ Cookieを取得する関数の一例

function getCookie(name) {
    const cookies = document.cookie.split(";");

    for (let i = 0; i < cookies.length; i++) {
        const cookie = cookies[i].trim();
        if (cookie.startsWith(name + "=")) {
            return cookie.substring(name.length + 1);
        }
    }
    return null;
}

▼ 使い方

const token = getCookie("cookieName");
console.log("cookieName:", token);

注意

HttpOnlyが設定されているCookieはJSから見えないので、この方法では取得できません。


5. ローカル開発で特にハマりやすいポイント

① Secure と "http://localhost" は相性が悪い

  • Secure = true → HTTPS でしか Cookie を送らない
  • ローカルは http → Cookie が送られない

→ 開発時は Secure=false 推奨
ただし、"http://localhost"だと、Cookieの設定が厳格に適応されず、Secure = trueでもCookieが発行される場合があります。なので、本番環境でSecure = trueを設定したい場合は、必ずhttpsの開発環境のを準備し、挙動を確認する必要があります。


② SameSite=None には Secure=true が必須

Chrome・Edge など多くのブラウザで
「None なら Secure が必要」という仕様になっています。

Secure を付けない場合、Cookie が保存されない/送信されない原因に。


③ ポート番号違いは別サイト扱い

localhost:3000 と localhost:8080 は別サイト扱いなので Cookie は共有されません。


cookieName(Path=/)
cookieName(Path=/app)
これらは別物。


⑤ ブラウザによって、Cookieの表示が異なる

ブラウザによって、開発者ツールでのCookie表示に他のドメインのCookieも含まれていたり、表示箇所が異なっていたりします。
私は、このブラウザによる違いを理解していなかったのでテスト時に苦戦しました。


6. まとめ

  • Java では Cookie を new → 属性設定 → response.addCookie で発行
  • 同じ名前でも Path / Domain が違うと別 Cookie
  • JavaScript では document.cookie に文字列セット
  • JavaScript では HttpOnly が読めない
  • ローカル環境では Secure / SameSite / ポート違いでハマりやすい
  • ブラウザごとの挙動の違いに注意

補足ですが、Cookie はユーザーの端末側で簡単に操作できます。
ブラウザ開発者ツールで次の操作が可能です:

  • Cookie の値の書き換え
  • 有効期限の延長
  • Domain / Path の変更
  • Cookie 自体の削除
  • 追加の Cookie を勝手に作成
  • HttpOnly 以外は JS で読み書き可能

つまり、Cookie 自体を認証手段として信用してはいけません。

  • 「Cookie に user_id を入れる」
  • 「Cookie の値があればログイン済み扱いにする」

といった設計は攻撃者に非常に弱いです。

本来は、

  1. Cookie は 署名付きのトークン(JWTなど)を運ぶ器
  2. 認証の正当性はサーバー側で検証
  3. Cookie を書き換えられても偽造は不可能
  4. HttpOnly + Secure + SameSite を適切に設定

という構成が必須になります。

Discussion