ラベル プライバシー の投稿を表示しています。 すべての投稿を表示
ラベル プライバシー の投稿を表示しています。 すべての投稿を表示

2021年7月23日金曜日

必読!「デジタルアイデンティティー」

 こんにちは、富士榮です。


ついに発売されました。米OpenID Foundation理事長の崎村夏彦さんによるデジタルアイデンティティに関する集大成とも言える書籍、その名も「デジタルアイデンティティー 経営者が知らないサイバービジネスの核心」です。

献本いただきましたので早速熟読してみました。


もう一言では言い尽くせないのですが、何しろ素晴らしい。(ボキャブラリー不足、、汗)

ここまで体系的かつ広い視点でデジタルアイデンティティに関して俯瞰した書籍は洋書を含めて存在していなかったんじゃないか?と思います。(Phil Windleyの「Digital Identity」はもちろん良書ですが、如何せん2004年の書籍なので古くなってきています)


とにかくこちらから購入できるので、まだの人は今すぐポチるのです。


ざっと感想を含め見どころを。

  • 言葉の定義が経緯を含めとにかく丁寧に書かれている
    • これを見ると世の中に出回っている記事がどれだけ適当な理解で書かれているのかわかってしまいます。この辺がこの領域をわかりにくくしている原因の一つだと思います。
  • 技術仕様がなぜ必要なのか、OAuth/OpenID Connectがなぜ必要となったのか、など歴史的な経緯を含め解説されている
    • 頑張って仕様を読んでも、あくまで結果をみているだけなので、なぜこのような仕様になったのか?がわからず腹に落ちにくい点もあると思います。もちろん解説記事やイベントでのプレゼンテーションは存在するのですが、分散してしまっているので体系的に理解するのは至難の業です。
  • FAPIやeKYC&IDAなど若い仕様についても言及されている
    • 単純にフレームワークとしてのOAuth/OpenID Connectだけでは不足している実世界でのユースケースと対応するためのプロファイル群についても詳細に記載されている。
  • よく知っている事件を例に何が必要だったのかを解説しており、理解しやすい
    • ドコモ口座事件、SBI証券の不正出金の件、Facebookのアクセストークン漏洩事件などIT業界のみならず広く報道された事件の裏側がデジタルアイデンティティの側面から解説されており、腹落ちしやすい。
  • プライバシーと個人情報保護の関係、トラストフレームワークなどビジネス担当も技術担当も周辺知識として知っておく必要がある知識もカバーしている
    • まさにサブタイトルにもなっている「経営者がしならない〜」という点にも繋がりますが、システム担当だけでなくビジネス担当やまさに経営者の方も知らなかった、では済まされないプライバシー尊重に関する考え方についても非常に易しく書かれており、非技術者でも読みやすい。

書き始めるとキリがないので、この辺りでやめておきます。

また、大きな特徴として「他の文献への参照が異常に少ない」という点が挙げられると思います。これは常に第一線でデジタルアイデンティティに取り組んでこられた崎村さん自身が執筆している、ということが大きく影響していると思われます。つまり、本書は今後の文献では一次ソースとして扱われることになる、ということを示しています。その点においても必携・必読であるとも言えます。


ちなみに、OpenIDファウンデーション・ジャパンでは崎村さんをお招きして本書の見所解説などを直接お話しいただく出版記念イベントを企画している最中です。こちらは纏まりましたら改めてお知らせしたいと思います。(サインもらえるかも!)

2014年12月22日月曜日

[AD FS]プライバシーに考慮したID連携設定

2か月連続でお世話になりましたCLR/HさんのイベントCLR/H Tokyo vol.7で「ID連携における仮名」の話をしてきました。
(数日前まで登壇の事実を忘れていたので事前準備・告知など全くできず・・・)

当日の資料はこちら



当日行ったデモの内容を含め、少し補足しておきたいと思います。

◆仮名(カメイ)とは
仮名(カメイ/pseudonym)とは、プライバシーに考慮しつつID連携を行いたい、というユースケースに対応した仕組みです。
例えば、企業グループ内で共有しているサービスにおいては、あらかじめ信頼したIdentity Provider(IdP)で認証された、という事実だけがあれば本来個人を特定する情報(氏名やメールアドレス)は不要なはずです。(アプリケーションの動作上、もしくは運用上必要になるケースはありますが)
しかし、実際のID連携のシナリオでは「なんとなく」様々な属性が連携されており、ID連携をしている複数のサービス間でユーザ情報の名寄せが出来てしまったりするケースが散見されます。
エンタープライズシナリオにおいては問題になることはあまりありませんが、複数のService Provider(SP)が存在し、かつ運営主体が別個であるコンシューマシナリオやセンシティブな情報を扱うシナリオ(例えば医療情報などを扱うSPを含むシナリオ)ではユーザ情報の名寄せは問題となることがあります。

