HTML5.JP

Ads

WHATWG - HTML5 Working Draft 日本語訳

4.10 クライアント側のキー/値ペアーのセッションと永続ストレージ

一部、直訳ではなく意訳した部分がございます。原文と表現が異なることがございますので、ご了承ください。この日本語訳は、私が理解を深めるために、自分なりに日本語化したものです。本日本語訳には、翻訳上の誤りがある可能性があります。したがって、内容について一切保証をするものではありません。正確さを求める場合には、必ず原文を参照してください。当方は、この文書によって利用者が被るいかなる損害の責任を負いません。もし誤りなどを見つけたら、当サイトのお問い合わせより連絡いただければ幸いです。

概要

HTML 5 で規定しているクライアントサイド・ストレージに関する仕様です。

HTML 5 で規定しているクライアントサイド・ストレージには、ブラウザが開いている時だけに一時的に利用することを想定した sessionStorage や、永続的にデータを保存することを想定した globalStorage が規定されています。

日本語訳

HTML 5

Working Draft — 27 October 2007

4.10. クライアント側のキー/値ペアーのセッションと永続ストレージ

4.10.1. はじめに

このセクションは規定ではありません。

この仕様では、2つの関連のあるメカニズムを紹介します。それらは、HTTPセッションクッキー [RFC2965]に似ており、クライアント側に構造化データを蓄積するために使います。

一つ目は、ユーザが単一の処理を実行するという想定で設計されています。しかし、同時に異なるウィンドウで複数の処理を実行することもできます。

この場合、クッキーではうまくいきません。例えば、ユーザが2つの異なるウィンドウに同じサイトを開き航空チケットを購入しているとしましょう。もし、そのサイトでは、ユーザがどのチケットを買おうとしているのかを捕捉するためにクッキーを使っていたなら、ユーザが両方のウィンドウでクリックしてページを移動したとき、今購入しているチケットはもう一つののウィンドウへ漏れてしまうでしょう。ユーザは、まったく気づくことなく、同じフライトのチケットを2枚購入してしまうということが起こりえます。

これを解決するために、この仕様では sessionStorage DOM 属性を導入します。サイトは、セッション・ストレージにデータを追加することができます。そして、そのウィンドウに開かれたページと同じドメインのページであれば、どのページからでも、追加したデータにアクセスすることができるようになります。

例えば、ページに、保険が欲しいと示すためにユーザがチェックを入れるチェックボックスがあるとしましょう。:

<label>
 <input type="checkbox" onchange="sessionStorage.insurance = checked">
 I want insurance on this trip.
</label>

後のページで、そのユーザがチェックボックスにチェックを入れたかどうかをスクリプトからチェックすることができます。:

if (sessionStorage.insurance) { ... }

もしユーザがそのサイトを複数のウィンドウで開いていたなら、セッション・ストレージ・オブジェクトのコピーが各ウィンドウごとに割り当てられます。

2つ目のストレージ・メカニズムは、複数のウィンドウを橋渡しし、現在のセッションが終わっても存続するストレージのために設計されたものです。特に、ウェブアプリケーションでは、ユーザが書いた文書全体やユーザのメールボックスのように、何メガバイトというサイズのユーザデータを、パフォーマンスの理由からクライアント側に蓄積したい場合もあるでしょう。

この場合もクッキーではうまく扱うことができません。クッキーはリクエストごとに一緒に転送されてしまうからです。

グローバル・ストレージ領域にアクセスするには、globalStorage DOM 属性を使います。

example.com のサイトは、ページの下部に次のコードを入れることで、ユーザがそのページを表示した回数を表示することができます。:

<p>
  You have viewed this page
  <span id="count">an untold number of</span>
  time(s).
</p>
<script>
  var storage = globalStorage['example.com'];
  if (!storage.pageLoadCount)
    storage.pageLoadCount = 0;
  storage.pageLoadCount = parseInt(storage.pageLoadCount, 10) + 1;
  document.getElementById('count').textContent = storage.pageLoadCount;
</script>

ドメインとサブドメインは、別々のストレージ領域を持ちます。サブドメインは親ドメインのストレージ領域にアクセスすることができます。また、ドメインはサブドメインのストレージ領域にアクセスすることができます。

ストレージ領域(セッション・ストレージとグローバル・ストレージのいずれも)は、文字列を蓄積するものです。ストレージ領域に構造化データを蓄積したい場合は、最初にあなたがそのデータを文字列に変換しなければいけません。

4.10.2. Storage インタフェース

interface Storage {
  readonly attribute unsigned long length;
  DOMString key(in unsigned long index);
  StorageItem getItem(in DOMString key);
  void setItem(in DOMString key, in DOMString data);
  void removeItem(in DOMString key);
};

