一覧WB-05-1 · Cookieとブラウザ内保存

Cookieの保存範囲と削除

curlのCookie保存ファイルを使い、同じCookieを別パス・別ホストへ送った結果を確認します。名前が同じCookieの更新、削除時に必要な範囲指定、セッションCookieの扱いまでを続けて操作します。hosts.confには演習用ホスト名と接続先の対応を設定しています。

説明

Cookieは配信側がSet-Cookieで保存を求め、後の要求でクライアントがCookieヘッダーに付ける名前と値です。保存した全Cookieを毎回送るのではなく、宛先のホスト、パス、有効期限などの条件によって選びます。

curlのCookie保存ファイルを使い、同じCookieを別パス・別ホストへ送った結果を確認します。名前が同じCookieの更新、削除時に必要な範囲指定、セッションCookieの扱いまでを続けて操作します。hosts.confには演習用ホスト名と接続先の対応を設定しています。

1二つのCookieを受け取る

shop.example.testから、ホストだけに属するthemeと、example.test配下へ送るlangを受け取ります。

curl -K hosts.confホスト名と接続先の設定 -sS -i -c cookies.txt受信Cookieを保存 http://shop.example.test:18080/set

Set-Cookieは二行です。themeにはDomainがなく、受け取ったshop.example.testだけに送るhost-only Cookieになります。langはDomain=example.test、Path=/shop、Max-Age=3600で、対象サブドメインとパス、有効期間を指定しています。

2保存された属性を確認

保存ファイルから宛先・パス・期限の有無を表示します。

python3 jar.pyCookie保存ファイルの属性を表示

themeのsubdomainsはFALSE、langはTRUEです。persistentは期限付きかどうかを示します。Cookieの値と属性は別で、langの値はjaです。DomainやPathの文字列まで値の一部になるわけではありません。

3対象パスへ送信

保存ファイルを-bで読み込み、/shop/itemsへ要求します。

curl -K hosts.conf -sS -b cookies.txt保存済みCookieを読み込む http://shop.example.test:18080/shop/items/shop配下の要求

受信側のcookieにはlang=jaとtheme=lightが届きます。要求のCookieヘッダーには名前と値が入り、Domain・Path・Max-Ageの属性は送りません。属性はクライアントが送信可否を選ぶために使います。

4似ているパスでも境界がある

/shoppingへ要求します。

curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shopping/shopとは異なるパス境界

themeだけが届きます。Path=/shopは/shopそのものと/shop/配下には一致しますが、単に文字列の先頭が似ている/shoppingには一致しません。Pathは送信範囲の選択であり、同じサイト内のスクリプトを隔離する安全境界ではありません。

5別のサブドメインへ要求

api.example.testの/shop/itemsを取得します。

curl -K hosts.conf -sS -b cookies.txt http://api.example.test:18080/shop/items同じ親ドメインの別ホスト

Domain=example.testのlangだけが届き、host-onlyのthemeは届きません。Domainを指定すると、指定ドメイン自身とそのサブドメインが対象になります。先頭のドットには現在のCookie仕様で特別な意味はありません。

6末尾が似ている無関係のホスト

notexample.testへ要求します。

curl -K hosts.conf -sS -b cookies.txt http://notexample.test:18080/shop/itemsラベル境界が一致しないホスト

Cookieは空です。example.testという文字列が末尾にあればよいのではなく、ドメイン名のラベル境界で一致する必要があります。notexample.testはexample.testのサブドメインではありません。

7無関係のDomainを保存しようとする応答

shop.example.testからDomain=other.testを設定する応答を受け取り、保存一覧を開きます。

curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt既存Cookieを読み込み更新して保存 http://shop.example.test:18080/reject無関係のDomainを指定する応答 python3 jar.py保存されなかったことを確認

応答にはbad=yesがありますが、保存一覧には追加されません。応答元shop.example.testはother.testへ一致しないためです。任意のサイトが無関係のドメインのCookieを設定できる仕組みではありません。

8同じ範囲のCookieを更新

themeをdarkへ変更する応答を受け取り、/shop/itemsへ再送します。

curl -K hosts.conf -sS -b cookies.txt -c cookies.txt http://shop.example.test:18080/update同じ範囲のthemeを更新 curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items更新後の値を送信

themeはlightからdarkに置き換わります。同じ名前・ドメイン・パスの組合せでは新しい値が以前の値を置換します。同じ名前でもパスが異なるCookieは併存できるため、名前だけでは保存項目を特定できません。