そんな時、サービス毎にユニークな名前(ハンドルネームのようなイメージ)をIdPが自動的に発行することで名寄せを防ぎます。このユニークな名前のことを「仮名」と呼びます。
また、仮名には、
・永続的な仮名
・一時的な仮名
があります。

永続的な仮名は同じSPに対しては何度ログインし直しても毎回同じ仮名が発行されますので、SP側でデータを持つ場合でも継続してサービスを使うことが出来ます。
一方で一時的な仮名はSPに対してログインする度に異なる仮名が発行されるので、同じサービス内でのID情報(前回のログイン時に行った振る舞いなど)を紐づけられる心配はありません。


◆ID連携プロトコルにおける仮名
スライドではSAMLを例に紹介しましたが、ws-federationやSAML、OpenID Connectなどの各種ID連携プロトコルにおいて仮名が実装されています。(PPID/Private Personal Identifierとか呼んだりしています)

SAMLにおいてはNameID Formatで表現しており、
・永続的仮名では「urn:oasis:names:tc:SAML:2.0:nameid-format:persistent」
・一時的仮名では「urn:oasis:names:tc:SAML:2.0:nameid-format:transient」
が使われます。


◆AD FSでの仮名のサポート
これまであまり話題に上りませんでしたが、AD FSでも当然仮名を扱うことが出来ます。

ずいぶん前の記事ですが、このあたりでこっそりと紹介されています。

Technet
 When to Use a Custom Claim Rule
 http://technet.microsoft.com/en-us/library/ee913558.aspx
 - Example: How to issue a PPID claim based on an LDAP attribute

MSDN blog
 Name Identifiers in SAML assertions
 http://blogs.msdn.com/b/card/archive/2010/02/17/name-identifiers-in-saml-assertions.aspx


簡単に解説すると、AD FSにはビルトインで「_OpaqueIdStore」というIDストアが定義されており、そこから適切なNameID Format(persistent/transient)をプロパティとしてつけてクレームを発行する、という手順になります。

以下に設定例を紹介します。
(基本はMSDN blogの手順です)


◆永続的仮名を発行する場合
対象のRelying Partyのクレームルール(要求変換規則)に以下の2つのルールを定義します。

1._OpaqueIdStoreからIDの払い出し
 以下のカスタムルールを直接記載します。
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
 => add(store = "_OpaqueIdStore", types = ("http://mycompany/internal/persistentId"), query = "{0};{1};{2}", param = "ppid", param = c.Value, param = c.OriginalIssuer);




2.払い出された値をNameIDとして発行する
 GUIで設定可能です。
 ・[入力方向の要求の種類]に1で発行した際のtypeを指定します
 ・[出力方向の名前IDの形式]に[永続ID]を指定します


実際に払い出されるSAML AssertionをみるとNameID Formatに「urn:oasis:names:tc:SAML:2.0:nameid-format:persistent」が設定されていて、不必要な属性(名前やメールアドレスなど)が発行されていないことがわかります。
<samlp:Response ID="_8b9add32-95c9-47ae-b0f7-fe8719b14207"
                Version="2.0"
                IssueInstant="2014-12-20T07:57:32.137Z"
                Destination="https://sp.example.com/acs"
                Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
                InResponseTo="dlmfilinoelgaclpmbbiiknifkjngebcocfoocan"
                xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                >
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://idp.example.local/adfs/services/trust</Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </samlp:Status>
    <Assertion ID="_f9880ee1-5236-4a03-911a-dc41d4d6e589"
               IssueInstant="2014-12-20T07:57:32.137Z"
               Version="2.0"
               xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
               >
        <Issuer>http://idp.example.local/adfs/services/trust</Issuer>
        <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
                <ds:Reference URI="#_f9880ee1-5236-4a03-911a-dc41d4d6e589">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                    <ds:DigestValue>qtaUKLYlHQjHAszsestllzzSlwKG/GnfxBTM0LALHmM=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>KC2HtMYzjIQ...snip...bhQ3Dg3QBlpcmiA==</ds:SignatureValue>
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <ds:X509Data>
                    <ds:X509Certificate>MIIC+jCC...snip...E94b3S4cuw==</ds:X509Certificate>
                </ds:X509Data>
            </KeyInfo>
        </ds:Signature>
        <Subject>
            <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">Eh1as1gTWtagxAk+ECEuTnu/dzUS2fyOnx3ER/NMCeg=</NameID>
            <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData InResponseTo="dlmfilinoelgaclpmbbiiknifkjngebcocfoocan"
