OIDC CIBAで作る「スマートフォンでログイン」機能

こんばんは、ritouです。

今日は OpenID Connect Client Initiated Backchannel Authentication Flow 通称CIBA のユースケースについて書きます。

CIBA は決済や送金のためのもの?

自分の記事でも、CIBAのユースケースとしてコンビニ決済への導入例を挙げてみたりしました。 そして、CIBAにやたらと詳しい某Authlete社の記事を見ても、送金とか決済などで使えそうな話がプンプンします。

www.authlete.com

www.authlete.com

お金周りはUX改善のメリットとして伝え安いですし、クレカ決済のDecoupled AuthNの実例もあります。 CIBAもFAPIとの絡みがあるのでこの辺りを例示しがちではありますが、今回はそんな流れに逆張りとばかりにシンプルなユースケースに注目します。

スマートフォンでログイン」の要件とCIBAの機能

例えば Google アカウントにログインする際、Androidバイスなどを用いた次のような認証方式が利用可能です。

  • パスワードの代わりにスマートフォンで使用する <- パスワードレス!?
  • 2 段階認証プロセスを有効にした場合に、パスワードに加えて使用する <- 2段階認証!?

support.google.com

Googleは次のようなメリットを挙げています。

f:id:ritou:20201020034338p:plain

  • SMSで受信した認証コードを盗まれるなどのリスクを回避
  • リッチなUI
  • 拒否機能あり

SMSやOTPを使うよりは安心感が出そうですが、なかなか実装の敷居が高そうな機能です。言い換えると、これを簡単に実装できそうだとしたら面白くないですか?

このような機能を実現するための要件としては

  • ユーザーと端末が紐づいている : ユーザーとADの関係
  • 端末にプッシュなどでの通知ができる : CIBA の AuthN Request を受けた OP が ADにプッシュ通知を送って...
  • 必要ならば通知先の端末でユーザー認証 : CIBAではブラックボックスになっているがこの辺はよしなにやるべき内容
  • 環境などリッチな情報を表示して許可を求める : AuthN Requestに情報を載せてやれば良い
  • ユーザーが拒否したら認証フローを終わらせられる : ADでユーザーが拒否したらエラーが返る

ということで、今回はこの「スマートフォンでログイン」をCIBAを使って実装するとどうなるか?っていう話をします。

GOAL

パスワードレス

Google の 「スマートフォンでログイン」のUXを見てみましょう。 まずはメールアドレスなどを入れてユーザーを特定します。

f:id:ritou:20201021215500p:plain

ここで設定が済んでいると、スマートフォンでログインのフローに入ります。 スマートフォン見てみろやと。許可しろやと。そして下に書いてるのと同じ数字をタップしろやと。

f:id:ritou:20201021220705p:plain

ここで、手元のスマートフォンに通知が来ます。 2FAではなくこれだけでログインさせるので設定時に「この機能使う時、画面ロックかかるよ」って言われています。

スマートフォンで表示される画面はこんなんです。 リッチな...とか言ってましたがあんまり情報ないですね。まぁいいか。

f:id:ritou:20201021220719p:plain

「はい」を押すと、さっき言ってた同じ数字をタップしろやと言ってきます。

f:id:ritou:20201021220731p:plain

これでログインできます。

2段階認証

違いとしては

  • ユーザー特定後、パスワード認証
  • パスワードがあっていたら「スマートフォンを確認しろ」画面(上述したような数字のくだりはなし)

というあたりです。

CIBAを用いた実装案

ここでは一旦、「利用するスマートフォンの設定が済んでいる」前提とします。

上で紹介したGoogleの例と揃えると、CIBAの仕様におけるOP/RPという役割がどちらも同一サービス(Google)とする方がイメージしやすいかもしれません。

  • RP : Webアプリやモバイルアプリ
  • OP : 認証基盤的なやーつ

最初に、RPはHTMLフォームなどでユーザー特定に必要な値を受け取ります。 ここではメールアドレスとしましょう。

次に、RPからOPにバックチャンネルで AuthN Request を送ります。 (Client認証部分は省略しています。)

   POST /bc-authorize HTTP/1.1
   Host: server.example.com
   Content-Type: application/x-www-form-urlencoded

   scope=openid&
   binding_message=93&
   login_hint=user@example.com

パラメータとしては

  • login_hint : 対象ユーザーのメアド
  • scope : ログインできたらいいので openid のみ
  • binding_message : 上述のGoogleの例に揃え 93 を指定

というあたりがあれば十分そうです。 レスポンスはこうなります。 パスワードレス、2FAのコンテキストを指定したい場合は acr_values あたりを使っても良いかもしれません。

    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: no-store

    {
      "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
      "expires_in": 120,
      "interval": 2
    }

このレスポンスを受けたら、RPはユーザーに「スマートフォンを確認しろ」「binding_messageで指定した値を選択しろ」という画面が出せます。 一方、OPはAuthN Requestを受けたらユーザーのAD(スマートフォンのアプリなど)に通知を送ります。

通知を受けたADでは

  • (パスワードレスをうたうなら)画面ロックなどの再認証要求
  • 対象ユーザーのプロフィール画像、メアドの取得
  • ログインしますか?とユーザーに聞く
  • 「はい」の場合に、binding_message に指定した値とそれ以外の値を払い出し、選択させる

binding_message のあたりは独自でルールを決めつつって感じですが、1 ~ 99 までの数とかに制限しておくと Google のような画面が作れそうです。 OKならRPはIDTokenを取得でき、認証成功したことを検証できます。

ということで、ほぼCIBAの仕様範囲内で実装できそうです。 まぁ、ここまで理解してできる開発者ならもうちょっとシンプルに設計/実装できそうな気もしなくはないですが。

CIBAを利用するにあたり、考えるべき点

RPがWebアプリの例を示しましたが、モバイルアプリでも同様に実装できそうです。 ただし、CIBAはConfidential Clientを対象としているのでリクエストを送るWebサーバーを間に置いておく必要があるかもしれません。

あとは前提のあたりで書いた「RP/OP」が別サービスの場合ですが、

  • 最初にRP(example.com) 内でユーザー特定し、そこから先(AD上の表示など)はOP(example.net)のコンテキストで行われるあたりのユーザーへの見せ方
  • RP->OPのAuthN Requestの login_hint に指定する値

あたりをよく検討してユーザーが気持ち悪く思わないようなUXに仕上げる必要があるでしょう。

登録

上にも書きましたが、CIBAの仕様では、ADとの紐付けは仕様の対象外です。 この辺りはよしなに...とすると悩んじゃいそうなので、この前書いたDevice AuthZ GrantっぽいUXを使って登録フローを考えても良いと思います。

ritou.hatenablog.com

リッチなUI、環境に関する情報

Googleでは2FAの時の画面では

  • バイス(OS情報?)
  • 場所(ネットワーク情報?)
  • 時刻

などを表示していました。 ユーザーへの表示以外にもOP側でリスク判定などに使える値だったりするので、目的外利用とか言われないようにちゃんと同意を得た上で環境に関する情報をやりとりしても良いでしょう。

まとめ

  • CIBAを使って「スマートフォンでログイン」的なパスワードレス、2FAの仕組みが作れそう
  • RP/OPが同一サービスだったらシンプルに作れそう
  • RP/OPが別で「2FA専用SaaS」みたいなのも面白そう

この辺りはプッシュ通知を受けられるPWAなWebアプリでも作れることはわかってるので、どこかでデモできればいいなと思っております。 これからもAuthentication Device (AD)を使うユースケースを探究できたらと思います。

ではまた!

f:id:ritou:20201021234131p:plain

OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様を考えてみた

おはようございます。ritou です。

なんか急に寒くなりましたね。私は先週末、風邪をひきました。

何の話?

OpenID Connect の CIBA と OAuth 2.0 Device AuthZ Grant は手元の端末を用いてユーザーがID連携やリソースアクセスを許可することから似ている面があるものの、プロトコルとしては結構な違いがあります。

ritou.hatenablog.com

tools.ietf.org

あまり深く考えずにこれらの標準化仕様を弄ってどうこうするのはお勧めできないわけですが、今回は特定の条件下においてこの2つを組み合わせられるのでは?というのを考えてみました。

それぞれの特徴

リクエストやらエンドポイントやらのプロトコルの詳細は一旦おいておいて、ざっくり

  • CIBA
    • RPがOP上のユーザーに紐づく情報を知っている必要がある
    • 事前にユーザーと Authentication Device (AD) の紐付けが存在し、AD上でID連携を許可する。紐付け方については仕様範囲外
  • Device AuthZ Grant
    • Clientは事前にユーザーを知らなくても良い
    • ClientがURL+User Code や QRコード を表示して、ユーザーが自らが利用する端末のブラウザを利用してリソースアクセスを許可する。

のように整理できます。

こう書くと結構な違いがありますが、一方で綺麗に仕様が分かれているようにも感じられるのではないでしょうか。

組み合わせの可能性

FAPIとかのガチなユースケースでは変なこと考えない方が良いと思いますが、C向けの比較的ライトウェイトなサービスとかでは既存の仕様を弄り回すのも頭の体操ぐらいにはなりそうです。

自分でPWAを用いたCIBAのデモを作ってみたりして気付いたんですが、CIBAで前提となっているもののその部分自体は未定義である「ADとユーザーの紐付け」や「RPとの最初のID連携」の部分を簡単にやれるといいなーという思いが出てきました。

そんな中、この2つの仕様が交わるユースケースを考えてみたところ、例えば PWA なWebアプリやモバイルアプリなどで

  • OIDC CIBA のように AD が Push を受けられる
  • OAuth 2.0 Device AuthZ Grant のように URL や QRコードで起動できる

という2つの要件を満たせるならば 「OIDC CIBA で RP とユーザーの紐付けがない状態の時だけ Device AuthZ Grant っぽく」みたいなのができて上記の課題を解決できるのでは?と思ってきました。 そこで、OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様 を考えてみたわけです。

OIDC CIBA Dynamic AD Enrollment Extension(仮)

ここからが本番です。いきなりまとめると

  • CIBA の Backchannel Authentication Endpoint への Authentication Request で指定した *hint が空だったり OP 側で紐付けがない/切れた場合に OAuth 2.0 Device AuthZ Grant の Device Authorization Response を返す
  • それにより、動的なAD紐付けが可能になる

みたいな感じです。わかりますか?わかりませんよね。 もうちょっと詳しく説明してみます。

動的なAD紐付け(拡張)

OP上でユーザーとADの紐付けが行われていないもしくはリセットされたような状態からの動的な紐付けを行うケースを想定します。 あとはADが複数存在する場合にRPに対して利用するADを選択するようなケースとかでも使えそうです。

f:id:ritou:20201019005740j:plain

図ではCIBAのPoll modeを想定していますが他のmodeでもあまり変わりません。

1. Authentication Request

RPはOPに対して Authentication Request を送ります。

  POST /bc-authorize HTTP/1.1
   Host: server.example.com
   Content-Type: application/x-www-form-urlencoded

   scope=openid%20email%20example-scope&
   client_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255&
   binding_message=W4SCT&
   login_hint_token=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
   zdWJfaWQiOnsic3ViamVjdF90eXBlIjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjg
   xODAwNCJ9fQ.Kk8jcUbHjJAQkRSHyDuFQr3NMEOSJEZc85VfER74tX6J9CuUllr8
   9WKUHUR7MA0-mWlptMRRhdgW1ZDt7g1uwQ&
   client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
   client-assertion-type%3Ajwt-bearer&
   client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
   pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB
   zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiYmRjLVhzX3NmLTNZTW80RlN
   6SUoyUSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.Ybr8mg_3
   E2OptOSsA8rnelYO_y1L-yFaF_j1iemM3ntB61_GN3APe5cl_-5a6cvGlP154XAK
   7fL-GaZSdnd9kg

OIDC CIBAで定義されていいるそのまま載せましたが、今回の拡張を利用するための追加のパラメータが必要になるかもしれません。

CIBAでは*_hintパラメータで指定されたユーザーを特定し、存在しない場合やユーザーが管理しているADと通信できないなどの場合はエラーとして扱いますが、今回の案ではエラーではなく「OAuth 2.0 Device AuthZ Grant」風のレスポンスを返すものとします。

      HTTP/1.1 200 OK
      Content-Type: application/json
      Cache-Control: no-store

      {
        # CIBAのauth_req_id は OAuth 2.0 Device AuthZ Grant の device code 相当
        "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",

        # ここから下が OAuth 2.0 Device AuthZ Grant のレスポンス
        "user_code": "WDJB-MJHT",
        "verification_uri": "https://example.com/device",
        "verification_uri_complete":
            "https://example.com/device?user_code=WDJB-MJHT",

        # 有効期限とインターバルの間隔
        "expires_in": 1800,
        "interval": 5
      }

2. User Interaction

RPは受け取ったverification_uri + user_code や verification_uri_complete をユーザーに提示し、ユーザーはそこにアクセスします。 CIBAのユースケースとしてPOS端末での利用がありましたが、例えばポイントカードを持っていたらスーパーのATMやサービスカウンターにある端末などで最初にこの辺りの設定をする、とかでも良いでしょう。

3. AD Enrollment & Consent

ここで

  • ADとしての登録 (AD Enrollment)
  • RPにユーザー情報を提供することへの同意 (Consent)

などが行われます。

4. Polling Request / Response(NG)

3 が完了するまでは、RPからのPolling Requestに対してOPはエラーを返します。

5. Polling Request / Response(OK)

3 が完了すると、RPからのPolling Requestに対してOPは成功レスポンスを返します。

通常のCIBAフロー

ユーザーとADが紐付けられていて、RPからのAuthentication Requestでユーザーを特定できた場合は通常のCIBAのフローになります。

f:id:ritou:20201019005237j:plain

GNAP, 3D Secure 2.0

以前、XYZとして紹介したドラフト仕様を覚えているでしょうか?

ritou.hatenablog.com

現在はGrant Negotiation and Authorization Protocol(GNAP)として仕様策定が進められています。

tools.ietf.org

これ、最初の頃から

  • バックチャンネルでリソースアクセスを要求
  • 必要であればユーザーインタラクションが発生

という流れになっていました。

OAuth 2.0に求められるユースケース毎の要件を整理し、OAuth 1.0の時のようなバックチャンネルのリクエスト中心のプロトコルとして書き直した感じです。

なので今回紹介したやつとほとんど一緒です。

さらに、XYZの紹介記事でちょっと触れた様に 3D Secure 2.0 のフローにも似ています。

3dsecure2.com

この辺りは細かいパラメータなどは異なるにせよ、大まかな仕組みとしては似ているところに落ち着いていきそうな気がします。

まとめ

  • OIDC CIBA と OAuth 2.0 Device AuthZ Grant の組み合わせを考えてみた
  • OIDC CIBA の仕様外である「ADの登録」のところに OAuth 2.0 Device AuthZ Grant の「動的なリソースアクセス許可」 を適用することで「動的なAD登録」みたいなのが実現できそう
  • XYZ(GNAP)とかと似てる

せっかく仕組み考えたので、次回はこれを使った 「OIDC CIBA as a MFA」 みたいな話を書こうかと思っています。 ではまた!

f:id:ritou:20201017234812p:plain

2020/11/19 に 「idcon vol.28 DID特集その2」 やります

こんにちは、ritouです。

あの #idcon がオンラインで復活!?しかもテーマはDecentralized Identity(DID)!? と言うことで誰かの意識が高まっているのを観測したのでやります。

idcon.connpass.com

今のところの発表案です。

  • 「MSのDID/VC概要」by phr_eidentity : MSのDID/VCを触ってみたので解説します。
  • 「Credential Handler API(仮)」by kg0r0
  • 「DIDCommとかSIOP」by ken5
  • 「Email, Messaging, and SSI/DID: Round2」by s01 : Email, Messaging, and SSI/DID の日本語再放送 + DIDCommで本当にいけるのかという話

順番はテキトーに決めましたが、最初に概要から入り、Credential Handler APIとかDIDCommとかSIOPとか、個別のトピックについて解説されると一気に理解が進むのではないかと期待しています。

そして、大体は こんな感じだよ -> へー、なるほどー終わりーとならない(!)のが idcon でもあります。

  • MSはわかった。他に試せるところって?
  • Credential Handler APIって必要?SIOP拡張したったらこんなのいらなくね?
  • DIDCommってもっとシンプルにならんの?

と言ったあたりはいつもの idcon だと発表の後で盛り上がるところなので、オンラインでも白熱した議論が行われると良いですね。

配信どうしようかまだ決めていませんが、なるようになるでしょう。11月になったら考えます。

と言うことで、参加申込み募集中で〜す。ではまた!

(そろそろ iddance もやらないとなぁ...)

f:id:ritou:20201012185719p:plain

Self-Issued OpenID Connect Provider DID Profile v0.1 とは

f:id:ritou:20200922040730p:plain

おはようございます。ritouです。

今日はこれを読んでみます。

Self-Issued OpenID Connect Provider DID Profile v0.1

何のための仕様か

This specification defines the "SIOP DID Profile" (SIOP DID) that is a DID AuthN flavor to use OpenID Connect (OIDC) together with the strong decentralization, privacy and security guarantees of Decentralized Identifiers (DID) for everyone who wants to have a generic way to integrate Identity Wallets into their web applications.

  • WebアプリケーションにIdentity Walletを統合するために
  • DIDとOpenID Connectの組み合わせるための
  • SIOP DID Profileじゃ!

と言うことです。

SIOPについてはもう大丈夫でしょうか?七年前の記事で良ければどうぞ。

ritou.hatenablog.com

Qiitaにもいくつか記事があります。

qiita.com

  • OpenID Providerとして特定のWebアプリケーション(Googleとか)ではなく、モバイル端末内で動作するアプリケーションなどを利用する
  • openid:// と言うカスタムURIスキームを用いた認可リクエストにより呼び出され、鍵ペアを生成/管理してIDToken を返す
  • ユーザーの同意のもとで端末単位で保存している情報のやりとりや、使い方次第では端末の識別やリクエストが同端末から送られたことの検証などにも使おうと思えば使える

と言うものであり、仕様としてはモバイルアプリ、ブラウザのプラグイン、デバイスの機能など特定のURI呼び出しを検知して起動できる仕組みで使えるように汎用的に作られています。

この仕様では、特定のサービスではなく端末自体をOPにすると言うSIOPをDID/SSIのIdentity Walletとして使うために必要な差分なりが定義されています。

Protocol Flow

RPはWebアプリ/ブラウザベース(SPAなど)のアプリであり、モバイルもしくはデスクトップブラウザからIdentityWalletアプリを立ち上げて使う想定です。 公式の図を見てみましょう。

https://identity.foundation/did-siop/assets/did_authn_siop_profile_flow.png

流れをざっくりまとめると、

  1. RPは "Sign-in with SSI" ボタンみたいなのを用意し、ユーザーが押すと SIOP Request を生成
  2. openid://?<SIOP Request> として何やかんやで Identity Walletアプリが起動する
  3. Identity Walletアプリは OIDC/DID AuthN に従って SIOP Request を検証する
  4. 必要なら認証をして、その後に SIOP Response を作成する
  5. response_mode の指定にしたがってRPにSIOP Responseが渡される
  6. RPはOIDC/DID AuthN に従って SIOP Response を検証する

となります。

基本的にこのSIOPの流れに、DID用の処理が追加されるイメージです。

  • SIOP Request : RPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成
  • SIOP Response : SIOPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成

それでは見ていきましょう。

Generate SIOP Request

SIOP Request は次のように定義されています。

  • 互換性のため、response_type, scope, client_id を文字列で指定する
  • それ以外のパラメータは request もしくは request_uri として指定する。RPのDIDもこっちで指定。

例を引用します。

openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request=<JWT>
openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request_uri=https%3A%2F%2Frp.example.com%2F90ce0b8a-a910-4dd0

いわゆるリクエストオブジェクトを指定、なんてのはFAPIなどのProfileでも使われているので驚きはないでしょう。

SIOPのフローでは、registration パラメータによってRPのメタデータを登録できます。

  • アルゴリズムRS256 に加えて ES256KEdDSAをサポートしなければならない
  • Request ObjectはDIDドキュメントに記載されている検証方法で直接/間接的に検証可能であり、RPのJWKSにより直接検証可能である必要がある
  • JWKSは jwks_uri もしくは jwks パラメータで指定され、jwks の場合は kid が一致する必要がある。jwks_uriの場合はHTTP(S) DID Resolution Bindingが必要とか...
  • RPはSIOP Responseを暗号化して受信することもできる

リクエストオブジェクトについても細かく書いてありますが、眠いので例示に留めます。

#header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#veri-key1"
}

# payload
{
    "iss": "did:example:0xab", # RP's DIID
    "response_type": "id_token",
    "client_id": "https://my.rp.com/cb",
    "scope": "openid did_authn", # did_authn を指定
    "state": "af0ifjsldkj",
    "nonce": "n-0S6_WzA2Mj",
    "response_mode" : "form_post",
    "registration" : {
        "jwks_uri" : "https://uniresolver.io/1.0/identifiers/did:example:0xab;transform-keys=jwks",
        "id_token_signed_response_alg" : "ES256K"
    }
}

SIOP Request Validation

SIOPは scopedid_authn が指定されていたら、OIDCで定義されている検証に加え次のような検証を行います。

  • iss クレームで指定されたRPのDIDからDIDドキュメントを取得
  • jwks_uriが存在する場合、iss とDIDが一致することを検証
  • RPのDIDドキュメントから、kid と一致する検証方法を取得
  • SIOP Requestの検証

Generate SIOP Response

SIOPは以下のような SIOP Response を作成してRPに戻します。

  • sub_jwkkid を含む
    • kid はSIOPのDIDドキュメントの検証方法を参照する DID URL
  • SIOPのDIDを含む : did クレーム
# Header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#key-1"
}

# Payload
{
    "iss": "https://self-issued.me",
    "nonce": "n-0S6_WzA2Mj",
    "exp": 1311281970,
    "iat": 1311280970,
    "sub_jwk" : {
        "crv":"secp256k1",
        "kid":"did:example:0xcd#verikey-1",
        "kty":"EC",
        "x":"7KEKZa5xJPh7WVqHJyUpb2MgEe3nA8Rk7eUlXsmBl-M",
        "y":"3zIgl_ml4RhapyEm5J7lvU-4f5jiBvZr4KgxUjEhl9o"
    },
    "sub": "9-aYUQ7mgL2SWQ_LNTeVN2rtw7xFP-3Y2EO9WV22cF0",
    "did": "did:example:0xcd" # SIOPDID
}

(ちょっと追記)通常のSIOPは鍵を生成して端末なりに保存しておくだけのイメージですが、ここではDIDを含みDIDドキュメントから検証できるようにする必要があるわけなのでこれまでのSIOPの感覚で言うと鍵の登録処理も発生しそうです。もう少し細かく追記してもらうのが良いのかなと思ったりします。

SIOP Response Validation

OIDCのSIOP Responseの検証としては

  1. id_token を取得
  2. id_tokensub_jwk の鍵で署名されたことを検証

さらに DID AuthNとして

  1. id_token の SIOP DID(did) から DIDドキュメントを取得
  2. id_tokenのDIDドキュメントから sub_jwkkid と一致する検証方法を取得
  3. その検証方法で id_token を検証

SIOP Discovery

省略します。

UX Considerations

カスタムURLスキームの扱いについて。 モバイルブラウザの場合はアプリ立ち上げるけどAndroid/iOSそれぞれで今までもいろいろ言われてきたよねと。 デスクトップブラウザの場合、もしかしたらブラウザ拡張/プラグインでサポートされるかもしれないけどうまくいかなそうならIdentity Walletのアプリを開かせてQR読み込ませるとかが必要かも。

この辺りが改善されるにはもう少し時間がかかるかもしれませんね。

Security Considerations

まずはSIOP ResponseのIDToken漏れるかも問題

  • Interception of the Redirect URI : SIOP Responseを取られたらIDToken持っていかれるよ -> RP頑張れ(オープンリダイレクト作るな)
  • Identity Token Leak in Browser History : ブラウザの履歴からSIOP ResponseのIDToken漏れるよ -> IDTokenの有効期限短くしたりキャッシュされないようにしたりしよう。完全な対策は難しいかも。
  • Identity Token Leak to Third Party Scripts : SIOP Responseをを受ける時に3rd PartyのJSとかでIDToken持っていかれるよ -> RP頑張れ(信頼できるやつだけ使え)

対策として response_mode=form_post 使えるならう。無理な場合もあるけど。とあります。

次に Session Fixation in Cross-Device Flow として、異なるデバイス間の転送を含む場合の脅威が記載されています。 RPがQRコードからIdentity Walletを呼び出す仕様の場合、攻撃者は自らのセッションに紐付いたQRを読ませることで第3者の認証を攻撃者のセッションでできるかも。 対策としては同一セッションであることの確認、もしくは異なるデバイスでも同一ユーザーであることを別の認証方式などで確認することが必要。

Github

何かあったらここでやってるよと。

github.com

(追記)SIOP側の公開鍵登録についてもう少し説明必要では?みたいなことを書いてみました。

github.com

まとめ

  • SIOPの流れにDIDの検証処理を追加するProfile
  • RPが作るリクエストオブジェクトの部分がモリモリしてるがSIOPのフローは変わらない
  • カスタムURIスキームやQRコード使う部分はもうちょい改善されないとUXキツそう

と言うあたりでしょうか。引き続きウォッチしていきましょう。 ではまた!

フィッシング対策視点から考えるメールやSMS通知のあり方

こんばんは、ritouです。

令和の時代においても、フィッシング攻撃はメール、SMS共に存在します。 だいぶ普及してきたみんな大好きワンタイムパスワードでもフィッシングに対しては脆弱です(FIDOにしましょう)。 フィッシング攻撃への現状の対策はどうかというと、メール自体の検証、メールにあるURLの表示と実際のリンクの差異、URLが正規のものかを確認することは素人になればなるほど困難です。 SMSならばURLはテキストそのものだから安心かもしれませんが、そもそも正規のメッセージに偽物が混ざってきたらわかりません。

ということで、今回は「メールやSMSにできるだけURLや電話番号などを記載するのを避けよう。」という話です。

主張

例えばこの記事

keepmealive.jp

それならば対策は二つだけ 1. SMSに書かれているURLは原則としてクリックしない 2. どうしてもクリックする必要があるときは本物のURLか確認する ということになります。

ここではdocomoの正規のURL(ドメイン)のリストがずらっと並んでいますが、このような検証を幅広いサービスに適用していくことは困難です。 なので、「メールやSMSにできるだけURLや電話番号などを記載するのはやめよう。」という意見ですね。

某、徳●さんのTweetで見かけたんですが、

pc.watch.impress.co.jp

同社では、「正規の当選メールには、サイトのURLの記載やリンクはなく、申し込み時に登録する『マスク抽選販売サイト』にある『当選者専用サイト』から登録する設計になっている。偽の当選メールに記載されているサイトのURLに行かないようにしてほしい」としている。

まさにこれですね。

UX低下を防ぐ仕組み

この話をすると、URLや電話番号を載せなかったらUXが悪くなるのでは?と言われることがあります。 フィッシングサイトや業者まで一発で引っ張っていけるということで、それだけURLや電話番号を利用することは効率的なUXであるとも言えるでしょう。 正規の通知しか送られてこない前提になっている、例えばモバイルアプリの通知のような場合はそこからアプリを立ち上げて...というUXを変える必要はないでしょうけれども、フィッシング攻撃の可能性がある限りはその部分を取り除きつつ通知の詳細確認やその後の必要な処理への誘導について、代替手段を用意する必要があります。 通知に含まれたURLや電話番号に直接アクセスする代わりに、Webアプリやモバイルアプリに通知を確認できる場所を用意しておき、ユーザー自身でそこにアクセスしにいく方法が良いのではないかと。

  • 今まで
    • 通知の概要(メール/SMS) -> URLクリック -> 詳細確認や継続処理
  • これから
    • 通知の概要(メール/SMS) -> (自分でブックマークなどからWebアプリに移動) -> 詳細確認や継続処理
    • 通知の概要(メール/SMS) -> (手元の端末でモバイルアプリを起動) -> 詳細確認や継続処理

「これから」の方に書いたUXが定着していくと、フィッシング攻撃が来ても「このフロー変じゃない?」と気付けるような仕組みの上での「啓蒙活動」もやりやすくなり、世界の平和に向けて一歩前進できるのではないでしょうか。 サービスの種類にもよりますが、個人的にはこの方が通知を受けたデバイスと実際にサービスに到達しにいくデバイスが異なるパターンでも利用できそうですし、UXは向上するのではないかと思ったりします。。

まぁ、実際にプロダクトでやろうと思ってもなかなか受け入れられないかもしれませんが、さいきょうのアイディーを求めることは悪いことではないでしょう。 ではまた!

f:id:ritou:20200903010702p:plain

現在仕様策定中の OpenID Connect RP-Initiated Logout 1.0 とは

こんばんは ritouです。

むかーしむかし、あるところにOIDCのセッション管理に関する3つの仕様がありました。

(2015年の記事)

ritou.hatenablog.com

(Session Managementについてのさらに古い 2013年の記事)

ritou.hatenablog.com

いわゆるソーシャルログインと呼ばれる使い方ではRP/OP間のセッションの整合性をあまり意識しない感じになっていますが、 昔から使われている "SSO" 的な使われ方においてはそのあたりが意識されるかもしれません。 これらの仕様ではRP/OP間でセッションに変更がないか、ログアウトさせるいくつかの方法が定義されています。

これらは最近どうしてるのかな?というところで現状を見てみると、4つの仕様として策定が進められています。

[Openid-specs-ab] RP-Initiated Logout is now its own specification

また、既にOpenID Certificationにはテストも用意されており、パスしたOPも書かれています。

openid.net

f:id:ritou:20200819024520p:plain

というところで、今回はこのRP-Initiated Logoutについて概要(not 翻訳)を紹介します。

openid.net

This specification complements the OpenID Connect Core 1.0 specification by enabling the Relying Party to request that an End-User be logged out by the OpenID Provider.

これはOPによるエンドユーザーのログアウトをRPから要求できるようにするための拡張仕様です。

新しい用語

これぐらいです。

  • Logout Endpoint : RPがログアウトのリクエストを送るターゲットとなるOPのエンドポイント

RPはこの値を後述する metadata から取得したりドキュメントとかで把握する必要があります。

RPからOPへのログアウト要求

RPがOPにログアウトを要求するパターンとして、2つあります。

  • RP -> OP と遷移して終わるパターン
  • RP -> OP -> RP に戻ってくるパターン

前者の場合、必要なパラメータは

  • id_token_hint : OPからRPに過去に発行されたID Tokenの値をヒントとして指定。RECOMMENDED
  • ui_locales : OP上での優先言語、スクリプトの指定。OPTIONAL

となります。AuthZ(AuthN) Requestのように client_id パラメータを用いて明示的に Client を指定したりはありません。 id_token_hint パラメータがあった場合、事前に ID Token にセッション識別子である sid を入れておくことで現在のセッションと一致するかどうかの判定ができますが、ない場合や検証不可な場合はOPとしてはユーザーがどこから来たのかさえわからない(信用できない)状態になります。

