SAML Assertionを解体する
目標
実際の形式のSAML Responseをデコードして、Issuer・NameID・Conditions・属性・署名の要素を自分で抽出し、SPが必ず検証すべき項目を整理できるようになります。
なぜ重要なのか
SAML連携は、たいていライブラリがやってくれますが、障害が起きると、結局XMLを直接見ることになります。「Audience不一致」、「NotOnOrAfter超過」、「InResponseToなし」のようなエラーメッセージを受け取ったときに、文書のどこを見ればよいかを知っている必要があります。そして、このラボの本当の目的は、署名検証の落とし穴を理解することです。XML Signature Wrapping攻撃は、署名検証を通過しながらも、アプリが読むデータが偽物である状態を作り出します。「署名が有効か」と「自分が読むノードが署名されたノードか」が別の質問であることを文書の上で確認すれば、なぜSAMLを自前で実装してはいけないのかを、自分で説明できるようになります。
ステップ
/opt/lab/fixtures/auth/saml/response.b64をデコードして、/root/saml/response.xmlとして保存してください。有効なXMLである必要があります。/root/saml/head.txtを作成してください。4行で、形式は次のとおりです。
(山括弧の中の韓国語はプレースホルダーで、順にResponseのIssuerの値、Destination属性、InResponseTo属性、StatusCodeのValue属性です。)issuer=<Response 의 Issuer 값> destination=<Destination 속성> inresponseto=<InResponseTo 속성> status=<StatusCode 의 Value 속성>/root/saml/subject.txtを作成してください。2行です。
(山括弧の中の韓国語はプレースホルダーで、順にNameIDの値、NameIDのFormat属性です。)nameid=<NameID 값> format=<NameID 의 Format 속성>/root/saml/conditions.txtを作成してください。4行です。
(山括弧の中の韓国語はプレースホルダーで、audienceはAudienceの値、validは現在時刻を基準に有効ならY、そうでなければNです。)notbefore=<NotBefore> notonorafter=<NotOnOrAfter> audience=<Audience 값> valid=<현재 시각 기준 유효하면 Y, 아니면 N>AttributeStatementの属性を取り出して、/root/saml/attrs.csvを作成してください。1行目はname,valueで、名前の昇順で並べ替えます。/root/saml/sig.txtを作成してください。3行です。
(山括弧の中の韓国語はプレースホルダーで、順にReferenceのURI属性、DigestMethodのAlgorithm属性、SignatureMethodのAlgorithm属性です。)reference_uri=<Reference 의 URI 속성> digest_alg=<DigestMethod 의 Algorithm 속성> signature_alg=<SignatureMethod 의 Algorithm 속성>- XMLの中の
X509Certificateの内容をPEM形式に復元して、/root/saml/idp.pemに保存してください。openssl x509 -in /root/saml/idp.pem -noout -subjectが成功する必要があります。 /root/saml/checklist.mdを作成してください。SPが検証すべき項目を7個以上リストで書き、各項目に検証に失敗したときのリスクを1行ずつ添えてください。 本文に、Audience、NotOnOrAfter、InResponseTo、Destination、Issuer、서명、재사용の7つの語がすべて登場する必要があります(最後の2つの語は、韓国語で順に「署名」「再利用」を意味します)。
参考
- 名前空間を無視して要素を探す:
xmlstarlet sel -t -v "//*[local-name()='Issuer']" -n 파일.xml(プレースホルダーはファイル名です) - 属性の値:
xmlstarlet sel -t -v "//*[local-name()='Response']/@Destination" -n 파일.xml(プレースホルダーはファイル名です) - PEMの復元:
-----BEGIN CERTIFICATE-----と-----END CERTIFICATE-----の間に、base64の本文を64文字ずつ改行して入れます(fold -w 64)。 - よくあるミス1: プレフィックス(
saml:、samlp:)をそのままXPathに書いて、何も見つけられないことです。 - よくあるミス2:
ResponseのIssuerとAssertionのIssuerを混同することです。 - よくあるミス3: PEMを1行にして、opensslが読めなくなることです。
SAMLResponseのデコード
/opt/lab/fixtures/auth/saml/response.b64をデコードして、/root/saml/response.xmlとして保存してください。有効なXMLである必要があります。
SAMLResponseのパラメーターはbase64です。POSTバインディングでは圧縮がなく、Redirectバインディングではdeflate圧縮が加わる点も、あわせて覚えておいてください。
Responseヘッダー情報の抽出
/root/saml/head.txtを作成してください。4行で、形式は次のとおりです。
issuer=<Response 의 Issuer 값>
destination=<Destination 속성>
inresponseto=<InResponseTo 속성>
status=<StatusCode 의 Value 속성>
(山括弧の中の韓国語はプレースホルダーで、順にResponseのIssuerの値、Destination属性、InResponseTo属性、StatusCodeのValue属性です。)
ネームスペースが複数あるXMLです。xmlstarletでは、ローカル名で探す方法を使うと、プレフィックスに左右されません。
NameIDと形式
/root/saml/subject.txtを作成してください。2行です。
nameid=<NameID 값>
format=<NameID 의 Format 속성>
(山括弧の中の韓国語はプレースホルダーで、順にNameIDの値、NameIDのFormat属性です。)
NameIDのFormatが何かによって、SPがユーザーを識別する方法が変わります。persistentとtransientの違いを考えてみてください。
有効時間と対象の確認
/root/saml/conditions.txtを作成してください。4行です。
notbefore=<NotBefore>
notonorafter=<NotOnOrAfter>
audience=<Audience 값>
valid=<현재 시각 기준 유효하면 Y, 아니면 N>
(山括弧の中の韓国語はプレースホルダーで、audienceはAudienceの値、validは現在時刻を基準に有効ならY、そうでなければNです。)
NotOnOrAfterは「この時刻以降は無効」です。現在時刻と比較して判定してください。このfixtureは過去に発行されたものです。
属性の抽出
AttributeStatementの属性を取り出して、/root/saml/attrs.csvを作成してください。
1行目はname,valueで、名前の昇順で並べ替えます。
AttributeStatementの中にAttributeが複数あり、それぞれ値が1つ以上あります。名前と値を組にして並べ替えてください。
署名要素の確認
/root/saml/sig.txtを作成してください。3行です。
reference_uri=<Reference 의 URI 속성>
digest_alg=<DigestMethod 의 Algorithm 속성>
signature_alg=<SignatureMethod 의 Algorithm 속성>
(山括弧の中の韓国語はプレースホルダーで、順にReferenceのURI属性、DigestMethodのAlgorithm属性、SignatureMethodのAlgorithm属性です。)
ReferenceのURIが何を指しているかが核心です。それが私たちが実際に読むノードと同じかを確認するのが、署名検証の半分です。
IdP証明書の復元
XMLの中のX509Certificateの内容をPEM形式に復元して、/root/saml/idp.pemに保存してください。
openssl x509 -in /root/saml/idp.pem -noout -subjectが成功する必要があります。
X509Certificate要素の内容は、PEMの本文(base64)だけを含んでいます。ヘッダーとフッターを付けて、改行を入れないと、opensslが読めません。
SP検証チェックリスト
/root/saml/checklist.mdを作成してください。SPが検証すべき項目を7個以上リストで書き、各項目に検証に失敗したときのリスクを1行ずつ添えてください。
本文に、Audience、NotOnOrAfter、InResponseTo、Destination、Issuer、서명、재사용の7つの語がすべて登場する必要があります(最後の2つの語は、韓国語で順に「署名」「再利用」を意味します)。
「署名が有効か」と「自分が読むノードが署名されたノードか」は、別の質問です。この違いが、XML Signature Wrapping攻撃の核心です。