NotOnOrAfter="2014-12-20T08:02:32.137Z"
Recipient="https://sp.example.com/acs"
/>
            </SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2014-12-20T07:57:32.121Z"
                    NotOnOrAfter="2014-12-20T08:57:32.121Z"
                    >
            <AudienceRestriction>
                <Audience>sp.example.com</Audience>
            </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
            <Attribute Name="http://custom/identity/claims/age">
                <AttributeValue>I am 25 years old.</AttributeValue>
            </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2014-12-20T07:57:31.839Z"
                        SessionIndex="_f9880ee1-5236-4a03-911a-dc41d4d6e589"
                        >
            <AuthnContext>
                <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
            </AuthnContext>
        </AuthnStatement>
    </Assertion>
</samlp:Response>


発行されているのは、
・発行元(Issuer):SPがあらかじめ信頼したIdPのEntityID
・識別子(NameID):仮名
・年齢(age):I am 25 years old.(カスタムスキーマを設定して年齢だけ渡すルールを別途書いています)
・認証情報(AuthnContextClassRef):urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport(パスワードで認証されたことを示します)
といった情報くらいです。
サービスは「あらかじめ信頼したIdP」で「パスワードで認証された」ユーザで「18歳以上(25歳という属性より)」であることがわかるので、ログインを許可しコンテンツを利用させることが出来る、と判断することが出来ます。
また、発行されたNameIDは前回同じユーザがログインした時のものと同じ値なので、サービス側で保持している情報との紐づけも可能となります。


◆一時的仮名を発行する場合
同じく、対象のRelying Partyのクレームルール(要求変換規則)に以下の2つのルールを定義します。

1._OpaqueIdStoreからIDの払い出し
 以下のカスタムルールを直接記載します。
c1:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
 && c2:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant"]
 => add(store = "_OpaqueIdStore", types = ("http://mycompany/internal/sessionid"), query = "{0};{1};{2};{3};{4}", param = "useEntropy", param = c1.Value, param = c1.OriginalIssuer, param = "", param = c2.Value);




2.払い出された値をNameIDとして発行する
 GUIで設定可能です。
 ・[入力方向の要求の種類]に1で発行した際のtypeを指定します
 ・[出力方向の名前IDの形式]に[一時ID]を指定します



実際に払い出されるSAML AssertionをみるとNameID Formatに「urn:oasis:names:tc:SAML:2.0:nameid-format:transient」が設定されていて、不必要な属性(名前やメールアドレスなど)が発行されていないことがわかります。(先の永続IDに発行されたAssertionとNameID部分だけが異なります)
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">luV8SsaKfGB+vn3IpxhsUL1M/EekpM5E4S20YhWp1Go=</NameID>


こちらも同じく発行されているのは、
・発行元(Issuer):SPがあらかじめ信頼したIdPのEntityID
・識別子(NameID):仮名
・年齢(age):I am 25 years old.(カスタムスキーマを設定して年齢だけ渡すルールを別途書いています)
・認証情報(AuthnContextClassRef):urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport(パスワードで認証されたことを示します)
といった情報くらいです。
サービスは「あらかじめ信頼したIdP」で「パスワードで認証された」ユーザで「18歳以上(25歳という属性より)」であることがわかるので、ログインを許可しコンテンツを利用させることが出来る、と判断することが出来ます。
また、発行されたNameIDは前回同じユーザがログインした時のものとは異なる値なので、サービス側では前回ログインしたユーザと今回ログインしてきたユーザが同じユーザであることが判別できないので、サービス内部でのユーザの紐づけは出来ません。


◆仮名を使う場合の注意点
せっかく仮名を使ったとしても、他にユーザを一意にする属性(メールアドレスなど)をAssertionの中に含めてしまうと仮名を使う意味が全くなくなってしまうので注意が必要です。
(おそらくディレクトリ同期したユーザの情報とAD FSが発行するクレームの紐づけをする必要があるが故にではありますが)悪い例として、Office365のID連携ではNameIDは永続的仮名を使うのですが、別途IDP Emailという属性でメールアドレスを設定する必要があるので、実は仮名の使い方としては意味がありません。

アプリケーションとのID連携を設計する際は、必要とされるプライバシー要件を十分に考慮して利用するNameIDのタイプや連携する属性を検討しましょう。