Storage オブジェクトは、キー/値ペアーのリストへのアクセスを提供します。キー/値ペアーのことを、アイテムと呼ぶこともあります。キーは文字列です。キーにはどんな文字列(空の文字列も含む)を使っても構いません。値は、関連付けられたメタデータを持つ文字列です。この値は、StorageItem オブジェクトによって表されます。

sessionStorageglobalStorage 属性のセクションで規定されてるとおり、各 Storage オブジェクトは、生成時にキー/値ペアのリストに関連付けられます。Storage インタフェースを実装する複数の別々のオブジェクトすべてに対して、同時に、同じキー/値ペアーのリストに関連付けることができます。

キー/値ペアーは関連したメタデータを持ちます。とりわけ、キー/値ペアーには "セキュアコンテンツ専用の安全性" または、"セキュアと非セキュアコンテンツ両用の安全性" のいずれかをセットすることができます。

キー/値ペアーは、"セキュアと非セキュアコンテンツ両用の安全性" がセットされていれば、もしくは "セキュアコンテンツ専用の安全性" がセットされ、かつ、当のスクリプトが安全なブラウジングコンテキスト内で実行されていれば、アクセス可能(accessible) です。

length 属性は、オブジェクトに関連付けられたリストに現存するキー/値ペアーのうち アクセス可能 なペアーの数を返さなければいけません。

key(n) メソッドは、リスト内で n 番目の アクセス可能 なキーの名前を返さなければいけません。キーの順番は、ユーザーエージェントが定義した順番となりますが、キーの数が変更されても、オブジェクトの中では一貫性を保たなければいけません(そのため、キーの 追加 または 削除 によってキーの順番が変わっても構いませんが、ただ単に現存のキーの値が変更されただけで、その順番が変わってしまってはいけません。)。もし、n が 0 未満またはオブジェクト内のキー/値ペアーの数以上だった場合、このメソッドは INDEX_SIZE_ERR 例外を発出しなければいけません。

getItem(key) メソッドは、引数に与えられた key を持つキー/値ペアーを表す StorageItem オブジェクトを返さなければいけません。もし引数に与えられた key がオブジェクトに関連付けられたリストに存在しない場合や、アクセス可能 でない場合、このメソッドは null を返さなければいけません。引き続き、同じセキュリティーコンテキスト内で実行しているスクリプトから同じキーを使ってこのメソッドがコールされた場合は、StorageItem インタフェースの同じインスタンスを返さなければいけません(とはいえ、このようなインスタンスはセキュリティコンテキストを超えて共有されてはいけません。)。

setItem(key, value) メソッドは、まず最初に、オブジェクトと関連付けられたリストに、引数に与えられた key を持つキー/値ペアーがすでに存在するかどうかをチェックしなければいけません。

もし存在しない場合は、引数に与えられた keyvalue を持った新規のキー/値ペアーがリストに追加されなければいけません。このキー/値ペアーを参照する現在もしくは将来の StorageItem オブジェクトは、引数 value に与えられた値を返します。もし値をセットしたスクリプトが安全なブラウジングコンテキスト内で動いているなら、キー/値ペアーは "セキュアコンテンツ専用の安全性" として記録されなければいけません。そうでなければ、"セキュアと非セキュアコンテンツ両用の安全性" として記録されなければいけません。

引数 key がリストに存在した場合、引数 key を持ったキー/値ペアーが アクセス可能 なら、このメソッドは、このキー/値ペアーを参照する現在または将来の StorageItem オブジェクトが引数 value に与えられた値を返すことができるよう、値を更新しなければいけません。もし引数 key を持ったキー/値ペアーが アクセス可能 でないなら、このメソッドは セキュリティ例外 を発出しなければいけません。

sessionStorage and globalStorage 属性のセクションで規定されている通り、setItem() メソッドの呼び出しに成功すると(例えば、例外を発出しなかった場合)、新規に蓄積されたデータにアクセスできる他の HTMLDocument オブジェクト上にイベントが送出されます。

removeItem(key) メソッドは、オブジェクトと関連付けられたリストに引数 key を持ったキー/値ペアーが存在し アクセス可能 なら、そのリストから該当のキー/値ペアーを削除しなければいけません。そのキーを持ったアイテムが存在しない場合は、このメソッドは何もしてはいけません。該当のキーをもったアイテムが存在するものの、それが アクセス可能 でない場合は、このメソッドは セキュリティ例外 を発出しなければいけません。

setItem()removeItem() メソッドは、失敗に対してアトミックでなければいけません。つまり、データストレージ領域に対して変更があった場合、成功するか、そうでなければ、何も変更されないかのいずれかとならなければいけません。

