이 문서는 카카오 로그인이 적용된 서비스 사용자 계정의 상태가 변경되었을 때, 해당 정보를 서비스에 공유해 주는 보안 이벤트 구독에 대해 설명합니다.
보안 이벤트 구독은 사용자의 앱 연결 및 해제, 비밀번호 변경, 사용자 계정 비활성화와 같이 계정 상태에 중요한 변화가 생겼을 때, 그 내용을 사전에 등록된 콜백 URL로 전달하는 기능입니다. 서비스는 변경 알림을 통해 세션 종료, 사용자 재인증 요구 등 필요한 조치를 취해 보안을 강화할 수 있습니다.
이벤트는 OpenID 재단에서 개발 및 제공하는 Shared Signals and Events Framework(이하 'SSF') 규격을 바탕으로 설계됐으며, 일부 이벤트는 카카오에서 직접 정의하여 제공합니다.
용어 | 설명 |
---|---|
이벤트 | 앱 연결 및 해제, 비밀번호 변경, 사용자 계정 비활성화와 같은 사용자의 상태 변경 시 발생하는 이벤트 |
콜백 URL | 카카오로부터 이벤트를 전달받을 엔드포인트 설정하기 > 보안 이벤트 참고 |
SET | 보안 이벤트 토큰(Security Event Token, 이하 'SET') 보안 이벤트 발생 시, 서비스가 설정한 콜백 URL로 전달되는 정보 이벤트 정보를 안전하게 전달하기 위해 JSON 웹 토큰(JSON Web Token, JWT) 형식으로 전달 OpenID 재단의 Security Event Token (SET) 사양 참고 |
CAEP, RISC 카테고리의 보안 이벤트는 민감 정보를 포함합니다. 따라서 [보안 이벤트 정보 제공] 동의항목 설정 및 사용자 동의가 필요합니다.
필요 시 아래 절차를 진행합니다.
[보안 이벤트 정보 제공]은 [필수 동의]는 설정할 수 없어 사용자가 동의하지 않을 수 있습니다. 사용자가 [보안 이벤트 정보 제공]에 동의하지 않은 경우, CAEP, RISC 카테고리 보안 이벤트 정보는 제공되지 않습니다.
지원하는 카테고리별 이벤트는 아래와 같습니다. 카테고리 이름 선택 시 해당 카테고리 하위에 속한 이벤트를 자세히 확인할 수 있습니다.
카테고리 | 설명 | 사용 사례 |
---|---|---|
OAUTH | OAuth 2.0 프로토콜과 관련된 보안 이벤트 타입, 주로 액세스 토큰의 발급, 취소, 클라이언트 상태 변경 등을 포함 OpenID 재단의 OAUTH 규격 사용 |
카카오 로그인 사용자의 앱 연결 및 해제, 동의항목 동의 및 철회 시 알림 |
RISC | 사용자 카카오계정의 이상징후 보안 이벤트 포함 OpenID 재단의 RISC(Risk Incident Sharing and Coordination) 규격 사용 중요: 동의항목 설정 필요 |
사용자 계정의 비정상적인 활동이나 계정 탈취 시도 시 알림 |
CAEP | 사용자 카카오계정에 발급된 자격증명(Token) 및 액세스 권한과 관련된 보안 이벤트 OpenID 재단의 CAEP(Continuous Access Evaluation Protocol) 규격 사용 중요: 동의항목 설정 필요 |
인증 보안 수준이나 비밀번호 변경 시 알림 |
KAKAO | 사용자 카카오계정의 상태 정보 변경 시 발생하는 이벤트 카카오에서 정의하여 제공하는 규격 |
이메일, 생일 등과 같은 프로필 정보 변경 시 또는 OpenID에서 제공하지 않는 카카오 자체 제공 이벤트 발생 시 알림 |
OAuth 카테고리는 OAuth 2.0 프로토콜과 관련한 보안 이벤트 타입을 포함합니다.
이벤트 타입 | 발생 시점 | 권장 조치 사항 |
---|---|---|
Tokens Revokedhttps://schemas.openid.net/secevent/oauth/event-type/tokens-revoked |
카카오 로그인을 통해 발급된 사용자의 모든 토큰 만료 | 필수: 현재 열려 있는 서비스 세션을 종료하여 사용자 계정 보호 |
User Linkedhttps://schemas.openid.net/secevent/oauth/event-type/user-linked |
사용자가 앱과 연결 | [로그인 시 앱 자동 연결]을 [사용안함]으로 설정한 앱인 경우, 회원 가입 완료 처리 외 서비스에서 필요한 조치 수행 |
User Unlinkedhttps://schemas.openid.net/secevent/oauth/event-type/user-unlinked |
사용자가 앱과 연결 해제 | 사용자 회원 정보의 카카오 로그인 연동을 해제하거나, 카카오 로그인으로만 이용 가능한 경우에는 회원 탈퇴 처리 (참고: 연결 끊기 콜백) |
User Scope Consenthttps://schemas.openid.net/secevent/oauth/event-type/user-scope-consent |
사용자가 동의항목에 동의 | - |
User Scope Withdrawhttps://schemas.openid.net/secevent/oauth/event-type/user-scope-withdraw |
사용자가 동의항목 동의 철회 | - |
RISC 카테고리는 사용자 계정의 비정상적인 활동을 알리는 보안 이벤트를 포함합니다. 동의항목 설정 및 사용자 동의가 필요합니다.
이벤트 타입 | 발생 시점 | 권장 조치 사항 |
---|---|---|
Account Credential Change Requiredhttps://schemas.openid.net/secevent/risc/event-type/account-credential-change-required |
계정 비밀번호 변경 | 서비스에서 의심스러운 활동이 있는지 확인하여 필요한 후속 조치 결정 |
Account Disabledhttps://schemas.openid.net/secevent/risc/event-type/account-disabled 아래 프로퍼티 포함 reason : 계정 비활성화 원인 |
계정 비활성화: 카카오계정 보호 조치, 잠금 처리, 이용 제재 시 |
필수: 계정이 비활성화된 이유가 hijacking 인 경우 현재 열려있는 세션을 종료하여 사용자 계정 보호 계정이 비활성화된 이유가 bulk-account 인 경우 서비스에서 사용자의 활동을 분석하고 필요한 후속 조치 결정 |
Account Enabledhttps://schemas.openid.net/secevent/risc/event-type/account-enabled |
계정 활성화: 카카오계정 휴면 또는 도용 상태에서 복구될 때 발생 |
사용자의 카카오 로그인 및 카카오계정 이메일 주소로 계정 복구 기능을 다시 활성화 |
Account Purgedhttps://schemas.openid.net/secevent/risc/event-type/account-purged |
계정 탈퇴 | 사용자 계정 삭제 또는 다른 로그인 방법 제공 |
Credential Compromisehttps://schemas.openid.net/secevent/risc/event-type/credential-compromise |
계정 자격증명 손상: 카카오계정 자격증명이 탈취 의심되는 경우(예: 계정 탈취가 의심되는 새로운 환경에서 로그인 성공) |
서비스에서 의심스러운 활동이 있는지 확인하여 필요한 후속 조치 결정 |
Identifier Changedhttps://schemas.openid.net/secevent/risc/event-type/identifier-changed |
계정 식별자 변경: 사용자의 이메일 또는 전화번호가 변경된 경우 |
기존 사용자의 전화번호 또는 이메일을 파기하고, 변경된 전화번호나 이메일로 업데이트 |
Identifier Recycledhttps://schemas.openid.net/secevent/risc/event-type/identifier-recycled |
기존 계정 식별자 사용 불가: 카카오계정의 이메일 또는 전화번호가 다른 사용자에게 사용돼 이메일 인증 만료(Expired), 유예(Suspended) 상태가 된 경우 |
사용자 계정의 이메일 및 전화번호를 더 이상 사용하지 않도록 처리하고, 서비스에서 직접 새로운 이메일 및 전화번호 수집 |
Sessions Revokedhttps://schemas.openid.net/secevent/risc/event-type/sessions-revoked |
계정의 모든 세션 만료: 비밀번호 변경 후 기존 기기 로그아웃 처리 시 |
필수: 현재 열려 있는 세션을 종료하여 사용자 계정 보호 |
CAEP 카테고리는 사용자 계정의 자격 증명과 관련한 보안 이벤트를 포함합니다. 동의항목 설정 및 사용자 동의가 필요합니다.
이벤트 타입 | 발생 시점 | 권장 조치 사항 |
---|---|---|
Assurance Level Changehttps://schemas.openid.net/secevent/caep/event-type/assurance-level-change |
인증 보안 수준 변경: 2차 인증 설정 등 보안 수준 변경 시 발생 |
현재 사용자가 서비스 이용에 필요한 인증 보안 수준을 충족하는지 확인 후, 필요에 따라 재인증 등 조치를 거쳐 서비스 제공 |
Credential Changehttps://schemas.openid.net/secevent/caep/event-type/credential-change |
계정 비밀번호 변경: 비밀번호 재설정 또는 카카오 인증서 재발급 시 발생 |
- |
KAKAO 카테고리는 카카오가 정의하여 제공하는 이벤트 타입을 포함합니다.
이벤트 타입 | 발생 시점 | 권장 조치 사항 |
---|---|---|
User Profile Changedhttps://schemas.kakao.com/platevent/kakao/event-type/user-profile-changed |
사용자의 카카오계정 정보 변경 단, 사용자가 제공 동의한 정보 변경 시에만 알림 |
사용자 정보 가져오기 API를 호출하여 변경된 정보로 업데이트 |
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://kauth.kakao.com/.well-known/sse-configuration | - |
보안 이벤트 구독 시스템의 규격을 확인합니다.
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
issuer | String |
SET 발급자https://kauth.kakao.com 으로 고정 |
O |
jwks_uri | String |
SET 암호화 공개키 조회 URI 공개키는 SET 검증 시 필요 |
O |
delivery_methods_supported | String |
지원하는 SSE 이벤트 전송 방식push 만 지원 |
O |
state | String |
요청 시 전달한 state 값과 동일한 값 |
X |
curl -X GET https://kauth.kakao.com/.well-known/sse-configuration
HTTP/1.1 200 OK
{
"issuer": "https://kauth.kakao.com",
"jwks_uri": "https://kauth.kakao.com/.well-known/jwks.json",
"delivery_methods_supported": "http://schemas.openid.net/secevent/risc/delivery-method/push"
}
메서드 | URL | 필수 응답 규격 | 인증 방식 |
---|---|---|---|
POST |
[내 애플리케이션] > [카카오 로그인] > [보안 이벤트]에 등록한 콜백 URL | SET 검증 결과별 규격으로 3초 내에 응답 - 성공 시: HTTP 상태 코드 202 Accepted - 실패 시: HTTP 상태 코드 400 Bad Request 와 지정 헤더 및 본문(참고) |
- |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
- | 카카오 로그인 활성화 보안 이벤트 |
- | - |
사용자의 보안 이벤트 발생 시, 보안 이벤트 정보를 서비스의 콜백 URL에 HTTP POST
요청으로 전달합니다. 콜백 요청의 헤더(Header) Content-Type
은 application/secevent+jwt
, 본문은 보안 이벤트 정보가 담긴 SET 값입니다.
아래는 콜백 URL로 전달되는 요청 예시입니다.
POST /kakao/events HTTP/1.1
Host: callback.example.com
Content-Type: application/secevent+jwt
Accept: application/json
eyJraWQiOiI2NjVhYmVlYzExOGRkZmMyZDNiZjNlMmFkYWU3OT...
서비스는 콜백 URL에 전달된 콜백에 대해 SET 검증 후 성공 또는 실패로 응답해야 합니다.
콜백 요청이 지속적으로 실패하거나 무응답인 경우, 앱의 보안 이벤트 구독 상태가 비활성화되고 보안 이벤트 전달이 중단됩니다. 이 경우, 서비스에서 보안 이벤트 수신 처리에 이상이 없는지 확인 후 다시 보안 이벤트 구독 설정을 해야 합니다.
서비스는 카카오계정의 보안 이벤트 정보가 담긴 SET을 POST
메서드로 전달받습니다. SET은 JWT(JSON Web Token) 형식의 토큰으로, 아래 세 가지 영역으로 구성돼 있습니다.
구분 | 설명 |
---|---|
헤더(Header) | SET 규격 정보 |
페이로드(Payload) | 보안 이벤트 정보 |
서명(Signature) | 카카오 인증 서버(KAUTH)가 헤더의 kid 에 해당하는 공개키로 서명한 값 |
아래는 헤더, 페이로드 영역에 포함되는 필드의 상세 정보입니다.
이름 | 타입 | 설명 |
---|---|---|
alg | String |
SET에 적용된 암호화 방식, RS256 으로 고정 |
typ | String |
SET의 형식, secevent+jwt 으로 고정 |
kid | String |
SET 암호화 시 사용된 공개키 ID 메타데이터 조회의 SET 암호화 공개키 조회 URI( jwks_uri )에서 확인 가능 |
이름 | 타입 | 설명 |
---|---|---|
iss | String |
SET 발급 기관, https://kauth.kakao.com 으로 고정 |
aud | String |
SET을 전달받는 앱의 REST API 키 |
sub | String |
SET에 해당하는 사용자 회원번호 |
iat | String |
SET 발급 시간 |
jti | String |
SET 고유 식별 값 |
events | Event |
보안 이벤트 타입 및 상세 정보 |
이름 | 타입 | 설명 |
---|---|---|
${SCHEMA} | JSON |
보안 이벤트 타입별 상세 정보 키는 보안 이벤트 타입별 Schema 값은 보안 이벤트 타입마다 차이가 있으므로 아래 보안 이벤트 상세 정보 참고 |
이벤트 타입 | 이름 | 타입 | 설명 |
---|---|---|---|
공통 | subject | Subject |
보안 이벤트 상세 정보 |
OAuth > User Unlinked |
reason | String |
연결 끊기 사유, 아래 중 하나ACCOUNT_DELETE : 카카오계정 탈퇴FORCED_ACCOUNT_DELETE : 장기 휴면 또는 고객센터를 통한 카카오계정 강제 탈퇴INCOMPLETE_SIGN_UP : 가입 미완료자 탈퇴UNLINK_FROM_ADMIN : 카카오 관리자로 인한 탈퇴 처리UNLINK_FROM_APPS : 카카오계정 페이지를 통한 서비스 연결 끊기REVOKE_ACCOUNT_SERVICE_TERMS : 통합서비스 약관 동의 철회UNLINK_FROM_SERVICE : 서비스 탈퇴 |
OAuth > User Scope Consent, User Scope Withdraw |
scope | String |
사용자가 동의 또는 동의 철회한 동의항목 각 동의항목의 ID를 공백으로 이어 붙인 하나의 문자열 (예: account_email birthday age_range ) |
RISC > Identifier Changed, Identifier Recycled |
new-value | String |
변경된 전화번호 또는 이메일 값 |
CAEP > Assurance Level Change |
current_level | String |
카카오계정 인증 레벨nist-aal1 : 2차 인증 미설정 상태nist-aal2 : 2차 인증 설정 상태 |
change_direction | String |
카카오계정 인증 레벨 변경 사항increase : 인증 레벨 상향decrease : 인증 레벨 하향 |
|
previous_level | String |
변경 전 카카오계정 인증 레벨nist-aal1 : 2차 인증 미설정 상태nist-aal2 : 2차 인증 설정 상태 |
|
CAEP > Credential Change |
change_type | String |
계정 비밀번호 변경 유형update : 비밀번호 변경 또는 카카오 인증서 재발급 |
KAKAO > User Profile Changed |
profile | String |
사용자가 변경한 프로필 정보 각 동의항목의 ID를 공백으로 이어 붙인 하나의 문자열 변경된 값은 전달하지 않고, 변경이 발생한 사용자 정보 종류만 전달 (예: account_email birthday age_range ) |
이벤트 타입 | 이름 | 타입 | 설명 |
---|---|---|---|
공통 | subject_type | String |
사용자 식별자 타입iss_sub : 회원번호phone : 전화번호account_email : 이메일 |
iss | String |
SET 발급 기관https://kauth.kakao.com 로 고정중요: Identifier Changed, Identifier Recycled 타입 보안 이벤트 정보에는 미포함 |
|
sub | String |
SET에 해당하는 사용자 회원번호 중요: Identifier Changed, Identifier Recycled 타입 보안 이벤트 정보에는 미포함 |
|
RISC > Identifier Changed, Identifier Recycled |
phone_number | String |
변경 또는 사용 불가 처리된 기존 전화번호 값 |
account_email | String |
변경 또는 사용 불가 처리된 기존 이메일 값 |
SET은 세 영역의 값을 Base64 인코딩(Encoding) 한 후 온점(.)으로 이어 붙인 하나의 문자열로 생성됩니다. 따라서 온점을 기준으로 각 영역을 분리하고, Base64 디코딩(Decoding)하여 내용을 확인할 수 있습니다. 서비스는 SET 검증 후 페이로드 내용을 확인하여 필요한 사용자 계정 보호 조치를 수행할 수 있습니다. 아래는 디코딩된 SET 헤더와 페이로드 예제입니다.
{
"kid": "665abeec118ddfc2d3bf3e2adae799",
"typ": "secevent+jwt",
"alg": "RS256"
}
{
"iss": "https://kauth.kakao.com",
"aud": "${REST_API_KEY}",
"sub": "${USER_ID}",
"txm": "92a79799-3ae3-4112-8fe2-921c710daa38",
"iat": 1674702636,
"jti": "6a1a7a3e-b923-4eb8-886c-cbcbd1621fb0",
"events": {
"https://schemas.openid.net/secevent/oauth/event-type/user-linked": {
"subject": {
"sub": "1376016924429759243",
"subject_type": "iss-sub",
"iss": "https://kauth.kakao.com"
}
}
}
}
서비스는 보안 이벤트 정보에 따른 사용자 계정 보호 조치를 수행하기 전 반드시 SET 내용을 확인하고 검증해야 합니다. 아래 순서로 SET 내용을 확인하고 검증할 수 있습니다.
iss
값이 https://kauth.kakao.com
와 일치하는지 확인aud
값이 서비스 앱의 REST API 키와 일치하는지 확인서명 검증은 아래 순서로 진행합니다.
kid
에 해당하는 공개키 값 확인SET 수신 서버가 콜백 수신 후 SET 검증에 성공한 경우, 본문 없이 HTTP 상태 코드 202 Accepted
로 3초 내에 응답해야 합니다. 아래 예제를 참고합니다.
HTTP/1.1 202 Accepted
SET 수신 서버가 콜백 수신 후 SET 검증에 실패한 경우, 아래 형식으로 3초 내에 응답해야 합니다.
400 Bad Request
Content-Type
: application/json
JSON
형식으로 RFC8935 규격에 따라 에러 코드(err
)와 이유(description
) 포함아래 예제를 함께 참고합니다.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"err": "invalid_key",
"description": "Key ID 12345 has been revoked."
}
Error Code | 설명 |
---|---|
invalid_request | 전달된 SET가 JWT 규격에 맞지 않을 경우 |
invalid_key | 전달된 SET을 카카오의 공개키로 복호화 실패 시 |
invalid_issuer | 전달된 SET의 issuer가 카카오가 아닐 경우 |
invalid_audience | 전달된 SET의 aud 값이 서비스 앱ID와 일치하지 않을 경우 |
보안 이벤트 수신 처리가 올바르게 구현되었는지 [도구] > [보안 이벤트 테스트]에서 확인할 수 있습니다.
🅐 앱: 테스트 대상 앱 선택 🅑 콜백 URL: 보안 이벤트 설정 시 입력한 콜백 URL 표시 🅒 카테고리: 보안 이벤트 카테고리 선택, 테스트 시에는 모든 카테고리 선택 가능 🅓 이벤트 타입: 테스트 전송할 보안 이벤트 타입 선택, RISC와 CAEP 카테고리는 권한이 필요하나 테스트 시에는 이용 가능 🅔 카카오계정: 앱에 등록된 팀원 중 이벤트를 발송할 팀원 선택, 단, 선택한 계정은 해당 앱에 [연결]되어 있어야 이벤트를 발생시킬 수 있음 🅕 파라미터: 일부 카테고리의 경우 파라미터 입력 필요, 아래 참고
카테고리 | 이벤트 타입 | 파라미터 |
---|---|---|
OAuth | User Unlinked | reason : 사용자가 앱과 연결을 끊은 경로 선택 |
OAuth | User ServiceTerms Consent | scope : 사용자가 동의 시 콜백을 받을 사용자 정보 선택 |
OAuth | User ServiceTerms Withdraw | scope : 사용자가 동의 철회 시 콜백을 받을 사용자 정보 선택 |
OAuth | Tokens Revoked | reason : 토큰을 만료한 주체 선택, issuer(발급자) 또는 user(사용자) 중 하나 |
RISC | Account Disabled | reason : 카카오계정 비활성화 이유 선택 |
RISC | Identifier Changed | subject_type : 계정 식별 대상 선택, phone(전화번호) 또는 email(이메일) 중 하나 new_value : 변경된 새 전화번화 또는 이메일 입력 |
CAEP | Assurance Level Change | previous_value : 변경 전 카카오계정 인증 레벨 선택new_value : 변경 후 카카오계정 인증 레벨 선택, nist-aal1(2차 인증 미설정 상태) 또는 nist-aal2(2차 인증 설정 상태) 중 하나 |
KAKAO | User Profile Changed | profile : 변경 이벤트를 전송할 사용자 정보 종류 선택(예: account_email birthday age_range ) |
[발송]을 누르면 페이지 하단에 아래와 같은 테스트 정보가 나타납니다.
🅐 보안 이벤트 요청: 테스트 전송된 요청 전문, 콜백 URL 미설정 시 Host
와 URL
미포함 예시 출력
🅑 보안 이벤트 토큰: 🅐의 요청에 포함된 SET을 디코딩한 값, header
와 payload
각각 출력, 디버깅 시 참고