9異なるPathで削除を指示

langをMax-Age=0で削除しますが、ここではPath=/を指定した応答を受け取ります。

curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt http://shop.example.test:18080/delete-wrongPath=/で削除を指定 curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items元のlangが残ることを確認

lang=jaは残っています。元はPath=/shopで保存されているため、Path=/の削除指示は同じ保存項目を指しません。Cookieを消す場合も、保存した範囲と一致させる必要があります。

10元のDomainとPathで削除

Domain=example.test、Path=/shop、Max-Age=0の応答を受け取ります。

curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt http://shop.example.test:18080/delete元の範囲を指定して期限切れにする curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items削除後の要求

今度はlangが消え、theme=darkだけが届きます。Max-Ageが0以下なら期限切れにします。期限の指定にはExpiresもありますが、両方ある場合はMax-Ageが優先されます。

11セッションCookieを読み込まない起動

保存ファイルのセッションCookieを捨てて開始するcurlの-jを指定します。

curl -K hosts.conf -sS -jセッションCookieを保存ファイルから読み込まない -b cookies.txt http://shop.example.test:18080/shop/items

themeには期限がなく、セッションCookieとして保存されていたため、-jでの読込み対象から外れてCookieが空になります。これはcurlの新規セッションの扱いです。ブラウザではセッション復元機能によってセッションCookieが復元される場合があり、終了時の削除を秘密情報の保護策として頼り切らないようにします。

まとめ

Set-Cookieの属性で保存・送信範囲を決め、要求では名前と値をCookieヘッダーへ入れます。

Domainはホスト範囲、Pathはパス境界、有効期限は保存期間に関わります。

更新・削除では名前だけでなくドメインとパスの組合せを一致させます。

操作履歴と解説を振り返れます。

シェル / curl・HTTP/1.1

1
curl -K hosts.conf -sS -i -c cookies.txt http://shop.example.test:18080/set
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 28
Cache-Control: no-store
Set-Cookie: theme=light; Path=/
Set-Cookie: lang=ja; Domain=example.test; Path=/shop; Max-Age=3600

{"stored":"theme and lang"}
2
python3 jar.py
lang=ja domain=.example.test subdomains=TRUE path=/shop persistent=True
theme=light domain=shop.example.test subdomains=FALSE path=/ persistent=False
3
curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items
{"host":"shop.example.test","path":"/shop/items","cookie":"lang=ja; theme=light"}
4
curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shopping
{"host":"shop.example.test","path":"/shopping","cookie":"theme=light"}
5
curl -K hosts.conf -sS -b cookies.txt http://api.example.test:18080/shop/items
{"host":"api.example.test","path":"/shop/items","cookie":"lang=ja"}
6
curl -K hosts.conf -sS -b cookies.txt http://notexample.test:18080/shop/items
{"host":"notexample.test","path":"/shop/items","cookie":""}
7
curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt http://shop.example.test:18080/reject python3 jar.py
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 33
Cache-Control: no-store
Set-Cookie: bad=yes; Domain=other.test; Path=/

{"attempted":"unrelated domain"}
theme=light domain=shop.example.test subdomains=FALSE path=/ persistent=False
lang=ja domain=.example.test subdomains=TRUE path=/shop persistent=True
8
curl -K hosts.conf -sS -b cookies.txt -c cookies.txt http://shop.example.test:18080/update curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items
{"updated":"theme"}
{"host":"shop.example.test","path":"/shop/items","cookie":"lang=ja; theme=dark"}
9
curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt http://shop.example.test:18080/delete-wrong curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 24
Cache-Control: no-store
Set-Cookie: lang=; Domain=example.test; Path=/; Max-Age=0

{"deleted":"lang at /"}
{"host":"shop.example.test","path":"/shop/items","cookie":"lang=ja; theme=dark"}
10
curl -K hosts.conf -sS -i -b cookies.txt -c cookies.txt http://shop.example.test:18080/delete curl -K hosts.conf -sS -b cookies.txt http://shop.example.test:18080/shop/items
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 28
Cache-Control: no-store
Set-Cookie: lang=; Domain=example.test; Path=/shop; Max-Age=0

{"deleted":"lang at /shop"}
{"host":"shop.example.test","path":"/shop/items","cookie":"theme=dark"}
11
curl -K hosts.conf -sS -j -b cookies.txt http://shop.example.test:18080/shop/items
{"host":"shop.example.test","path":"/shop/items","cookie":""}

演習完了