ECMAScript DOM バインディングでは、Storage オブジェクトの列挙は、そのオブジェクトが関連付けられたリスト内に現存し アクセス可能 なキーを通して列挙されなければいけません(その値や実在するインタフェースのメンバーを列挙してはいけません。)。ECMAScript DOM バインディングでは、Storage オブジェクトは参照解除をサポートしなければいけません。オブジェクトのメンバーではない(例えば、Storage インタフェースでもなければ、Object でもない)プロパティを得る場合は、引数にプロパティの名前を与えて getItem() メソッドを呼び出さなければいけません。プロパティをセットする場合は、第一引数にプロパティの名前を、第二引数に対応した値を与えて、setItem() メソッドを呼び出さなければいけません。

4.10.3. StorageItem インタフェース

Storage オブジェクトのアイテムは、StorageItem インタフェースを実装したオブジェクトによって表されます。

interface StorageItem {
           attribute boolean secure;
           attribute DOMString value;
};

ECMAScript DOM バインディングにおいては、StorageItem オブジェクトは value 属性の値に文字列化しなければいけません。

value 属性は、オブジェクトによって表されるキー/値ペアーの現在値を返さなければいけません。属性がセットされたら、ユーザーエージェントは、StorageItem オブジェクトが第一引数として関連付けているキーと第二引数として新たに与えられた属性値を使って、StorageItem オブジェクトが関連付けられている Storage オブジェクトの setItem() メソッドを呼び出さなければいけません。

StorageItem オブジェクトは live でなければいけません。つまり、もとの Storage オブジェクトはそのキー/値ペアーを更新しなければならず、StorageItem オブジェクトは常にそれらが表わすキー/値ペアーの本当の値を返さなければいけません。

キー/値ペアーが削除されたら、StorageItem オブジェクトはその値が空の文字列だったかのように振舞わなければいけません。処理時においては、キー/値ペアーが再生成されるでしょう。

secure 属性は、安全性が考慮されていないブラウジングコンテキストのスクリプトからアクセスされたりセットされた場合(つまり、そのページが SSL ページでない場合)は、INVALID_ACCESS_ERR 例外を発出しなければいけません。

もしブラウジングコンテキストが安全であるなら、secure 属性は、そのキー/値ペアーが "セキュアコンテンツ専用の安全性" になっている場合は true を、 "セキュアと非セキュアコンテンツ両用の安全性" になっている場合は false を返さなければいけません。 true がセットされたら、そのキー/値ペアーに "セキュアコンテンツ専用の安全性" としてフラグ付けしなければいけません。false がセットされたら、そのキー/値ペアーに "セキュアと非セキュアコンテンツ両用の安全性" としてフラグ付けしなければいけません。

安全でないブラウジングコンテキストで実行しているスクリプトから StorageItem オブジェクトを取り出し、それから、実行中のスクリプトでそのアイテムに "セキュアコンテンツ専用の安全性" フラグをセットしたとしても、その StorageItem オブジェクトは最初のスクリプトから利用可能であり続けなければいけません。そのスクリプトからそのオブジェクトの値を読み取ることが可能となります。しかし、値をセットしようとするあらゆる試みは、前述の通り、例外を発出し始めます。そして、そのキー/値ペアーは適切な Storage オブジェクトにもう現れることはありません。

4.10.4. sessionStorage 属性

sessionStorage 属性は、現在の トップレベル・ブラウジングコンテキスト 特有のストレージ領域を表します。

トップレベル・ブラウジングコンテキスト はそれぞれ、セッションストレージ領域をドメインごとに一つだけ持ちます。

ユーザーエージェントは、ブラウジングコンテキストのセッションストレージ領域からデータを失効すべきではありません。しかし、ユーザーからデータ削除のリクエストがあった場合や、UA がそれがストレージスペースを制限したことを検知した場合や、セキュリティ上の理由があれば、そうしても構いません。ユーザーエージェントは、そのデータにアクセスできるスクリプトが実行している間は常に、データ削除を避けるべきです。トップレベル・ブラウジングコンテキストが破壊された(その結果、永久的にユーザーからアクセスできない)場合、そのセッションストレージ領域に蓄積されたデータを破棄することができます。本仕様で説明されている API は、それ以降、そのデータを取り出だす方法を一切提供しません。

ユーザーエージェントは、再起動後のセッション再開をサポートしているかもしれませんので、ブラウジングコンテキストの存続期間は、実際のユーザーエージェントのプロセス自身の存続期間と一致しないことがあります。

HTMLDocument が新規に生成されたら、ユーザーエージェントは、そのドキュメントの トップレベル・ブラウジングコンテキスト がその ドキュメントのドメイン 用のセッションストレージを割り当てたかどうかをチェックしなければいけません。もし割り当てられていないなら、そのドキュメントのドメイン用に新規のストレージ領域を生成しなければいけません。

ドキュメントの関連付けられた Window オブジェクトの sessionStorage 属性のための Storage オブジェクトは、その時、そのドメインのセッションストレージ領域に関連付けられなければいけません。

既存の ブラウジングコンテキスト を複製することで、新規の トップレベル・ブラウジングコンテキスト が生成された場合、新規のブラウジングコンテキストはもとのコンテキストと同じセッションストレージ領域を使って開始しなければいけません。しかしその2つのコンテキストはそれ以降分離されなければならず、決して相互作用してはいけません。

現存の ブラウジングコンテキスト 内のスクリプトによって、または、ユーザーが現存のブラウジングコンテキスト内のリンクを辿ることによって、または、HTMLDocument に関連する他の方法によって、トップレベル・ブラウジングコンテキスト が新規に生成された際、新規のコンテキストの最初の HTMLDocument が、生成元となる HTMLDocument と同じ ドメイン を持つなら、新規のブラウジングコンテキストは単一のセッションストレージ領域で開始しなければいけません。そのストレージ領域は、もとのブラウジングコンテキスト内にある該当のドメインのセッションストレージ領域の複製でなければいけません。それ以降は分離されなければならず、その2つのストレージ領域は決して相互作用してはいけません。

後述の通り、setItem() メソッドがセッションストレージ領域と関連付けられた Storage オブジェクト x 上で呼び出された際、もしそのメソッドが セキュリティ例外 を発出しなければ、Window オブジェクトの sessionStorage 属性の Storage オブジェクトが同じストレージ領域と関連付けられているすべての HTMLDocument オブジェクトにおいて、x 以外では、storage イベントが発生しなければいけません。

4.10.5. globalStorage 属性

interface StorageList {
  Storage namedItem(in DOMString domain);
};

globalStorage オブジェクトは、各ドメインに対応する Storage オブジェクトを提供します。

ECMAScript DOM バインディングにおいては、StorageList オブジェクトは、そのオブジェクトのメンバーではないプロパティを取得する際に、引数にプロパティの名前を指定する namedItem() メソッドを呼び出さなければいけないよう、参照解除をサポートしなければいけません。

ユーザーエージェントは、1ドメイン毎に1セットのグローバルストレージ領域を持たなければいけません。

ユーザーエージェントは、セキュリティ上の理由があれば、ユーザーがリクエストすれば、グローバルストレージ領域からデータを失効すべきです。ユーザーエージェントは、データにアクセスすることができるスクリプトが実行している間は常に、データの削除を避けるべきです。グローバルストレージ領域に蓄積されたデータは、ユーザーにとって非常に重要なものであると心得るべきです。グローバルストレージ領域は、ウェブアプリケーションによってユーザーが作成したドキュメントを蓄積するためにを使われる考えられます。

namedItem(domain) メソッドは、次に示すルールにしたがって、引数に指定されたドメインと関連付けられた Storage オブジェクトを返そうとします。

domain は、まず最初に、"." 文字 (U+002E 終止符) を区切りとした文字列の配列に分割されます。引数 domain が空文字の場合は、配列も同様に空となります。引数 domain が空ではないがドットが含まれていない場合は、配列の要素は1つになり、その要素は引数 domain と同等です。引数 domain に連続したドットが含まれている場合は、配列の要素に空の文字列が含まれます。(例えば、文字列 "hello..world" は3つの文字列 "hello", "", "world" に分割され、真ん中の要素が空の文字列となります。)

配列の各要素には、AllowUnassigned と UseSTD3ASCIIRules フラグの両方を使って、 IDNA ToASCII アルゴリズムを適用しなければいけません。[RFC3490] 要素の文字列の一つが、長すぎたり、不正な文字が含まれていたりするなどの理由で、ToASCII での変換に失敗したら、ユーザーエージェントは SYNTAX_ERR 例外を発出しなければいけません。 [DOM3CORE] この段階後の要素は、US-ASCII 文字のみで構成されます。

次に、配列の要素を小文字に変換しなければいけません。これは US-ASCII しか関係がありませんので、A-Z の範囲の文字を、対応する a-z の範囲の文字に変換するだけとなります。

下記の通り、この配列は、別の配列との比較に使います。なお、この配列の要素をドット (U+002E) で連結すれば、正規化リクエストドメインとなります。

