Skip to content

MS_PPID

nishi_74322014 edited this page Aug 4, 2026 · 1 revision

PPID

概要

  • Pairwise Pseudonymous Identifier (PPID)

    • ある SP (Service Provider), RP (Relying Party) に対してのみ、
      ある Entity の識別子として提供される値。
    • 他の SP, RP には、当該 PPID を当該 Entity と関連付けることはできない。
  • SAMLや、OIDCにある概念。

  • pairwise の対義語は public になる。

詳細

目的

一般的に、結託した SP, RP による名寄せを防ぐ目的で導入される。

※ なお、PPID を渡している時に本人を特定できそうな claim を一緒に渡したら無意味。

効果

public

以下のように実装しなければ、public でもそれほど問題は無さそう。

  • 「userid のみを送信して認証とみなす」の様な実装をしない。
  • トークンに署名する。できればクレームセットにも署名する。

pairwise

  • 名寄せを防止する目的(プライバシー保護)。

  • しかし、実際は、プライバシー保護で使用された事例はなく、
    セキュリティを高める副作用が確認されたことはある(らしい)。

    • トークン置換攻撃を緩和させる副作用
    • 「userid のみを送信して認証とみなす」みたいな非推奨をやってしまう
      人たちのアプリのセキュリティを高めてはいる。

考察

Pairwise Pseudonymous Identifier (PPID) の方がセキュア。

(・・・当たり前と言えば、当たり前だが。)

トレンド

ウェブサービス事業者のトレンドを分析しても五分五分かなと。

方式 事業者 備考
public Twitter 認証ではなく認可目的のため PPID にするモチベーションは無さそう
public Google 昔、Pairwise だったものを OIDC 対応時に public に変更した
public Yahoo アプリ横断の共通 ID(Yahoo ID とは異なる)
pairwise Apple Sign in with Apple
pairwise Facebook
pairwise LINE

補足(最新化): Sign in with Apple は pairwise に加えて メール アドレスの中継(Hide My Email) まで提供しており、 「名寄せを防ぐ」という発想がプラットフォーム側の要件として 定着したことを示している。 また、Apple はアプリ側にも同等の選択肢を提供することを App Store の審査要件にした時期があり、 pairwise の普及を後押しした。

sub=email

派生の問題。

  • 別に、sub=email でログインしても問題はない。

  • しかし、ID 連携時の sub = email は、ダメっぽい

    • 何故か?と言えば、
      • メアドが乗っ取られると、外部ログイン経由で乗っ取られるため。
      • 従って、ID 連携を行う場合は、パーマネントな ID が必要になる。
    • 従って、外部ログイン時は、
      • sub=userid とするか、
      • 別の方法(scope で claim を要求するなど)で userid を連携する。
    • また、sub = email(username)を Pairwise 化する場合、
      メアドがバイナリ文字列に変更になる訳で、イロイロ実装し難い。
  • Google — public を選択している Google でも以下のように言っているらしい。

    • 「Email はユニークではない可能性があり、
      ユーザーを識別する主キーとしては適さない」

補足: OpenID Connect の仕様上も、 ユーザの一意性は iss + sub の組で判定すべきと定められている。 sub 単独でも、email 単独でもない。

  • email変更されうるし、再利用されることもある
  • sub は IdP 内で一意なだけなので、複数 IdP を受け入れるなら iss と組にしないと衝突しうる

「メール アドレスをユーザの主キーにする」は、 外部ログインを導入した途端にアカウント乗っ取りの経路になる。

実装

プロトコル別

プロトコル 呼称
OIDC Pairwise Pseudonymous Identifier (PPID)
SAML Persistent Pseudonym Identifiers が PPID に該当

SAML でのこの実装は、

  • SAML メタデータの NameID
  • SAML リクエストの NameIDPolicy

の仕様に関連する。

計算方法

SAML では明示されていないが、OIDC では明示されている。

要件抽出

  • Client 毎にユニークになればイイ。

    sub = ハッシュ関数 ( Client毎にユニークな値 || userid || salt )
    
  • 「Client 毎にユニークな値」の要件

    • 一般的には、RedirectUri や JwksUri が使用される(Client 側の検証可能な URI)。
    • ClientID は、削除・追加で変わり、変更後、重複しているケースもある。
    • RedirectURI は
      • ドメイン保持すれば変更されない
        (が、EndPoint までか?FQDN までか?など悩ましい問題も)
      • CIBA(MS_CIBA.md)は RedirectUri が無いので JwksUri とか言うが、
        FAPI では JwksUri を使わないなど。
  • salt が必要になる理由
    「Client 毎にユニークな値」が漏れ得る場合(ClientID、RedirectUri)、
    前述の計算方法が解れば、PPID 間の紐付けが可能になるタメ。

補足: OpenID Connect Core の仕様では、 pairwise の subsector identifier を用いて算出すると定められている。

