発行後に報告されたエラーや問題については、正誤表をご確認ください。
また、 翻訳もご覧ください。
Copyright © 2018 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
WebSubは、あらゆる種類のWebコンテンツの発行者とその購読者との間の通信のための共通メカニズムを、HTTPウェブフックに基づいて提供します。購読リクエストはハブを通じて中継され、ハブがリクエストを検証・確認します。その後、ハブは新規または更新されたコンテンツを利用可能になった時点で購読者に配信します。WebSubは以前はPubSubHubbubとして知られていました。
このセクションは、本書が公開された時点での文書のステータスについて説明します。他の文書が本書に取って代わる場合があります。現在のW3Cの出版物や、この技術報告書の最新版は、W3C技術報告一覧(https://www.w3.org/TR/)で確認できます。
この文書はSocial Webワーキンググループによって勧告として発行されました。 この文書に関するご意見を歓迎します。興味のある方はどなたでも、ワーキンググループのIssueトラッカーを通じて実装情報やバグ報告、その他の意見をお寄せください。これらはSocial Webコミュニティグループで議論され、今後の仕様のバージョンで検討されます。
ワーキンググループの実装レポートもご覧ください。
この文書はW3Cメンバー、ソフトウェア開発者、その他のW3Cグループや関係者によってレビューされ、ディレクターによりW3C勧告として承認されています。 本書は安定した文書であり、参考資料としてまたは他の文書から引用することができます。W3Cが勧告を出す役割は、仕様に注目を集め、その広範な導入を促進することにあります。これにより、Webの機能性と相互運用性が向上します。
この文書は W3C パテントポリシーのもとで運営されているグループによって作成されました。 W3Cは、グループの成果物に関連して公開特許開示リストを管理しています。 そのページには、特許開示の方法についても記載されています。特許に関する実際の知識を持ち、必須特許請求が含まれていると信じる個人は、 W3Cパテントポリシー第6節に従ってその情報を開示しなければなりません。
この文書は、2017年3月1日付W3Cプロセス文書に従って管理されています。
(本セクションは規範的でありません。)
このプロトコルの初期バージョンはPubSubHubbubと呼ばれていました:
この文書内の "MUST(必須)"、"MUST NOT(してはならない)"、"REQUIRED(要求される)"、"SHALL(しなければならない)"、"SHALL NOT(してはならない)"、 "SHOULD(推奨)"、"SHOULD NOT(非推奨)"、 "RECOMMENDED(推奨される)"、"MAY(してもよい)"、および "OPTIONAL(任意)" の用語は、[RFC2119]で定義された通りに解釈されます。
WebSubは3つの役割:発行者、購読者、ハブを定義します。本セクションでは各役割の適合基準について説明します。
適合する購読者:
適合するハブ:
hub.callback、hub.mode、hub.topicパラメータ付きの購読リクエストを受け付けなければなりません。
hub.secretパラメータ付きの購読リクエストも受け付けなければなりません。
hub.secretで行われた場合はX-Hub-Signatureヘッダーを送信しなければなりません。
本仕様は、各機能について少なくとも2つの独立した相互運用可能な実装によってCR段階を終了しています。各機能は異なる製品によって実装されている場合があります。全ての機能を単一製品が実装する必要はありません。この基準のため、以下の用語を定義します:
WebSub発行者とは、1つ以上のリソースURLでトピックとハブURLを広告する実装です。適合基準は上記適合クラスに記載されています。
WebSub購読者とは、リソースURLからハブとトピックのURLを発見し、ハブに購読し、ハブからのコンテンツ配信リクエストを受け入れる実装です。購読者は認証付きコンテンツ配信をサポートしてもよい。適合基準は適合クラスに記載されています。
WebSubハブとは、購読リクエストを処理し、対応するトピックURL更新時に購読者へコンテンツを配信する実装です。ハブは秘密付き購読をサポートし、要求があれば認証付きリクエストを配信しなければなりません。ハブはリクエストでトピックURLの全内容を配信しなければならず、内容が対応していれば差分のみとすることもできます。適合基準は適合クラスに記載されています。
各実装は異なる主体が開発し、互いにコードを共有・再利用・派生してはならず、仕様実装に無関係な部分のみ例外とします。
特定の機能について、ハブが定義された動作を実行し、購読者がハブから想定された応答を受け取り、さらにハブも購読者へ正しい応答を返す場合、その購読者・ハブ実装ペアはその機能で「相互運用可能」とされます。
終了基準の評価上、以下の各項目が個別の機能と見なされます:
ディスカバリーメカニズムは、少なくとも2つのURLの特定を目的とします。
発行者は、耐障害性や冗長性のため複数のハブに広告・配信したい場合があります。もし1つのハブで更新の伝播に失敗した場合、複数の独立したハブを利用することで、購読者への配信の確率が高まります。したがって、購読者は広告された複数のハブのうち1つまたは複数に購読しても良いということです。
本プロトコルで現在サポートされているディスカバリーメカニズムは次の通りです。発行者は、これらのうち少なくとも1つを実装しなければなりません:
多くの年で<link>は<head>の中にのみ配置することが推奨されています。そのため、消費側のコードが<head>しかチェックしない場合があります。したがって、HTMLの<body>ではなく<head>のみに<link>タグを設置した方がより堅牢です。
GET /feed HTTP/1.1
Host: example.com
HTTP/1.1 200 Ok
Content-type: text/html
Link: <https://hub.example.com/>; rel="hub"
Link: <http://example.com/feed>; rel="self"
<!doctype html>
<html>
<head>
<link rel="hub" href="https://hub.example.com/">
<link rel="self" href="http://example.com/feed">
</head>
<body>
...
</body>
</html>
ディスカバリーを行う際、購読者は以下の順に3つのディスカバリーメカニズム全てを実装し、最初に一致した箇所で止める必要があります:
実用上、rel=selfのURLは単一の表現のみを提供することが重要です。ハブは、購読者によるディスカバリー時にどのMedia Type([RFC6838])や言語が要求されたかを知る術が無いため、適切な表現でコンテンツを配信できなくなります。
ただし、初期ディスカバリー時のHTTPヘッダーに応じて適切なrel=selfを返すことで、コンテンツネゴシエーションを行うことは可能です。たとえば、/feedへのAcceptヘッダーがapplication/json の場合、/feed.jsonをrel=selfとして返せます。
以下の例では、トピックURLが送信されたAcceptヘッダーに応じて異なるLinkヘッダーを返す方法を示しています。
GET /feed HTTP/1.1
Host: example.com
Accept: application/json
HTTP/1.1 200 Ok
Content-type: application/json
Link: </feed.json>; rel="self"
Link: <https://hub.example.com/>; rel="hub"
{
"items": [...]
}
GET /feed HTTP/1.1
Host: example.com
Accept: text/html
HTTP/1.1 200 Ok
Content-type: text/html
Link: </feed.html>; rel="self"
Link: <https://hub.example.com/>; rel="hub"
<html>
...
同様に、このテクニックはAccept-Languageヘッダーで指定された言語に応じて異なるrel=selfURLを返すためにも利用できます。
GET /feed HTTP/1.1
Host: example.com
Accept-Language: de-DE
HTTP/1.1 200 Ok
Content-type: text/html
Link: </feed-de.json>; rel="self"
Link: <https://hub.example.com/>; rel="hub"
{
"items": [...]
}
トピックURLの購読は、連続してまたは間隔を空けて発生する4つの段階で構成されます。
購読解除も同様の方法で動作しますが、1つのパラメータだけが購読解除の意思を示すように変更される点が異なります。また、ハブは購読解除リクエストについて発行者との検証は行いません。
購読は、購読者がハブURLにHTTPSまたはHTTPのPOSTリクエスト [RFC7231] を送信することで開始されます。このリクエストは 必ず application/x-www-form-urlencoded(Section 4.10.22.6 [HTML5] 参照)のContent-Typeヘッダーを持ち、必ず文書文字エンコーディングとしてUTF-8 [Encoding]を使用し、ボディ内で以下のパラメータを規定通りにフォーマットして含めなければなりません:
購読者は追加のHTTP [RFC7230]リクエストパラメータや、ハブが必要とする場合はHTTPヘッダーを含めてもかまいません。
ハブは理解できない追加リクエストパラメータを必ず無視する必要があります。
ハブは既に有効な購読について、購読者の再リクエストを必ず許可する必要があります。購読または購読解除の各リクエストは、アクションが検証されてから特定のトピックURLとコールバックURLの組み合わせに対し前回の購読状態を必ず上書きします(Section 4.3)。検証に失敗した場合、購読状態は変更しません。これにより、購読者はリース秒数の終了前に途切れることなく購読を更新できます。購読者は将来の購読で新しい hub.secret を利用しても、hub.secret 無しで新たな購読を行っても構いません。
トピックおよびコールバックURLは HTTPまたはHTTPS スキームを使って構いません [RFC7230] [RFC2818]。トピックURLは発行者がディスカバリー段階でSelf Link Headerに広告したURLでなければなりません(Section 3)。ハブはトピックURLが発行者によって広告されたものと合致しない場合には、購読を拒否することができます。他はURL仕様 [URL]に従う自由形式です。ハブは常にこれらのURLパラメータの予約されていない文字をデコードしなければなりません([URL] section 1.2 「Percent-encoded bytes」参照)。
コールバックURLは推測されにくく一意のURLであるべきです([capability-urls])。またHTTPSを利用することが望ましいです。コールバックURLは、ハブが購読を確認しコンテンツを届ける際の購読者への認証の役割も果たします。さらにコールバックは複数のハブで再利用せず、購読更新時には変更されるべきです。
コールバックURLには任意のクエリストリングパラメータを含めてもよい(例: ?foo=bar&red=fish)。ハブは検証リクエスト中に新しいパラメータを必ずリスト末尾にアンパサンド (&) で結合して付加し、既存の検証用パラメータ名と重複する場合は上書きしてはいけません。コンテンツ配信時は、ハブがPOSTリクエスト時にリクエストのボディでなくURL部分にクエリストリングを含めます。
ハブURLがWebSubをサポートしており、購読または購読解除リクエストを処理可能な場合は、購読リクエストに対し 必ず HTTP [RFC7231] 202 "Accepted" 応答を返し、その後そのリクエストをハブが(Section 4.3)検証・(Section 4.2)確認すると示します。ハブはこれらの検証・確認をできる限り早く行うべきです。
ハブが購読リクエストにエラーを見つけた場合は、適切なHTTPエラーコード(4xxまたは5xx)必ず返します。その際、クライアント開発者がエラー内容を理解できるよう応答ボディにプレーンテキストでエラー説明を返すべきですが、これはエンドユーザー表示目的ではありません。ハブは自身のポリシー(例: ドメイン認可、ポート番号など)に基づいてコールバックURLやトピックURLを拒否できます。ただし検証や意図確認はHTTP応答後に非同期で開始されるため、HTTP応答が検証結果や処理結果に依存してはなりません。
ハブURLが購読・購読解除リクエストを処理できない場合は、WebSubをサポートする他のハブへリダイレクトしてもよい。その場合はHTTP [RFC7231] 307(仮リダイレクト)または308(恒久リダイレクト)応答を返し、必ずHTTP [RFC7230] Locationヘッダーで推奨するハブのURLを示します。購読者は新しいハブURLで再リクエストします。
購読はハブ側でさらなる詳細を求めて受け入れまたは拒否の判断をする場合があります。ハブは発行者に購読受理の可否を確認してもかまいません。
購読が受理される場合、ハブは必ず購読者の意図検証を実施します。
購読が拒否された場合、ハブは購読リクエストに記載された購読者のコールバックURLにHTTP [RFC7231](またはHTTPS [RFC2818])のGETリクエストを送り通知することが必要です。このリクエストには、次のクエリパラメータが追加されます(フォーマットは [URL] Section 4 参照):
購読はどの時点でもハブにより拒否されることがあります(以前受理された後でも)。購読者は、その時点でその購読がもはや不可能と見なすべきです。
攻撃者が購読者本人になりすまし不正な購読(や望まない購読解除)を作成しないように、ハブは購読リクエストが確かに購読者自身から送信されたものかを確認しなければなりません。
ハブは、購読リクエストに記載された購読者のコールバックURLにHTTP [RFC7231](またはHTTPS [RFC2818])のGETリクエストを送信します。このリクエストのクエリ文字列には、以下のパラメータが追加されます([URL] Section 4 参照):
購読者はhub.topicが自分が保留中の購読または購読解除として実行したいものに対応していることを必ず確認する必要があります。該当すれば、購読者はhub.challengeパラメータと等しい値を応答ボディにしてHTTP成功(2xx)コードで返答しなければなりません。アクションに同意しない場合は、404 "Not Found" 応答を返します。
ハブは成功以外(3xx, 4xx, 5xx)を返すサーバーレスポンスコードを検証失敗と見なします。また購読者がHTTP成功(2xx)を返してもボディがhub.challengeに一致しなければやはり検証失敗と見なします。
ハブはhub.lease_seconds値を購読者リクエスト値と同じにしてもよいですが、自身のポリシーで変更する場合もあります。購読を継続したい場合は購読者がリース期間満了前にハブへ再購読リクエストが必須です。
ハブはリース有効期限を必ず強制し、無期限リースを発行してはなりません。
この仕様では、購読リクエストの確認/否認とコンテンツ配信の判別にGETとPOSTを使い分けています。これはWebアーキテクチャ上ベストプラクティスと見なされませんが、コールバックURLの実装を単純にする効果があります。なぜなら配信リクエストのPOSTボディは任意のContent-Typeを含み実際の文書内容のみを運ぶので、GETかPOSTかで振り分けできるこの仕組みで実装が容易になります。
トピックが更新された場合、発行者は以前指定したハブに必ず通知しなければなりません。ハブと発行者はどんなメカニズムでも合意できますが、最終的にハブが購読者へ更新ペイロードを届けられることが条件です。
発行者がハブへ知らせる具体的な方法は規定されていません。例えば、既存のパブリックハブのいくつかは [1] [2] [3] のように、hub.mode="publish" と hub.url=(更新されたリソースのURL) キーのPOSTリクエストを要求しています。
発行者が既存の購読を新しいトピックURLへ移行したい場合は、HTTPリダイレクトを用いて行えます。
rel=self URLと新しいハブを発見し、購読者は新URLで新しいハブに購読します。これには以前のハブ側の特別な介入は不要で、発行者がハブを変更しても問題無く機能します。
コンテンツ配信リクエストは、トピックURLに新規コンテンツが利用可能になったとき、ハブから購読者へ送信されます。このリクエストはハブから購読者のコールバックURLへのHTTP [RFC7231](またはHTTPS [RFC2818])POSTリクエストで、HTTPボディには配信通知のペイロードが必ず含まれます。配信リクエストのContent-TypeヘッダーはトピックのContent-Typeと一致させ、例外規定を除いてトピックURLの全内容を含める必要があります。
Atom ([RFC4287]) やRSS ([RSS-2.0])
フィードでは、ハブがすでに配信済みのatom:entryやrss:item要素をフィードから省略してもかまいません。
このリクエスト必ず少なくとも1つのハブのURL(rel=hub)を示すLink Header [RFC5988]と、rel=selfで更新対象トピックの正規URLを示すLink Header [RFC5988]を含まなければなりません。ハブはこれらを1つのLink Headerにまとめてもよいです。これらURLはディスカバリー手順(Section 3)の結果です。購読者はこれらのLink Headerを配信リクエストがどの購読に対応するか判定に使ってはなりません。なぜならLink Headerはトピックコンテンツのメタデータであって、特定の購読のものではないからです(配信リクエスト内のトピックURLが最初に購読したURLと異なる場合もあります)。
購読者のコールバックURLは、HTTP [RFC7231] 2xx応答コードを返す 必要があります。HTTP 410応答を返すことで購読が削除されたことを示すこともできます。ハブはこの応答を受け取った場合、購読を終了しても構いません。購読者からの他の応答はすべて失敗として扱います(必ず)。つまり購読者はサブスクリプション移動にHTTPリダイレクトを使ってはなりません。購読者はコンテンツ配信リクエストへの応答をできるだけ速く返し、その成功応答コードは単にメッセージ受領を意味し、実際の処理完了を示すものではありません。購読者による応答ボディはハブが必ず無視します。ハブはコンテンツ配信の再試行回数や時間を自身の制限内で繰り返すべきです。配信失敗が制限を超えた場合はその通知の再送をやめますが、リース有効期限までは購読を保持し、新規更新時に再配信を継続します。
購読者が購読リクエストにhub.secret値を指定した場合、ハブは必ずペイロードのHMAC署名を生成し、配信リクエストのリクエストヘッダーにX-Hub-Signatureを含めます。このヘッダー値はmethod=signature形式とし、methodは認識されるアルゴリズム名、signatureは署名の16進表現です。署名はHMACアルゴリズム [RFC6151] でリクエストボディをデータ、hub.secretをキーに計算します。
当初登録済みのアルゴリズム名は、発行時点の [FIPS-PUB-180-4] レジストリ内容に基づきます。
今後、購読者が検証可能なアルゴリズムを指定する拡張が定義されるかもしれません。執筆時点では、互換性のため多くのハブが既知の脆弱性があるSHA-1でも署名しています。
購読者がX-Hub-Signatureヘッダー付きで配信リクエストを受信した場合、共有シークレットと同じメソッドで署名を再計算し検証すべきです。一致しなければそのメッセージを必ず無効として無視します。購読者が非同期でメッセージを処理したい場合や総当たり攻撃を防止したい場合、2xx応答で受信のみを認めて構いません。この手法とHTTPS [RFC2818]を組み合わせれば、購読者がHTTPSサーバーを立てなくても認証付き配信リクエストの受信が可能です。
ただしこの署名はペイロードが改ざんされていないことだけを保証するもので、リクエストに含まれるヘッダーは購読者側で安全であるとみなしてはなりません(購読者がHTTPSコールバックを使う場合を除く)。
ここにセキュリティに関する要点をまとめます。WebSubはHTTPだけを利用するサーバ間プロトコルであり、すべてのリクエストにHTTPSを利用することが強く推奨されます。
購読者がページの<body>内の<link>要素もチェックすべきか(<head>と同様に)という判断は簡単ではなく、いまだ明確な合意がありません。<body>をスキップする理由のひとつは、あるWebサイトは(意図せず)ユーザーに<link>タグを書き込ませる可能性もあるからです(そのような実例は報告されていません)。こうしたサイトでWebSubディスカバリーがその<link>要素を読んでしまうと、悪意あるユーザーが任意のハブをすべての購読者に知らせ、後で悪意のあるコンテンツを配信できるリスクもあります。この潜在的攻撃を考慮すれば、HTML文書の<head>だけでディスカバリーを行うのが賢明かもしれません。
まず、購読者はハブのURLがHTTPで広告されていても常にHTTPS URLを優先すべきです。次に、コールバックには予測困難で一意なURL(capability URL)を使い、HTTPSで提供するべきです。最後に、購読時にhub.secretを利用してコンテンツ配信時に署名できるようにすべきです。
ハブは短い存続期間(例えば10日をデフォルトとする)のhub.lease_secondsを強制すべきです。意図検証時はランダムな使い捨てhub.challengeを使うべきです。
ハブは購読者が指定したコールバックそのもの(HTTPS利用も含む)を必ず使う必要があります。ハブは購読者がhub.secret指定した場合、その値で必ず配信リクエストを署名しなければなりません。
購読者が購読時にhub.secretを含めている場合、購読者はハブが提供する署名を検証し、それをするなら必ず(MUST)ハブが示したアルゴリズムで判別し、検証失敗したリクエストは廃棄しなければなりません。
購読者がHTTPSでないコールバック、またはハブ-購読者間のTLS通信が信用できない場合、コンテンツ配信通知の完全性はhub.secretおよびハッシュアルゴリズムのみに依存します。このようなときは必要なセキュリティ基準に応じて適切なハッシュアルゴリズムを使うべきであり、SHA-1の脆弱性が公知になっているため本発行時点ではSHA-256以上を推奨します。
以下は「Self-Review Questionnaire: Security and Privacy」([security-privacy-questionnaire])に沿ったセキュリティ・プライバシー上の検討ポイントです。
このセクションは規範的ではありません。
編集者たちは、PubSubHubbubの著者、IndieWebコミュニティ、およびその他の実装者の皆さまのご支援、ご助言、そして熱意に感謝いたします。特に、 Brad Fitzpatrick、 Brett Slatkin、 Martin Atkins、 Amy Guy、 Barry Frost、 Benjamin Roberts、 Eugen Rochko、 Jordan Potter、 Matthias Pfefferle、 Malcolm Blaney、 Marten de Vries、 Sandro Hawke、 Tantek Çelik、 そして Tony Garnock-Jones 各氏に感謝いたします。
このセクションは規範的ではありません。
.host-metaディスカバリー機能を削除(Issue #97)hub.secretが暗号学的にランダムかつ一意であるべきことの記述を追加Accept-Languageヘッダーに応じて異なるrel=self URLを返す例を追加<link>タグのみを許可rel=self URL利用例を追加hub.topicは発見したselfのURLでなければならないことを明記Fromヘッダー含有の推奨を削除