もし元の domain が "Åsgård.Example.Com" だったなら、生成される配列は3つの要素 "xn--sgrd-poac", "example", and "com" を持つことになります。そして、正規化リクエストドメインは "xn--sgrd-poac.example.com" となります。

次に、リクエストドメインへのアクセスが許可されているなら、スクリプトの origin と呼んでいるドメイン部分が抽出されます。

サーバの IP アドレスしか分からない場合のように、スクリプトの origine にドメイン部分が存在せず、さらに、正規化リクエストドメイン が空の文字列でない場合、ユーザーエージェントは セキュリティ例外 を発出しなければいけません。

もし 正規化リクエストドメイン が空の文字列なら、このアルゴリズムの残りをスキップすることができます。これは、次の状況での理由からです。以下の2つの配列を比較しても、それらは常に同じであることが分かるでしょう。 — このような状況における最初の配列もまた空であり、ストレージエリアへのアクセス許可は常に与えられます。

スクリプトの origin のドメイン部分にドット (U+002E) がない場合、文字列 ".localdomain" をスクリプトのドメインに追加しなければいけません。

次に、前述domain 引数で説明した通り、スクリプトの origin のドメイン部分を、分離し、ASCII に変換し、小文字に変換して、配列に変えなければいけません。

2つの配列のうち、長い方の配列の最初の要素から削除して、短い方の長さに切り詰めなければいけません。

domain 引数が "www.example.com" で、スクリプトの origin のドメイン部分が "example.com" なら、最初の配列は3つの要素 ("www", "example", "com") を持った配列となります。そして、2番目の配列は、2つの要素 ("example", "com") を持った配列となります。最初の配列の先頭部分を削除して短くし、2つの配列を同じ要素を持った配列 ("example", "com") にします。

もし2つの配列が文字列比較において要素ごとに等しくなければ、ユーザーエージェントは セキュリティ例外 を発出しなければいけません。

そうでなければ、ユーザーエージェントは 正規化リクエストドメイン に対してグローバルストレージ領域を割り当てたかどうかをチェックしなければいけません。

次に、ユーザーエージェントは、そのドメインのグローバルストレージ領域と関連付けられた Storage オブジェクトを生成しなければいけません。

リクエストされた domain が、トップレベルドメイン、空の文字列、 "co.uk" や "ca.us" といった国固有のサブドメインだった場合、この関連づけられるグローバルストレージ領域は パブリックストレージ領域 と言われているものとなります。

setItem() メソッドは、ドメイン d 用のグローバルストレージ領域と関連付けられた Storageオブジェクト上で呼び出されるかもしれません。それは、Window オブジェクト x と関連付けられた StorageList オブジェクトによって生成されます。これが起こったときは常に、そのメソッドが例外を発出しなかったなら、後述のとおり、次の条件に一致するすべての HTMLDocument オブジェクトで storage イベントが発生しなければいけません。

つまり、そのドメインのグローバルストレージ領域にアクセスできるすべての他のドキュメントに、変更を通知することになります。

4.10.6. storage イベント

前述の2セクション (セッションストレージ, グローバルストレージ)で説明した通り、ストレージに変更が生じると、HTMLDocument では storage イベントが発生します。

これが発生すると、名前空間を持たないところで storage イベントが body 要素 上で発生しなければいけません。このイベントは、バブリングし、キャンセルはできず、デフォルトアクションがありません。そして、後述の StorageEvent インタフェースを使います。

しかし、その時点で、ターゲットとなる HTMLDocument オブジェクトがアクティブでない可能性があります(恐らく実際にはセッションストレージ領域が該当するでしょう。)。例えば、それがセッション履歴の中で 現在のエントリ となっていないかもしれません。一般的に、ユーザーエージェントは履歴内にあるページでの実行からスクリプトを停止します。そのような場合、ユーザーエージェントは、問題の HTMLDocument オブジェクトが再度アクティブになる時までイベントの発生を遅らせなければいけません。

同じ HTMLDocument オブジェクトに複数の遅延 storage イベントがある場合、ユーザーエージェントは同じ domain 値を持ったイベントを統合すべきです(重複分を取り除くのです)。

遅延 storage イベントを溜めてきたページの DOM が破棄されたなら、遅延イベントも同様に破棄されます。

interface StorageEvent : Event {
  readonly attribute DOMString domain;
  void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString domainArg);
  void initStorageEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString domainArg);
};

initStorageEvent()initStorageEventNS()メソッドは、DOM3 イベントインタフェースにある同様の名前のメソッドと同じように、イベントを初期化しなければいけません。 [DOM3EVENTS]