sub = Hash( sector_identifier || local_account_id || salt )

sector identifier は既定では RedirectUri のホスト部で、 sector_identifier_uri を登録すれば 複数の RedirectUri を持つクライアント群で同じ sub を共有できる。 「ClientID に統一する」という後述の判断は、 仕様の推奨からは外れるが、CIBA を扱う都合を優先した設計判断である。

オレオレ

  • 以下の計算式を使用する。

    sub = ハッシュ関数 ( Client毎にユニークな値 || userid || salt )
    
  • ハッシュ関数: SHA-256

  • Client 毎にユニークな値

    • OIDC — ClientID に統一する(CIBA には RedirectUri が無いので)
    • SAML — samlp:AuthnRequest の Issuer を利用する。
      汎用認証サイトは OAuth/OIDC メインなので、結局、
      samlp:AuthnRequest の Issuer に ClientID を使っている。

設計・実装のメモ

備忘録。

PPIDで名寄せできる属性を返したら意味ない

・・・と言うことで、

  • /userinfo では、sub 以外の値を返さない。
  • そもそも、IdP 側が、PPID で sub(user) を特定できないので。

Client認証の場合、PPIDは無効で良い

  • Client 認証とは、
    • Client Credentials グラント種別
    • JWT bearer token authorization グラント種別
  • Client に名寄せは無いダロと。

Resource Serverを使う場合、PPIDは不適合

sub(user) を特定できないので、

  • User Store を参照できないので、
  • User Resource を参照できない。

認証用のClientと、Resourceアクセス用のClientを分ける

  • PPID は、

    • 認証用の Client に適用し、
    • Resource アクセス用の Client には適用しない。
  • ただし、認証用の Client も、

    • フェデレーションする必要はあるし、
    • フェデレーション・スタイルを決定する必要もある。
    • PPID でも、紐付けに必要な、ユーザ名やメアド程度は
      取れるように実装する必要があるケースは多そう。

汎用認証サイトのケース

SPの外部ログイン

  • SP のログインに ID 連携は必須ではないと言う感じ。

    • IdP/STS から、
      • 取得したトークン検証が済めばログインするなど。
      • 取得したユーザ名やメアドを、そのまま使う。
    • PPID で、ユーザ名やメアドが取れない場合は、
      ローカル・ログインの機能を実装し、
      ローカルのログイン・アカウントと外部アカウントを紐付ける
      (となると、ローカルのログインの実装が必要になる)。
  • IdP/STS との関係次第

    • 関係がであれば、ID 連携は不要。
      • トークン検証が済めばログインするなど。
      • そもそも、PPID も不要で、ユーザ名やメアドが取得できるハズ。
    • 関係がであれば、ID 連携をする。
      • トークン検証後、ローカルの userid と、連携先の userid or ppid を紐付ける。
      • 若しくは、関係が密になるように、自前の IdP を建てて、Hybrid-IdP する。
      • 前者は、アプリでやるには面倒なので、やるなら、後者が良さそうではある。

IdPの外部ログイン・ID連携(Hybrid-IdP)

  • Owin.Security ライブラリを使用した外部ログインに関しては、
    ASP.NET Identity の補助輪パワーで
    一応、適切に実装が出来てるっポイ。
    UserLoginInfoLoginProviderProviderKey を含んでいる。

  • フェデレーション・スタイルに関する考察。

    • 著名ウェブサービス事業者の場合
      (これは ≒ 外部ログイン、ソーシャル・ログインの実装)
      • トークン検証後、
      • UserLoginInfo(IdP 名+userid or ppid)を永続化して記憶し、
      • ローカル・アカウントとは、メアド一致で紐付けている
        (異なるメアド同士のアカウントを紐付けるのもなんかアレなので)。
    • 関係が疎 or フリーメール可能な IdP との場合は、前述と同じ。
    • 関係が密 or 企業メールが前提な IdP との場合
      (これは ≒ ID フェデレーションの実装)
      • トークン検証後、
      • UserLoginInfo(IdP 名+userid or ppid)を永続化して記憶し、
      • そのまま、ログイン・アカウントと紐付けなどでも良い。
      • また、アカウント同期の方式なども検討しておく必要がある
        (特に、PPID を採用するようなケースでは、別で同期を行う必要がある)。

補足(セキュリティ): 「メアド一致で自動的に紐付ける」は 実装として一般的だが、未検証のメール アドレスで行うと アカウント乗っ取りになる(pre-account-hijacking)。

  • IdP から受け取る email_verified を必ず確認する
  • email_verified が false、または claim 自体が無い IdP は信用しない
  • 自動紐付けではなく、既存アカウントへのサインインを求めて明示的に連結させる

SCIM のようなプロビジョニング連携がある環境なら、 そもそもメアド突合に頼らずに済む。

参考


Tags: IT国際標準, 認証基盤, クレームベース認証

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally