LabHub
배우기 러닝패스 코스

企業認証の連携

SAML Assertionを解体する

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

실제 형태의 SAML Response 를 디코드해 Issuer·NameID·Conditions·속성·서명 요소를 직접 추출하고, SP 가 반드시 검증해야 할 항목을 정리할 수 있게 됩니다.

왜 중요한가

SAML 연동은 대개 라이브러리가 해 주지만, 장애가 나면 결국 XML 을 직접 봅니다. "Audience 불일치", "NotOnOrAfter 초과", "InResponseTo 없음" 같은 오류 메시지를 받았을 때 문서 어디를 봐야 하는지 알아야 합니다. 그리고 이 실습의 진짜 목적은 서명 검증의 함정을 이해하는 것입니다. XML Signature Wrapping 공격은 서명 검증을 통과하면서도 앱이 읽는 데이터는 가짜인 상태를 만듭니다. "서명이 유효한가"와 "내가 읽는 노드가 서명된 노드인가"가 다른 질문이라는 것을 문서 위에서 확인하고 나면, 왜 SAML 을 직접 구현하면 안 되는지 스스로 설명할 수 있게 됩니다.

단계

  1. /opt/lab/fixtures/auth/saml/response.b64 를 디코드해 /root/saml/response.xml 로 저장합니다. 유효한 XML 이어야 합니다.
  2. /root/saml/head.txt 를 만듭니다. 네 줄이고 형식은 아래와 같습니다.
    issuer=<Response 의 Issuer 값>
    destination=<Destination 속성>
    inresponseto=<InResponseTo 속성>
    status=<StatusCode 의 Value 속성>
    
  3. /root/saml/subject.txt 를 만듭니다. 두 줄입니다.
    nameid=<NameID 값>
    format=<NameID 의 Format 속성>
    
  4. /root/saml/conditions.txt 를 만듭니다. 네 줄입니다.
    notbefore=<NotBefore>
    notonorafter=<NotOnOrAfter>
    audience=<Audience 값>
    valid=<현재 시각 기준 유효하면 Y, 아니면 N>
    
  5. AttributeStatement 의 속성을 뽑아 /root/saml/attrs.csv 를 만듭니다. 첫 줄은 name,value, 이름 오름차순 정렬입니다.
  6. /root/saml/sig.txt 를 만듭니다. 세 줄입니다.
    reference_uri=<Reference 의 URI 속성>
    digest_alg=<DigestMethod 의 Algorithm 속성>
    signature_alg=<SignatureMethod 의 Algorithm 속성>
    
  7. XML 안의 X509Certificate 내용을 PEM 형식으로 복원해 /root/saml/idp.pem 에 저장합니다. openssl x509 -in /root/saml/idp.pem -noout -subject 가 성공해야 합니다.
  8. /root/saml/checklist.md 를 작성합니다. SP 가 검증해야 할 항목을 7개 이상 목록으로 적고, 각 항목에 검증 실패 시 위험을 한 줄씩 덧붙입니다. 본문에 Audience, NotOnOrAfter, InResponseTo, Destination, Issuer, 서명, 재사용 일곱 단어가 모두 등장해야 합니다.

참고

SAMLResponse 디코드

/opt/lab/fixtures/auth/saml/response.b64 를 디코드해 /root/saml/response.xml 로 저장합니다. 유효한 XML 이어야 합니다.

SAMLResponse 파라미터는 base64 입니다. POST 바인딩에서는 압축이 없고, Redirect 바인딩에서는 deflate 압축이 추가된다는 점도 함께 기억하세요.

Response 헤더 정보 추출

/root/saml/head.txt 를 만듭니다. 네 줄이고 형식은 아래와 같습니다.

issuer=<Response 의 Issuer 값>
destination=<Destination 속성>
inresponseto=<InResponseTo 속성>
status=<StatusCode 의 Value 속성>

네임스페이스가 여러 개인 XML 입니다. xmlstarlet 에서는 로컬 이름으로 찾는 방법을 쓰면 접두어에 흔들리지 않습니다.

NameID 와 형식

/root/saml/subject.txt 를 만듭니다. 두 줄입니다.

nameid=<NameID 값>
format=<NameID 의 Format 속성>

NameID 의 Format 이 무엇이냐에 따라 SP 가 사용자를 식별하는 방식이 달라집니다. persistent 와 transient 의 차이를 생각해 보세요.

유효 시간과 대상 확인

/root/saml/conditions.txt 를 만듭니다. 네 줄입니다.

notbefore=<NotBefore>
notonorafter=<NotOnOrAfter>
audience=<Audience 값>
valid=<현재 시각 기준 유효하면 Y, 아니면 N>

NotOnOrAfter 는 '이 시각 이후로는 무효'입니다. 현재 시각과 비교해 판정하세요. 이 fixture 는 과거에 발급된 것입니다.

속성 추출

AttributeStatement 의 속성을 뽑아 /root/saml/attrs.csv 를 만듭니다. 첫 줄은 name,value, 이름 오름차순 정렬입니다.

AttributeStatement 안에 Attribute 가 여러 개 있고 각각 값이 하나 이상입니다. 이름과 값을 짝지어 정렬하세요.

서명 요소 확인

/root/saml/sig.txt 를 만듭니다. 세 줄입니다.

reference_uri=<Reference 의 URI 속성>
digest_alg=<DigestMethod 의 Algorithm 속성>
signature_alg=<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개 이상 목록으로 적고, 각 항목에 검증 실패 시 위험을 한 줄씩 덧붙입니다. 본문에 Audience, NotOnOrAfter, InResponseTo, Destination, Issuer, 서명, 재사용 일곱 단어가 모두 등장해야 합니다.

'서명이 유효한가'와 '내가 읽는 노드가 서명된 노드인가'는 다른 질문입니다. 이 차이가 XML Signature Wrapping 공격의 핵심입니다.