StorageEvent イベントオブジェクトの domain 属性には、グローバルストレージ領域の場合は、そのストレージ領域と関連付けられたドメインの名前をセットしなければいけません。また、セッションストレージ領域の場合は、文字列 "#session" をセットしなければいけません。

4.10.7. ストレージ領域の各種実装要件

4.10.7.1. ディスクスペース

ユーザーエージェントは、該当ページのドメインに対して設定された値に基づいて、ドメイン単位で利用可能な容量を制限すべきです。

ユーザーエージェントは、ストレージ領域単位で利用可能な容量を制限すべきではありません。そうしないと、サイトは、サブドメインがいくつあってもデータを蓄積できてしまいます。例えば、a1.example.com, a2.example.com, a3.example.com などそれぞれで上限まで蓄積でき、ドメイン単位の制限が回避されてしまいます。

ユーザーエージェントはさらなる容量制限メカニズムも考慮すべきです(例えば、ドメインのサブドメインに提供する容量をグループとして制限します。)。こうすることで、悪意のある者が、DOS攻撃 (denial-of-service attack) で複数のサブドメインすべてからグローバルストレージ領域にデータを追加しようとしても、スクリプトを実行することができません。

ユーザーエージェントは、ドメイン単位の領域の容量制限に達したら、サイトにもっと容量を割り当てるよう、ユーザーに通知するかもしれません。こうすることで、例えば、ユーザーのコンピューター上にユーザーが作成した多くのドキュメントを蓄積することができるようになります。

ユーザーエージェントは、ユーザーに対して、各ドメインごとにどれくらいのサイズの領域を使っているのかを分かるようにすべきです。

setItem()コールの最中にストレージ領域の容量制限に達したら、ユーザーエージェントは例外を発出すべきです。

通常、ドメインごとに5メババイトの任意制限を推奨します。実装に関するフィードバックは歓迎です。将来的にはフィードバックを参考にして、この提案が更新されるでしょう。

4.10.7.2. スレッド

複数のブラウジングコンテキストが同時に期待通りにグローバルストレージ領域にアクセスできなければいけません。スクリプトから、現在のスクリプト実行を検知できるようにしてはいけません。。

これは、スクリプト自身から見て期待どおりとなるためというよりは、スクリプトの実行中に Storage オブジェクトの length 属性が決して変更されないことを保証するために必須としています。

この要件の実装には様々な方法があります。もし一つのブラウジングコンテキスト内で実行しているスクリプトがグローバルストレージ領域にアクセスしたら、UA は、他のブラウジングコンテキストのスクリプトがいかなるグローバルストレージ領域にアクセスしようとしても、最初のスクリプトの処理が完了するまで他のブラウジングコンテキストのスクリプトをブロックする、という方法が一つです。(同様に、一つのブラウジングコンテキストのスクリプトがセッションストレージ領域にアクセスしたら、同じトップレベルブラウジングコンテキストと同じドメインを持つあらゆるスクリプトは、それらのセッションストレージ領域にアクセスしても、最初のスクリプトの処理が完了するまで、ブロックされます。)もう一つの(潜在的にはより効果的だが恐らくより複雑な)実装方法として、楽観的なトランザクションのスクリプト実行を使う方法があります。この仕様では、前述の要件に適合する限り、個別の実装方法を一切縛ることはありません。

4.10.8. セキュリティとプライバシー

4.10.8.1. ユーザー追跡

サードパーティの広告主(または、複数のサイトに配布されたコンテンツを取得することができるエントリー)は、複数のセッションをまたがってユーザーを追跡するために、そのドメインのグローバルストレージ領域に蓄積されたユニークな識別子を使うことができ、精度の高いターゲッティング広告を実現するためにユーザーの嗜好のプロファイルを構築することができます。ユーザープロフィールを把握しているサイト(例えば、認証が必要なeコマースサイト)と連携すれば、圧政的なグループは、純粋な匿名のウェブ利用の世界と比べて、より高い正確性をもった個人をターゲットにすることができます。

globalStorage オブジェクトは、複数のドメイン上でユーザーを追跡することを協力するサイトのための一つの方法を提供します。それは、どんなドメインでもアクセス可能な "パブリック" トップレベルドメインのストレージ領域に識別データを蓄積するのです。

ユーザー追跡のリスクを軽減するいくつかのテクニックがあります。

これらの提案は、ユーザー追跡用のAPIのちょっとした利用を妨げることはありますが、全体をブロックすることはありません。単一のドメイン内であれば、サイトは複数のセッションをまたいでユーザー追跡を継続することができます。そして、そのサイトによって得られた特定情報(名前、クレジットカード番号、住所)とともに、サードパーティへすべての追跡情報を渡すことができます。サードパーティが複数のサイトとともにそのような情報の入手に協力すれば、プロファイルを作ることができるのです。

しかし、ユーザーエージェントから一切の協力が得られなくても、ある程度のユーザー追跡は可能です。例えば、URI のセッション識別子を使います。これは、すでに一般的には害がない目的で使われますが、簡単にユーザー追跡(遡及的にでさえ)に再利用できるテクニックです。この情報は、他のサイトと共有することができます。訪問者の IP アドレスやその他のユーザー特定データ(user-agent ヘッダーや設定情報など)を、分離されたセッションを分かりやすいユーザープロファイルに統合するために使います。

永続的ストレージ用のユーザーインタフェースが、HTTP セッションクッキーのデータと区別して、永続ストレージ機能のデータを提供するなら、ユーザーは一方だけのデータを削除してしまうでしょう。これは、ユーザーが自分のプライバシーを守ろうとしたにも関わらず、その意に反して、サイトはお互いに冗長なバックアップとして2つの機能を使うことができるでしょう。

4.10.8.3. "パブリック" ストレージ領域の統合

"パブリック" グローバルストレージ領域は、多くの異なるパーティーからのコンテンツによってアクセスできるため、サードパティーのサイトは、元のサイトが予期しない方法で、それらの領域に蓄積された情報を削除したり変更することが可能です。

慎重を期するデータを蓄積するために、"パブリック" グローバルストレージ領域を使ってはいけません。"パブリック" グローバルストレージ領域に蓄積されたデータを信用してはいけません。

4.10.8.4. クロス・プロトコルとクロス・ポート攻撃

この API は、HTTP や FTP といったホストベースのプロトコル上で提供されるコンテンツを区別しません。そして同じホスト上の異なるポートから提供されるコンテンツも区別しません。

そのため、例えば、HTTPポート 80 から提供されるページよって "www.example.com" 用のグローバルの永続的ストレージに蓄積されたデータは、http://example.com:18080/ で提供されるページに対しても利用可能となります。たとえ後者が異なるユーザーの制御下の試験サーバだとしてもです。

そのデータはユーザーエージェントによって有線で送信されないため、それ自体でセキュリティーリスクとなるわけではありません。しかし、慎重を期する情報を扱うホストのサブセットである完全修飾ホスト名を持つすべてのホストが、元のホスト自身と同等に安全であることを確認するための適切なステップを踏まなければいけません。

同様に、ホスト上に永続的ストレージが使われるウェブサーバがあるなら、ポートにかかわらず、ホスト上のすべてのウェブサーバが等しく信用されているかを確認しなければいけません。例えば、ウェブサーバが永続的ストレージ機能を利用するプロダクションサービスを実行しているなら、そのマシンにアクセスでき、他のポート上でウェブサーバを実行することができる他のユーザーは、そのプロダクションサービスによって追加された永続的ストレージにアクセスすることができるでしょう(ユーザーをだまして自身のページに訪問させることができると仮定)。

しかし、もし、ユーザーをだまして、これらユーザーによって利用されるプロダクションサービスと同じホスト名で異なるポートでウェブサーバを訪問させることができるなら、そのサイトの見た目を簡単に偽造することができ、それゆえに、ユーザーをだまして、直接、偽のサイトで認証させることができるでしょう。本当のサイトへのリクエストをフォワードし、その過程で信用証明を盗むのです。それゆえに、永続的ストレージ機能は、関連するリスクを最小限に食い止めるよう、考えられてます。

もし誰かが、あるポート上でサーバにたどり着き、それから、その URI に人々を呼び込むことができたとしたら、どうだろうか? 彼らは、それ以上のやりとりがなくても、すべてのデータを盗むことができるかもしれない。ポート番号を(暗黙のうちに)比較した文字列の最後に追加するのは、どうだろう?

4.10.8.5. DNS なりすまし攻撃

DNS なり済まし攻撃の可能性のため、本当に信頼できるドメインであると主張するホストが、そのドメインに由来するかどうかを保証することはできません。secure 属性は、信頼できるキー/値ペアーを安全な証明書(またはそれに近いメカニズム)を使って認証されたページにアクセス可能であるものとして印付けするために与えられます。

製作者は、確実に、慎重を期するアイテムを "セキュアと非セキュアコンテンツ両用の安全性" として印付けしないようにしなければいけません。(競合条件のリスクを避けるために、セキュアコンテキストのスクリプトによって蓄積されたデータは、デフォルトで、"セキュアコンテンツ専用の安全性" として印付けされます。)

4.10.8.6. クロス・ディレクトリ攻撃

geocities.com でユーザーのコンテンツをホスティングしているように、一つのホスト名を異なる製作者で共有すると、すべてが一つの永続的ストレージオブジェクトを共有します。パス名によるアクセス制限機能はありません。そのため、共有ホストの制作者は永続的ストレージ機能の利用を避けることが推奨されます。同じストレージ領域を読み書きしようとする制作者にとっては、あまり関係がない話ですが。

パス制限機能が使えるようになったとしても、通常のDOMスクリプティングのセキュリティモデルでは、この保護を迂回して、どんなパスのデータにもアクセスできてしまうでしょう。

4.10.8.7. ホストに一致したパブリックストレージ領域

もし、"パブリック" グローバルストレージ領域がホストに一致していれば、しかし dyndns.org や uk.com のようなサードパーティーのサブドメインを使ったプライベートドメイン用なら通常そうなりますが、その "パブリック" ドメインに一致するホストは、サードパーティーのサブドメインのストレージ領域すべてにアクセスすることができます。一般的に、製作者は、関連するすべてのドメインのオペレータが信用されない限り、globalStorage API を、慎重を期するデータに使わないようにしてください。

ユーザーエージェントは、することから、"パブリック" グローバルストレージ領域に一致するホストから、自身以外のあらゆるストレージ領域にアクセスできないようにすることで、この問題を軽減しても構いません。

4.10.8.8. パブリックストレージ領域に一致せず信用されていない上位レベルドメインに直面したストレージ領域

製作者は、信用されていない自身のサブセットである完全修飾ドメイン名を持ったホストがあるなら、グローバルストレージ API を使って慎重に期すべきデータを蓄積すべきではありません。例えば、finance.members.example.net の製作者は、example.net を実行するホストを信用していない限り、finance.members.example.net のストレージ領域に慎重に期すべき金銭にまつわるユーザーデータを蓄積すべきではありません。

4.10.8.9. 信用されていないサブドメインに直面したストレージ領域

example.com のホスト上でコンテンツを公開している製作者が、globalStorage API を使いたいのだが、そのホストのサブドメイン上のコンテンツにはデータにアクセスさせたくないなら、製作者は private.example.com などの他の存在しないサブドメイン名を使ってデータを蓄積するべきです。こうすることで、そのホスト(親ドメインも含む)に対してだけアクセス可能にすることができ、実在するサブドメイン(upload.example.com など)に対してはアクセスできないようにすることができます。

4.10.8.10. 実装のリスク

この永続的ストレージ機能を実装した場合、2つの主なリスクがあります。悪意のあるサイトが他のドメインから情報を読み取れてしまう点と、悪意のあるサイトが他のドメインから読み取られた情報を書き込めてしまう点です。

サードパーティーのドメインから読み取られると想定していないデータをサードパーティーのサイトに読み取らせることは、情報漏洩 を引き起こします。例えば、あるドメイン上のユーザーのショッピング希望リストが、ターゲッティング広告用の他のドメインで使われることがあるでしょう。もしくは、文書処理サイトによって蓄積されたユーザーの製作中の機密文書が、競合他社のサイトによって調査されることがあるでしょう。

サードパーティーのサイトに他のドメインのストレージ領域にデータを書き込ませることは、情報なりすまし を引き起こします。これは、危険そのものです。例えば、悪意のあるサイトがユーザーの希望リストにアイテムを追加することがあるでしょう。もしくは、悪意のサイトが、犠牲のサイト上でユーザー行動を追跡するために使うことができる既知の ID をユーザーのセッション識別子にセットすることがあるでしょう。

トップレベルドメイン名に一致するホスト名を持つローカルドメイン上のサーバによってもリスクがもたらされます。例えば、"com" や "net" というホスト名を持ったローカルドメインです。そのようなホストは、もし .localdomain を正しく末尾に追加する実装がなされていないと、そのトップレベルドメイン用の UA の永続的ストレージ内に蓄積されたすべてのデータにフルアクセスできてしまうかもしれません。

それゆえに、厳密に本仕様で説明されているモデルに従うことが、ユーザーセキュリティーにとって重要なのです。

さらに、 "パブリック" グローバルストレージ領域に関連した多くのオプションの制限は、前セクションで提示されています。この API は、これらの制限をサポートしない、もしくは、完全にはサポートしないことが、結果的に危機的なセキュリティー問題に至らないようにすることを考えて設計されています。しかし、それでもなお、"パブリック" ドメインのリストを生成し、それを維持し、前述の制限を適用する実装が奨励されます。

サイト運営者情報 | プライバシーポリシー | 当サイトのご利用条件 | お問い合わせ | サイトマップ
Copyright © 2007-2011 Futomi Hatano (@futomi) All Rights Reserved.