セッションとIDTokenの関連というと今までも何度か記事を書いてきましたが、今回のようなセッション関連の仕様を読むときは、IDTokenをセッション識別という目的で一定期間保持することを想定しなければなりません。有効期限はサーバー時間のずれに影響でないぐらいになるべく短くしIDTokenを取得したタイミングで "ID連携" を行う、という本来のOIDCの考え方との違いについてよく頭の体操をしておく必要があるでしょう。(個人的には id_token_hintという使い方が大っ嫌いなのですが精一杯大人な書き方をしています。)

また、仕様中に突然出てくる sid ですが、これは OpenID Connect Front-Channel Logout で定義されています。仕様の最初の方で他のセッション関連の拡張仕様との関連について言及はありますが、sid がどこで定義されたものかが言及されていないと、初めて見た開発者は混乱するかもしれません。

Draft: OpenID Connect Front-Channel Logout 1.0 - draft 04

sid Identifier for the Session.

OPはログアウトURLでユーザーに対して「ログアウトしますか?」と尋ねるべき(SHOULD)とあります。これを行うとユーザーの意図せぬ挙動を防ぐのと同時に、後述するトラッキング判定に対しても効果があるかもしれません。

ここまでの流れを図にしました。

f:id:ritou:20200825010654p:plain

複数のRPに接続済みのOPはログアウト後に、SessionManagementでのセッション判定で "状態変更あり" を示したり、Front-Channel/back-Channel Logoutの仕様でRPにログアウト通知を送ります。

さらに、RP->OP->RPと戻る場合はパラメータが変わります。

  • id_token_hint : OPからRPに過去に発行されたID Tokenの値をヒントとして指定。REQUIRED
  • post_logout_redirect_uri : OPのログアウト後にRPに戻したい時に指定する戻り先URL。このURLが指定されるときは id_token_hint の値が必須となる。検証の際は完全一致。
  • state : 戻り先がある時のCSRF対策のための...(略。必須でいいだろ(OPTIONAL)!
  • ui_locales : OP上での優先言語、スクリプトの指定。OPTIONAL

f:id:ritou:20200825010923p:plain

この場合は id_token_hint も必須になりますが、ここまでやるならAuthZ Requestのように client_id などを利用する方が良いのではないかと個人的には思います。

この仕様の概要としてはこんな感じです。

Metadata

OP/RPのURLの扱いが書かれています。

OpenID Provider Metadata

OpenID Provider Metadata では RP が Logout Endpoint を Discovery できるように、end_session_endpointという値を定義します。

Client Registration Metadata

OP が RP-Initiated LogoutとDynamic Registrationをサポートする場合、post_logout_redirect_uris という値を事前に登録します。

ITP, SameSite Cookieとセッション関連仕様への影響

ちょうど先日、OpenID TechNight vol.17 ~ with コロナ編でiframeを使うユースケースへの影響について説明されていました。

https://www.youtube.com/watch?v=0856pHMoTDs

その中で、iframeを使っているために影響が考えられる仕様として2つが紹介されていました。

  • Session Management
  • Front-Channel Logout

それぞれの仕様にもこの影響については言及があります。

  • Session Management - 5.1. User Agents Blocking Access to Third-Party Content「RPコンテキストで呼び出したOPのフレームがCookieにアクセスできず、ログイン状態が変更されたという応答を返し、再認証されまくるかも」
  • Front-Channel Logout - 4.1. User Agents Blocking Access to Third-Party Content「frontframe_logout_uriがOPによってレンダリングされた時にRPのログイン状態にアクセスできなくてログアウトされないかも」

今回のRP Initiated Logoutでは、OPはLogout EndpointへのアクセスでGET/POSTをサポートしなければならない(MUST)とあります。 よって、POSTパラメータとなると2つのパターンの前者ではOP、後者ではOP/RP両方でログアウト機能に関連するHTTP CookieのSameSite属性を意識する必要があります。

そう言えばチャチャッとSameSite属性毎の挙動を確認するためのツールを用意しましたので良かったら記事を読んでみてください。 medium.com

また、ログアウトしますか?のようなユーザーインタラクションを省略すると今度はトラッカー判定の方にも関連してきそうなので、この辺りの仕様とブラウザのHTTP Cookie, トラッカー判定事情の関係は今後も注意深くみていく必要がありそうです。

まとめ

  • RPからOPへのログアウト要求を送る方法が定義されている
  • OPからRPに戻るかどうかで2種類の挙動がある
  • POSTの場合はHTTP CookieのSameSite属性に気を付けろ

昔SessionManagementあたりのサンプル実装をしたことがあったのですがどっか行ってしまったので、またどこかのタイミングで動作確認ができる環境を用意したいと思います。

ではまた!

f:id:ritou:20200821032656p:plain

認証機能を独自実装する代わりにIDaaSのREST APIを使うアプローチ

こんにちは、ritou です。

最近のあれこれでIDaaSと呼ばれる機能に注目が集まっているような気がしますが、どうしてもフロントエンドでの導入部分が目に付きます。 「新規サービスで使っていこう」ならまだしも「既存のを何とかしたい」みたいな場合にフロントエンドまでごっそり変えるのなんて腰が重くなって仕方ない感じでしょう。

そこで今回は、REST APIを用いた新規導入、移行というアプローチもあるのかなという話を書いておきます。

IDaaS の REST API

この辺りをみてみてはどうでしょう。

APIベースで登録/ログイン/パスワード変更など結構揃っている印象です。 Firebaseだとソーシャルログインも実現できそうですし、Auth0のはまだあんまりじっくりみてないですがMFAとかも書いてあります。 あとはCognitoなんかもAPIいっぱいありますよね。

導入方法

このようなREST APIでは

  • UIを自前で用意
  • 受け取った値をさばくバックエンドの処理をREST APIで実現

という感じになりますね。それこそDeviseでやってたところをこのREST APIを使うパターンです。 サービスの種類は違いますがAuthleteはこれで認可サーバーを作っていく形ですね。

SPAかどうかにもあまり依存せずに使えそうですし、フロントにIDaaSのSDKを入れてガッツリUIレベルまでIDaaSに従う実装よりも自然に導入できそうな気がします。 私自身、自前でいくつか認証機能、基盤の開発をやってきた中でまだガッツリこの方式で作り込んだことはないんですが、やるとしたらこのアプローチかなと考えています。

IDaaS導入における不安要素にIDaaSが落ちたらどうする問題があるかと思うんですが、例えばREST APIを用いて取得したユーザー情報を "外部サービスであるIDaaSからの認証結果" と捉えてセッション管理などを自前にする設計パターンもあるんじゃないかと。 万が一IDaaSが落ちてたとしてもエラーハンドリングというかConfig設定とかで一時的にIDaaSに流さないようにし、登録済みメールアドレスなどを用いて自前でリカバリーというか暫定的な認証機能を提供するような感じならそれほどリスクなくできそうかなー、いやでもやっぱめんどくせーなーなどと思いながら引き続き検討してみるつもりです。

IDaaSにとってそれを使うサービスはどんな役割なのかを意識しよう

例えばOpenID Connectでいうところで ”IDaaSがOP、利用サービスがClient" という立場であるように考えがちです。 今回紹介したREST APIを使うイメージとあっているでしょう。

しかし、フロントエンドのSDKなどを使う場合、セッション管理のあたりまでJSでできてしまいます。 IDaaSの責務でセッション管理までする場合、利用するサービスが行うべきことは「現在ログイン中のユーザーを把握してそれに対するリソースアクセスを提供する」ということになり、役割としては利用するサービスのSPAがClient、バックエンドサーバーがResource Serverとなります。

IDaaSを効果的に使っていくためにはこの辺りも意識して設計/実装を進める必要があるでしょう。

まとめ

  • REST API結構ある
  • フロントエンドをあまり使わずにバックエンドで導入していくアプローチもあるのではないか
  • 自分はClientを作るのかResource Serverだけにするのかというレベルの検討も必要そう

おまけ

Firebase AuthnのAPIに「OAuth認証情報でサインインする」というのがあります。

https://firebase.google.com/docs/reference/rest/auth#section-sign-in-with-oauth-credential

いわゆるソーシャルログインをAPIベースでやろうとするものですね。

過去にネイティブアプリとバックエンドサーバーをOAuth 2.0のClient/Serverとして作り込まれたプラットフォームに関わっていたときに、ネイティブアプリでのソーシャルログイン実装でこのような独自拡張を実装したことがあります。

メンテナになってるPerlのOAuth 2.0 Serverライブラリである OAuth::Lite2 にはその痕跡が残されています。やりたい放題でした。

Changes - metacpan.org

0.09 2014-07-22T07:36:43Z
    - rename grant_type to external_service
    - rename params for grant_type=external_service
 
0.08 2014-06-03T07:54:41Z
    - add support for new grant types
        - "urn:ietf:params:oauth:grant-type:federated-assertion" : obtain access_token from external service assertion

GrantTypeにソーシャルログイン用のものを作成して、例えばGoogleなどから受け取ったAT/RT/AuthzCode/IDTokenなどを送ってログインさせようというものです。 オレオレ拡張仕様のメモ:

social_login_bearer_profile_for_oauth2.md · GitHub

このように、APIベースでもソーシャルログインなど実装できるものはたくさんありますので、今回紹介したREST APIを使ったアプローチを検討してみてはいかがでしょうか。

ではまた!

f:id:ritou:20200819131651p:plain

Capability URLsをBearer Tokenと捉えた場合のJWT適用の可能性

f:id:ritou:20200812192943p:plain

こんばんは。ritouです。 少し前に、このようなスライドを見かけました。

docs.google.com

今回はこのCapability URLsにJWTを使ってみてはいかがかなというお話をします。

Capability URLs as a Bearer Token

挙げられている特徴や要件として

  • 推測できてはいけない
  • URLとして適切な長さ(ブラウザによって処理できないやつが出てこない)

ぐらいで、"えいち、てぃー、てぃー、ぴー、..." とラジオのDJが番組内で紹介できるぐらいの短さを求められたりしないのであれば、OAuth 2.0のBearer Tokenの要件と同等に捉えることもできそうです。

qiita.com

JWTの適用

JSON Web Token、正確には JSON Web Signature を使うことで

  • 構造化されたデータを文字列にできる : リソースに一意に紐づけられるだけでなく、ちょっとしたパラメータを加えられる
  • 改ざんされていないことを検証できる : 第3者が有効なURLを生成しにくい

という特徴を利用できます。

JWTといえばステートレス信仰が湧き上がって来るわけですが、ここでは一旦おいておきます。 JWTをCapability URLsに利用する際のポイントを整理すると

  • 元々設計されているリソース識別子のエントロピーに影響しないURLが作成可能 : 任意のURLにアクセスできる確率の話は署名の方に依る
  • 同じリソースに対して細かいパラメータを加えてやれば有効期限などのちょっとした制御もできる
  • 無効化などの管理もJWT自体の識別子や全体のハッシュ値などを使えば それなりにできる

となるでしょう。 当然、

  • JWTのPayloadに含まれる情報には気をつける必要がある(見られたくないデータは含まない)
  • Payloadにたくさん入れすぎるとURLが長くなる(CWTワンチャン?)

というあたりには気をつける必要があるわけですが、十分実用に耐えうるのではないかと思います。

まとめ

  • Capability URLs も Bearer Token の要件に近いのではないか
  • JWTを適用することで得られるもの、気をつけるべき点をざっくり整理した

という感じです。 この手の機能の設計を行う際に、JWTの適用も選択肢に加えてみるのもいかがでしょうか?

それにしても私が数年前から罹患しているこの「何でもJWTで解決しようとしてしまういわゆるeyJ病」なかなか厄介です。 ではまた。

bosyuが実装したメールアドレスでの登録/ログイン機能とは!?

f:id:ritou:20200727191917p:plain

こんばんは、ritouです。

今日はこの機能を使ってみましょう。

何の話?

medium が前から採用していた方式です。

medium.com

これを新しい方式と捉えるかどうか、個人的にはそれほど新しくは感じません。

メアドでリカバリー手段を確保しつつパスワードを設定させるのが現状一般的な「パスワード認証を用いた登録フロー」だとしたらそこからパスワード設定を抜いたものがメアドによる新規登録フローと言えるでしょう。 また、パスワードを忘れた際にメアドでリカバリーする処理を認証フローとして使うことで「パスワード認証を用いた認証フロー」からパスワードの検証を取り除いたものと考えることができます。いつだったかのbuildersconでもそんな話をしたことがある気がしますね。

f:id:ritou:20200727190404p:plain

当然、この方式ではメールを受信できる環境が第3者の管理下に置かれた場合などが問題となるわけですが、それは既存のパスワード認証でもだいたい同じことが言えるでしょう。 一時的に利用できない場合もあるかもしれません。その場合は、SMSだったり他の認証方式と組み合わせる必要が出てくるでしょう。 この辺りを頭に入れつつ、見ていきましょう。

新規登録 from PC画面

PCから挙動を見てみましょう。メアドを入れます。

f:id:ritou:20200727183359p:plain

新規登録用のリンクを送りましたと出ます。 いや、出ませんね。ログイン用のリンクって書いてあります。 テンプレート間違えてるのでは疑惑がありますがまぁいいでしょう。

f:id:ritou:20200727183429j:plain

送られたメールにはボタンとリンクで新規登録を続けるためのURLがついています。 HTMLメールの扱いなどもあるかもしれませんが、メールを開く環境とbosyuを利用する環境が別だった場合はコピペしてメアドを入力した環境で処理を続けることができます。

f:id:ritou:20200727183448j:plain

アクセスすると新規登録を続けるための画面になります。

f:id:ritou:20200727183501p:plain

新規登録はこれで完了です。

新規登録 from Modile画面

次にモバイルのブラウザで開いた場合の挙動を確認しましょう。

f:id:ritou:20200727184435j:plain

メアドを入れた後の挙動が変わっています。 新規登録コードを送ったと表示され、入力フォームがあります。

f:id:ritou:20200727184449j:plain

これはメールを確認した後に再びモバイルの画面で処理を続けるために、コード入力という方式を選択しているということでしょう。 当然ながら送られてくるメールの内容もPCからの場合とは異なります。 コードを表示しつつ、リンクをコピペすることでもURLにアクセスできます。

f:id:ritou:20200727185039j:plain

mediumでも同様にPC/Mobileのブラウザ(もしくはアプリかどうかも?)を判別しているようですが、現状ではこのやり方がスタンダードと言えるでしょう。

ログイン

スクショ撮りまくりましたが、だいたい一緒っぽいので省略します。

登録状態の返答

パスワードを利用しないにせよ、メールアドレスを入力する機能となると、登録済みかどうかをどう扱うかが気になるところです。

qiita.com

bosyuの場合は、エラーを表示した後にメアドをフォームから消してくれる仕様となっております。

f:id:ritou:20200727162011p:plain

f:id:ritou:20200727161813p:plain

攻撃者視点で言うと、仮にメアド(とパスワード)のリストがあるときに登録済みかどうかを確認することで、生きているメールアドレスを抽出できるとも言えます。bosyuではパスワードを預かっていないと言うことで直接それが別の攻撃に繋がることはないため、ユーザーフレンドリーに結果をお伝えしていると言うところでしょうか。

この辺りはバランスが難しいですね。個人的には上記Qiitaの記事に書いたとおり画面ではエラーを返さない仕組みにしたいところです。

まとめ

bosyuが実装したメアドで登録/ログインの機能を確認しました。 もっといろいろな機能を持つサービスであれば「メールが急に届かなくなった」場合のリカバリーをもう少し考える必要が出てきて悩ましいところですが、比較的ライトなサービスであればこのぐらいの実装で問題ないと思います。

たくさん使われると良いですね。 ではまた!

(追記 : 前からこの辺の話はQiitaに書いてたので参考までに貼っておきます)

qiita.com

qiita.com

ユーザー名にURLやドメインを含むSNSのアカウントとメール通知による拡散行為について

こんばんは。ritouです。

f:id:ritou:20200614004856p:plain

なんの話?

ちょっと前にQiitaでこんなことがありました。

qiita.com

最近はこんなのも見かけました。

ということで、表題の通りSNSのユーザー名にURLやドメインを含み、通知用のメールが送られることで可能となる拡散行為について取り上げます。

拡散行為のターゲットは?

既存ユーザーをターゲットにした拡散行為

Qiitaの例では

  1. 悪意のある者は拡散させたいURL=ドメインを含む名前のアカウントを用意する
  2. 悪意のある者は既存ユーザーを次々とフォローしていく
  3. フォローされた人は、「〜さんからフォローされました」というような文言がメールで送られる
  4. メーラーによってドメイン部分がリンクとなりそこから誘導可能な状態となる

という流れのように見えます。

フォローやいいねを繰り返すことで、ドメインを拡散できる可能性があります。既にたくさんのユーザーを抱えるサービスなどでは注意が必要でしょう。

未登録ユーザーをターゲットにした拡散行為

後者のサービスの例では

  1. 悪意のある者は新規登録時にメールアドレスとURLを含む名前を入力する
  2. メールアドレス向けに「こんにちは ~ さん」のように名前を含むメールが送られる
  3. メールアドレスを持っている人のメーラーによってURL部分がリンクとなりそこから誘導可能な状態となる

新規サービスだからと言って安心してはいけません。 ターゲットのメアドリストを突っ込んでいくことで、URLやドメインを拡散できる可能性があります。

対策

いくつかあるでしょう。

メールで送られる可能性のある名前にURLやドメインが含まれないようにする

現実的に、こんにちは~さん、というメールはよく送られています。 登録時のユーザー名のバリデーションを厳密にやろうと思うとなかなか困難そうです。

URLやドメインを含む可能性がある"名前"を含むメールを送らない

新規登録時には、先にメールアドレスの確認を行うことで、登録完了してから名前入りのメールが行われるようになるなど、頻度は減らせるかもしれません。

URLやドメインがリンクとして扱われないようなメールにする

これも簡単ならやるべきかもしれませんが各メーラーの挙動はどうなんでしょう。

まとめ

URLの拡散行為への対策についてもう少し考えてみても良さそう(雑)

ではまた。


6/17追記

自作サービスがDDoS攻撃された話 - 週休7日で働きたい

「リンクを拡散できる」ことと「たくさんアカウントが作られたこと」のそれぞれの事象について

  • URLを弾く
  • reCAPTCHA や js などで大量アクセスを防ぐ

という考察が行われていますが、それぞれについてより深い考察が行われることが他のサービスで似たような被害が行われることを防ぐことに繋がるでしょう。