개요
SAML(Security Assertion Markup Language)는 유저ID나 패스워드 등 인증정보를 안전하게 교환하기 위한 XML사양이다. OASIS에 의해 책정되었다. SAML은 SOAP을 베이스로 하여, 동일 도메인 내 또는 특정 벤더 제품에 국한되지 않는 대규모 사이트 사이트에 있어서 상호운영성이 높은 SSO구조나 안전한 인증정보 관리를 실현하는 기술이다.
SSO란?
단일 로그인(Single Sign-on, 이하 SSO)은 사용자가 여러 서비스에 대해 한 번만 로그인하면 모든 서비스에 액세스할 수 있게 해주는 인증 방식이다. 이 방식은 사용자가 각각의 서비스에 대해 별도의 로그인 절차를 거치지 않아도 되므로, 사용자의 편의성을 크게 향상시킨다. SSO는 사용자가 한 번 로그인하면, 그 인증 정보를 다른 서비스에도 전달하는 방식으로 작동한다. 이를 위해 SSO는 일반적으로 중앙 인증 서버를 사용하여 사용자의 인증 정보를 관리한다. 사용자가 서비스에 로그인하면, 인증 서버는 사용자의 인증 정보를 확인하고, 그 정보를 해당 서비스에 전달한다. 이후 사용자가 다른 서비스에 액세스하려고 하면, 그 서비스는 인증 서버에 사용자의 인증 상태를 확인하고, 인증이 확인되면 사용자에게 서비스를 제공한다.
SSO의 예
대표적인 SSO의 예로는 구글 계정이 있다. 사용자는 구글 계정으로 로그인하면, 구글의 모든 서비스(예: Gmail, Google Drive, YouTube 등)에 액세스할 수 있다.
SAML을 이용한 SSO 시스템 구성요소
SAML을 이용한 SSO 시스템은 유저 계정 정보를 관리 및 인증을 수행하는 Identity Provider (IdP)와, 유저에게 서비스를 제공하는 Service Provider (SP)로 구성된다. 상호 인증을 수행하는 IdP와 SP는 사전에 메타정보를 연계하여 “Circle of Trust (신뢰의 고리)” 를 형성한다.
Circle of Trust (신뢰의 고리)
IdP와 SP사이의 신뢰의 고리는 주로 메타데이터 교환과 디지털 서명 기반의 검증을 통해 형성된다. 다음과 같은 과정을 거친다.
1. 메타데이터(Metadata) 생성 및 교환
IdP와 SP는 각각 메타데이터 파일(XML 형식)을 생성한다. 이 메타데이터에는 다음과 같은 정보가 포함된다:
- 엔티티 ID (고유 식별자)
- SSO(Single Sign-On) 및 SLO(Single Logout) 엔드포인트 URL
- 사용 가능한 바인딩 방식 (HTTP-Redirect, HTTP-POST 등)
- 공개 키 (디지털 서명 검증용)
서로의 메타데이터를 수동 또는 자동으로 교환하여 등록한다.
- SP는 IdP의 메타데이터를 가져와서 신뢰할 수 있는 IdP로 등록
- IdP는 SP의 메타데이터를 가져와서 인증 요청을 허용할 SP로 등록
2. 디지털 서명과 인증서 기반 신뢰
메타데이터에는 X.509 인증서가 포함되어 있으며, 이는 SAML 메시지에 서명할 때 사용된다. SP는 IdP가 서명한 SAML Assertion을 수신하면, 공개 키로 서명을 검증하여 메시지의 무결성과 출처를 확인한다. 마찬가지로, IdP도 SP의 요청 메시지에 서명이 있다면 이를 검증할 수 있다.
3. 신뢰 관계의 유지 및 갱신
인증서의 유효 기간이 만료되기 전에 정기적으로 메타데이터를 갱신해야 한다. 일부 시스템은 자동 메타데이터 갱신 기능을 지원하여 신뢰 관계를 지속적으로 유지한다.
※ Circle of Trust의 의미 Circle of Trust는 단순히 IdP와 SP 간의 1:1 관계뿐 아니라, 하나의 IdP가 여러 SP와, 또는 하나의 SP가 여러 IdP와 신뢰 관계를 맺는 구조를 포함한다. 이 구조는 페더레이션(Federation)이라고도 하며, 대규모 조직이나 연합 시스템에서 자주 사용된다.
SAML 어설션 (Assersion)
SAML 은 다음의 세 가지의 ‘어설션(Assertion)’이라고 불리는 보안정보를 다룬다. 어설션은 XML베이스의 증명서이다.
※ 어셜션은 주장이라는 의미를 가지는 Claim과 비슷한 단어다.
- 인증 어설션: 인증 결과를 전달하는데 사용
- 속성 어설션: 속성 정보를 전달하는데 사용
- 인가결정 어설션: 접근제한 정보를 전달하는데 사용
SAML 어설션 구성요소
-
주장(Statements): 주장은 사용자에 대한 구체적인 정보를 제공합한다. 이 정보는 사용자의 이름, 이메일 주소, 역할 등을 포함할 수 있다. 주장은 사용자가 누구인지를 식별하는 데 사용된다.
-
주체(Subject): 주체는 주장이 참조하는 개체를 나타낸다. 대부분의 경우, 주체는 사용자를 나타낸다. 주체는 사용자를 식별하기 위한 고유 식별자를 포함한다.
-
조건(Conditions): 조건은 주장이 유효한 시간과 문맥을 정의한다. 예를 들어, 주장이 특정 시간 동안만 유효하거나 특정 IP 주소에서만 액세스할 수 있도록 제한할 수 있다.
SAML 어설션의 예
이 XML 문서는 사용자의 이름(John Doe), 이메일 주소(john.doe@example.com), 그리고 역할(Admin)을 나타낸다. 이 정보는 서비스 제공자에게 전달되어 사용자가 해당 서비스에 액세스할 수 있도록 한다.
<saml:Assertion>
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
<saml:AttributeStatement>
<saml:Attribute Name="name">
<saml:AttributeValue>John Doe</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="email">
<saml:AttributeValue>john.doe@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="role">
<saml:AttributeValue>Admin</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
바인딩
SAML에서는 IdP와 SP간에 요구 메세지(SAMLRequest), 응답 메세지(SAMLResponse)를 송수신 하기 위한 HTTP나 SOAP 등의 프로토콜에 매핑하는 방법(바인딩)으로서 다음과 같은 종류가 있다.
- SOAP 바인딩: SOAP을 이용하여 어셜선을 보낸다.
- HTTP Redirect 바인딩: Base64 인코딩한 어설션을 HTTP GET 메소드로 보낸다.
- HTTP POST 바인딩: Base64 인코딩한 어설션을 HTTP POST 메소드로 보낸다.
- HTTP Artifact 바인딩: Artifact를 HTTP 리다이렉트로 보낸다. Assertion의 크기가 크기 때문에 GET이나 POST로 전달못하는 경우가 생겨서 등장.
SAML을 이용한 SSO 인증 흐름
HTTP Redirect 바인딩을 사용한 SSO 흐름이다.
출처:https://en.wikipedia.org/wiki/SAML_2.0
1. 사용자 접근 요청 (User Requests Access)
- 사용자가 브라우저를 통해 서비스 제공자(SP, Service Provider)에 접근한다.
- 예: 사용자가 회사의 클라우드 앱에 접속 시도.
2. SP가 인증 요청 (SP Sends Authentication Request)
- SP는 사용자가 인증되지 않았음을 인식하고, 인증을 위해 SAML인증요청(SAML AuthnRequest)을 생성한다.
- 이 요청은 브라우저를 통해 IdP(Identity Provider)로 전달된다.
3. 사용자 인증 (User Authenticates at IdP)
- 사용자는 IdP(예: 회사의 SSO 시스템, Entra ID, Okta 등)에서 로그인한다.
- 로그인 성공 시, IdP는 전사서명이 부여된 SAML 응답(SAML Response)을 생성한다. 이 응답에는 사용자의 인증 정보(Assertion)가 포함된다.
4. SAML 응답 전달 (SAML Response Sent to SP)
- SAML 응답은 브라우저를 통해 다시 SP로 전달된다.
- 이 응답은 디지털 서명되어 있어 위조를 방지한다.
5. SP가 응답 검증 및 세션 생성 (SP Validates and Grants Access)
- SP는 SAML 응답을 검증하고, 사용자의 세션을 발행하여 접근을 허용한다. 이후, 이 유저는 “Circle of Trust” 내의 다른 SP에 재차인증을 하지 않고도 접근할 수 있게 된다.
※ SAML은 집 열쇠와 비슷하다. 시설에 접근할 수 있도록 허가해 준다.
SAML 메세지의 예
SAML AuthNRequest (SP -> IdP)
Simple AuthNRequest
<!-- SAML 요청 예시 -->
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="identifier_1"
Version="2.0"
IssueInstant="2022-01-01T00:00:00Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="https://sp.example.com/acs">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
https://sp.example.com/metadata
</saml:Issuer>
</samlp:AuthnRequest>
AuthNRequest with embedded signature (HTTP-POST binding)
전자서명이 들어간 메세지를 HTTP-POST 바인딩으로 보낼 때의 메세지의 예이다. 전자서명(SignatureValue)과 증명서 정보(X509Certificate)가 들어가 있다.
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx41d8ef22-e612-8c50-9960-1b16f15741b3" Version="2.0" ProviderName="SP test" IssueInstant="2014-07-16T23:52:45Z" Destination="http://idp.example.com/SSOService.php" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://sp.example.com/demo1/index.php?acs">
<saml:Issuer>http://sp.example.com/demo1/metadata.php</saml: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/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfx41d8ef22-e612-8c50-9960-1b16f15741b3">
<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/2000/09/xmldsig#sha1"/>
<ds:DigestValue>yJN6cXUwQxTmMEsPesBP2NkqYFI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>g5eM9yPnKsmmE/Kh2qS7nfK8HoF6yHrAdNQxh70kh8pRI4KaNbYNOL9sF8F57Yd+jO6iNga8nnbwhbATKGXIZOJJSugXGAMRyZsj/rqngwTJk5KmujbqouR1SLFsbo7Iuwze933EgefBbAE4JRI7V2aD9YgmB3socPqAi2Qf97E=</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQQFADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcwMDI5MjdaFw0xNTA3MTcwMDI5MjdaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vU/6R/OBA6BKsZH4L2bIQ2cqBO7/aMfPjUPJPSn59d/f0aRqSC58YYrPuQODydUABiCknOn9yV0fEYm4bNvfjroTEd8bDlqo5oAXAUAI8XHPppJNz7pxbhZW0u35q45PJzGM9nCv9bglDQYJLby1ZUdHsSiDIpMbGgf/ZrxqawIDAQABo1AwTjAdBgNVHQ4EFgQU3s2NEpYx7wH6bq7xJFKa46jBDf4wHwYDVR0jBBgwFoAU3s2NEpYx7wH6bq7xJFKa46jBDf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQCPsNO2FG+zmk5miXEswAs30E14rBJpe/64FBpM1rPzOleexvMgZlr0/smF3P5TWb7H8Fy5kEiByxMjaQmml/nQx6qgVVzdhaTANpIE1ywEzVJlhdvw4hmRuEKYqTaFMLez0sRL79LUeDxPWw7Mj9FkpRYT+kAGiFomHop1nErV6Q==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
<samlp:RequestedAuthnContext Comparison="exact">
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</samlp:RequestedAuthnContext>
</samlp:AuthnRequest>
Response
사용자 인증후에 Idp가 SP로 돌려주는 메세지의 예이다. 전자서명이 포함된 메세지등, 더욱 자세한 것은 여기 를 참조하자.
<!-- SAML 응답 예시 -->
<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="identifier_2"
InResponseTo="identifier_1"
Version="2.0"
IssueInstant="2022-01-01T00:01:00Z"
Destination="https://sp.example.com/acs">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
https://idp.example.com/metadata
</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_3"
Version="2.0"
IssueInstant="2022-01-01T00:01:00Z">
<!-- 사용자 인증 정보 및 속성 -->
</saml:Assertion>
</samlp:Response>
SAML vs OIDC
- SAML과 OIDC는 각각 XML, JSON 기술을 사용하고 상호 호환되지 않는다.
- SSO 기능을 제공한다는 측면에서 비슷하다.(OIDC는 원래 SSO를 위해서 개발된 것은 아니지만 현재는 SSO기능도 제공한다.)
- 하지만 사용되는 곳은 서로 다르다. 기업의 레거시 시스템들 위한 SSO에서는 SAML이 사용된다.
- Google이나 Facebook과 같은 회사는 IdP로, 모바일앱이나 SPA에서 유저들을 위한 SSO가 필요할 때는 OIDC를 사용한다.
- 사실 서로 경쟁하는 관계가 아니라 서로 연동되는 관계다.
OIDC를 사용하는 경우:
- 모바일 앱 또는 SPA(Single Page Application)에서 인증이 필요할 때
- OAuth 2.0 기반 API 인증과 함께 사용하고 싶을 때
- Google, Microsoft, Apple 등 현대적인 IdP와 연동할 때
- JWT 기반 토큰을 활용하고 싶을 때
SAML을 사용하는 경우:
- 기업 내부의 레거시 시스템과 연동할 때
- 엔터프라이즈 SSO가 필요한 경우 (예: 사내 포털, ERP, Salesforce 등)
- IdP가 SAML만 지원하는 경우 (예: 일부 ADFS, Shibboleth 등)
- 브라우저 기반 웹 애플리케이션 중심일 때
SAML 인증과 OIDC가 같이 사용되는 패턴
.
SAML 인증과 관련된 취약점: XML 서명 래핑 공격 XML Signature Wrapping (XSW)
XML 서명 래핑 공격은 SAML응답을 조작하여 계정의 권한 상승을 노리는 공격이다.
구체적으로는 다음과 같은 방식으로 공격을 수행된다:
- 공격자가 유효한 SAML 응답을 가로채고,
- 새로운 악의적인 어설션을 삽입한 후,
- 원래의 서명은 그대로 유지하면서 구조를 변경하여 검증 로직이 원래 서명된 어설션이 아닌, 공격자가 삽입한 어설션을 사용하도록 유도한다.
이 공격은 SAML 응답을 파싱하고 서명을 검증하는 로직이 부정확하거나 불완전할 때 발생한다. 예를 들어, XML 파서가 서명된 어설션이 아닌, 첫 번째로 발견된 어설션을 사용하는 경우가 이에 해당한다.
예를 들면, 다음과 같은 SAML응답이 정상적인 것이라 하자.
<Response>
<Assertion ID="abc123">
<Subject>
<NameID>normal_user@example.com</NameID>
</Subject>
<AttributeStatement>
<Attribute Name="Role" Value="user"/>
</AttributeStatement>
</Assertion>
<Signature>
<!-- 디지털 서명: Assertion ID="abc123"에 대한 서명 -->
</Signature>
</Response>
공격자가 이 응답을 가로채서 다음과 같이 수정했다고 하자. 서명은 여전히 abc123 어설션에 대해 유효하다. 애플리케이션이 첫 번째 어설션(attacker123)을 사용하도록 구현되어 있다면, 공격자는 admin 권한을 가진 사용자로 인증된다.
<Response>
<Assertion ID="attacker123">
<Subject>
<NameID>attacker@example.com</NameID>
</Subject>
<AttributeStatement>
<Attribute Name="Role" Value="admin"/>
</AttributeStatement>
</Assertion>
<Assertion ID="abc123">
<Subject>
<NameID>normal_user@example.com</NameID>
</Subject>
<AttributeStatement>
<Attribute Name="Role" Value="user"/>
</AttributeStatement>
</Assertion>
<Signature>
<!-- 디지털 서명: Assertion ID="abc123"에 대한 서명 -->
</Signature>
SAML 인증과 관련된 취약점: SAMLStorm
취약점 유형으로 ‘XML 서명 래핑 공격’이 종래부터 알려졌으나, 최근에는 새로운 SAML 인증 우회 공격인 SAMLStorm이 알려졌다. SAML 인증(어설션) 응답의 XML 서명을 검증할 때, 라이브러리 내부에서 이용되는 XML 파서의 동작에 차이가 있는 것이 주원인이다.
CVE-2025-29774, CVE-2025-29775 (CVSS:9.3)
- Node.js용 SAML라이브러리 “xml-crypto”가 해당된다.
CVE-2025-25291 CVE-2025-25292 (CVSS:9.1)
- Ruby용 SAML라이브러리 “ruby-saml”가 해당된다.
서명 래핑 패턴
예를 들면, 공격자는 다음과 같은 응답을 SP에게 보낸다. 핵심포인트는 다음과 같다.
- 서명은 _valid_assertion에만 적용되어 있음
- 공격자는 _fake_assertion을 추가했지만, xml-crypto는 이를 무시하지 않고 처리함
- SP는 _fake_assertion을 신뢰하고 admin@victim.com으로 인증 처리함
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_some_id" Version="2.0" IssueInstant="2025-06-26T00:00:00Z"
Destination="https://vulnerable-sp.com/sso/acs">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://idp.example.com</saml:Issuer>
<!-- 유효한 서명이 포함된 무해한 assertion -->
<saml:Assertion ID="_valid_assertion" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Subject>
<saml:NameID>user@example.com</saml:NameID>
</saml:Subject>
<!-- 기타 정보 생략 -->
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:Reference URI="#_valid_assertion">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>VALIDDIGEST==</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>VALIDSIGNATURE==</ds:SignatureValue>
</ds:Signature>
</saml:Assertion>
<!-- 공격자가 삽입한 위조 assertion -->
<saml:Assertion ID="_fake_assertion" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Subject>
<saml:NameID>admin@victim.com</saml:NameID>
</saml:Subject>
<saml:AttributeStatement>
<saml:Attribute Name="Role">
<saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
주석 삽입 패턴
DigestValue에 주석을 삽입해 서명 검증을 우회하는 방식이다. 이는
- xml-crypto 라이브러리의 서명 검증 로직이 DigestValue에 포함된 XML 주석을 무시하면서도 해시값을 그대로 사용하는 문제를 악용했다.
- 이를 통해 공격자는 정상적인 서명 구조를 유지하면서도 어설션 내용을 조작할 수 있다.
- 결과적으로 서명은 유효하지만, 어설션은 공격자가 원하는 내용으로 바뀌는 상황이 발생한다.
<saml2p:Response Destination="acsurl" ID="id1857861521424404880641928" ...>
...
<saml2:Assertion ID="id1857861521593646366230134" ...>
<saml2:Issuer>samlissuer</saml2: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="#id1857861521593646366230134">
...
<ds:DigestValue><!--3YjA3OTNjZWQ1GI5YjljNjgzOWZiZWI5OWY1ZTk1ZDk=-->puw8MLNZ67893HzfgbpLjGPfsdSBJueFbcSw2neguIuk=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>assertionsignaturevalue</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>x509certificate</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
...
</saml2:Subject>
...
<saml2:AttributeStatement>
<saml2:Attribute Name="id">
<saml2:AttributeValue ...>idp-id</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
SP는 다음 두 가지를 체크한다.
- 서명검증
- DigestValue 검증
서명검증
- 서명검증시에는 정규화(Canonicalization)과정을 거치므로 주석이 없어진 상태의 XML문서를 대상으로 DigestValue를 계산한다. 따라서 정당한 값이 계산되어 서명과 일치한다.
DigestValue 검증
- DigestValue를 검증할 때에는
CVE-2025-29775 참고
- CVE-2025-29775에 대한 github 리뷰 결과: https://github.com/advisories/GHSA-x3m8-899r-f7c3
- CVE-2025-29775 랩: https://github.com/ethicalPap/CVE-2025-29775
- SAMLStorm에 대한 전반적 설명: https://workos.com/blog/samlstorm
- Ruby 라이브러리의 SAMLStorm: https://github.blog/security/sign-in-as-anyone-bypassing-saml-sso-authentication-with-parser-differentials/
참고
- https://www.okta.com/kr/identity-101/saml-vs-oauth/
- Why SAML?: https://medium.com/@winma.15/why-saml-security-assertion-markup-language-3d961a333fd7
- https://en.wikipedia.org/wiki/SAML_2.0
- MS의 Entra ID를 사용한 SAML SSO: https://learn.microsoft.com/en-us/entra/identity-platform/single-sign-on-saml-protocol
- SAML인증: https://lab.wallarm.com/what/saml-%EC%9D%B8%EC%A6%9D/?lang=ko
- SAML 메세지 예: https://www.samltool.com/generic_sso_req.php