카카오 로그인 SDK SRI 오류: 버전과 해시 맞추기
카카오 JavaScript SDK가 SRI 오류로 실행되지 않을 때 URL 버전과 integrity 해시를 확인하고 로그인 전체 경로를 검증하는 방법.
이 글의 목차소셜 로그인은 한 번의 API 호출이 아니다8
웹에서 카카오 로그인만 동작하지 않는 문제가 들어왔다.
백엔드 로그인 API를 보기 전에 브라우저가 카카오 JavaScript SDK를 실제로 실행했는지부터 확인했다.
기존 로그인 페이지에는 외부 CDN에서 SDK를 불러오는 <script> 태그와 integrity 값이 함께 있었다.
CDN(Content Delivery Network)은 여러 지역의 서버에서 정적 파일을 가까운 위치로 전달해 주는 배포망이다.
그런데 URL이 가리키는 SDK 버전과 무결성 값이 서로 다른 파일을 기준으로 작성돼 있었다.
이미 배포돼 있던 페이지에서 버전과 해시가 어긋나 있었고, 그 상태 때문에 웹 로그인이 동작하지 않았다.
로그인 로직을 뒤집어 보기 전에 브라우저가 외부 파일을 받아 실행하는 경계부터 따라갔다.
소셜 로그인은 한 번의 API 호출이 아니다
카카오 같은 소셜 로그인은 보통 네 구간을 지난다.
페이지가 카카오 SDK를 준비하고, 사용자가 카카오 인증 화면에서 동의한 뒤, 인증 결과가 애플리케이션으로 돌아오고, 마지막으로 서비스 서버가 그 결과를 검증해 자체 세션을 만든다.
SDK는 이 흐름을 시작하기 위한 브라우저용 도구 모음이다.
인증 자체를 모두 대신하는 서버는 아니다.
SDK 파일을 읽지 못한 문제와 잘못된 JavaScript 키, 등록하지 않은 도메인, callback 처리 실패는 사용자에게 모두 “로그인 버튼이 안 된다”로 보일 수 있지만 확인 위치가 다르다.
| 멈춘 위치 | 흔히 보이는 현상 | 먼저 확인할 것 |
|---|---|---|
| SDK 다운로드·실행 | window.Kakao가 없음 | Network, Console, SRI, CSP |
| SDK 초기화 | 객체는 있지만 초기화되지 않음 | JavaScript 키, 초기화 호출 |
| 카카오 인증 화면 | 창이 열리지 않거나 동의 후 실패 | 플랫폼 도메인, 로그인 API 설정 |
| 서비스 callback·세션 | 카카오 인증 뒤 다시 로그아웃됨 | callback 처리, 서버 검증, 쿠키 |
CSP(Content Security Policy)는 페이지가 어떤 출처의 스크립트와 이미지 등을 불러올 수 있는지 제한하는 브라우저 보안 정책이다.
이번 원인은 CSP가 아니라 SRI 불일치였지만, Console에서 차단 이유를 읽으면 둘을 구분할 수 있다.
SDK 요청이 아예 나가지 않았다면 CSP나 URL을, 응답은 왔지만 실행되지 않았다면 SRI와 응답 헤더를 먼저 본다.
로그인 코드까지 도달하지 못하고 있었다
처음에는 로그인 키, 허용 도메인, 로그인 후 돌아올 주소인 redirect URI나 백엔드 인증 API를 의심할 수 있다.
하지만 외부 SDK를 쓰는 로그인은 그보다 앞에 한 단계가 더 있다.
브라우저가 SDK 파일을 내려받고 실행해야 Kakao 객체와 로그인 함수가 만들어진다.
스크립트 실행이 막히면 그 뒤의 초기화나 API 호출은 시작되지 않는다.
SRI(Subresource Integrity)는 CDN 같은 외부 서버에서 받은 파일이 HTML 작성자가 기대한 파일과 같은지 확인하는 웹 표준이다.
브라우저는 다운로드한 파일 바이트로 암호학적 해시를 계산하고 <script> 태그의 integrity 값과 비교한다.
해시는 파일 내용을 일정 길이의 지문으로 바꾸는 계산 결과다.
한 글자만 달라져도 다른 값이 나온다.
일치하는 해시가 없으면 브라우저는 스크립트를 실행하지 않는다.
파일 이름이 같거나 서버가 HTTP 200을 반환했다는 사실만으로 통과하지 않는다.
integrity는 따로 바꾸는 설정이 아니다. URL이 가리키는 실제 파일 바이트와 해시가 한 쌍으로 맞아야 브라우저가 실행한다.버전 번호와 해시를 한 묶음으로 대조했다
카카오 JavaScript SDK 공식 문서는 CDN URL에 명시적인 버전을 넣고, 그 버전에 해당하는 integrity 값과 crossorigin="anonymous"를 함께 사용하도록 안내한다.
구조는 다음과 같다.
<script
src="https://t1.kakaocdn.net/kakao_js_sdk/${VERSION}/kakao.min.js"
integrity="${INTEGRITY_VALUE}"
crossorigin="anonymous"
></script>${VERSION}과 ${INTEGRITY_VALUE}는 그대로 사용할 문자열이 아니다.
카카오 공식 다운로드 문서에서 같은 버전으로 제공하는 값을 넣어야 한다.
src는 브라우저가 내려받을 파일의 주소다.
integrity는 그 파일에서 기대하는 해시 값이다.
crossorigin="anonymous"는 교차 출처 파일을 쿠키 같은 사용자 인증 정보 없이 CORS 방식으로 요청하게 한다.
CORS(Cross-Origin Resource Sharing)는 다른 출처의 리소스를 브라우저가 읽을 수 있는지 서버 응답 헤더로 허용하는 규칙이다.
교차 출처 SRI 검증은 해당 CDN 응답의 CORS 허용과 함께 동작해야 한다.
crossorigin 속성만 붙인다고 허용되는 것은 아니며 CDN도 Access-Control-Allow-Origin 응답 헤더로 접근을 허용해야 한다.
기존 태그를 카카오 다운로드 문서의 같은 버전 script 태그와 나란히 놓고 세 항목을 대조했다.
src경로의 SDK 버전- 해당 버전에 대응하는
integrity전체 값 crossorigin="anonymous"존재 여부
업무 기록에는 당시의 실제 버전 번호와 해시 문자열이 보존돼 있지 않다.
현재 최신 값을 과거 장애 당시 값처럼 만들어 쓰지 않고, 확인 가능한 원인인 “버전과 integrity 불일치”까지만 남겼다.
네트워크 성공과 실행 성공을 나눠 봤다
외부 스크립트 문제를 확인할 때 Network 탭의 상태 코드만 보면 놓치기 쉽다.
SRI가 틀리면 CDN 요청 자체는 성공했어도 브라우저가 실행 단계에서 차단할 수 있다.
같은 증상을 조사한다면 다음 순서가 빠르다.
- Network 탭에서 카카오 SDK URL과 응답 상태를 확인한다.
- Console에서 무결성 또는 스크립트 실행 오류를 확인한다.
- 페이지에서
window.Kakao가 만들어졌는지 확인한다. - SDK 초기화 뒤
Kakao.isInitialized()결과를 확인한다. - 실제 로그인 버튼으로 인증 화면과 callback까지 검증한다.
당시 콘솔 오류 문자열은 원본 기록에 남아 있지 않다.
따라서 특정 브라우저 문구를 실제 관찰처럼 인용하지 않았다.
위 순서는 SRI와 카카오 SDK의 공식 동작을 기준으로 현재 다시 점검할 때 사용하는 절차다.
단순한 상태 확인 코드는 다음처럼 만들 수 있다.
function assertKakaoSdkReady() {
if (!window.Kakao) {
throw new Error('KAKAO_SDK_NOT_LOADED');
}
if (!window.Kakao.isInitialized()) {
throw new Error('KAKAO_SDK_NOT_INITIALIZED');
}
}이 코드는 SRI 오류를 고치는 코드가 아니다.
로그인 버튼을 누른 뒤 알 수 없는 오류로 끝나는 대신, SDK가 준비되지 않은 경계를 분리하기 위한 방어 로직이다.
integrity를 지우는 방법은 해결로 쓰지 않았다
integrity 속성을 제거하면 브라우저는 해시 불일치를 검사하지 않는다.
그래서 문제가 사라진 것처럼 보일 수 있다.
하지만 이 방법은 CDN 파일이 예상한 바이트인지 확인하는 공급망 방어를 함께 제거한다.
공급망 공격은 애플리케이션이 직접 작성하지 않은 라이브러리나 배포 경로가 변조돼 악성 코드가 들어오는 공격이다.
최종 수정은 검사를 끄는 것이 아니라 같은 버전의 URL과 공식 해시를 다시 맞추는 방식이어야 한다.
SDK 버전을 올릴 때도 src 한 줄만 수정하지 않고 script 태그 전체를 공식 문서와 함께 갱신해야 한다.
자동 업데이트되는 “최신 버전” 주소와 고정된 SRI 해시는 성격이 맞지 않는다.
파일 바이트가 바뀌면 해시도 바뀌기 때문이다.
로그인처럼 중요한 외부 SDK는 버전과 해시를 함께 고정하고, 업데이트 PR에서 실제 로그인을 회귀 테스트하는 편이 낫다.
SDK 업데이트를 배포 절차로 만들었다면 막을 수 있었다
외부 SDK의 버전 변경은 화면 라이브러리 한 줄을 고치는 작은 수정처럼 보인다.
하지만 로그인 진입점에서 실행되는 코드이므로 배포 전에 최소 한 번은 실제 브라우저 검증이 필요하다.
현재 같은 구조를 운영한다면 다음 네 가지를 자동화 또는 체크리스트로 묶는다.
src와integrity가 카카오 공식 다운로드 문서의 같은 버전에서 복사됐는지 리뷰한다.- 테스트 페이지를 열어 SDK 요청 상태와 Console 오류를 확인한다.
window.Kakao와Kakao.isInitialized()를 준비 상태 점검에 포함한다.- 인증 창 열기부터 서비스 세션 생성까지 한 경로를 회귀 테스트한다.
HTML을 정적으로 분석해 URL 버전과 해시가 의미상 같은 쌍인지 계산하려면 실제 CDN 파일을 받아 해시를 검증해야 한다.
단순 문자열 검사만으로는 충분하지 않다.
CI에서 외부 CDN에 의존하는 검증은 일시적인 네트워크 실패도 다뤄야 하므로, 배포 차단 검사와 주기적인 공급망 검사를 분리하는 선택도 가능하다.
SDK 파일을 서비스 서버에 직접 복사해 제공하는 방식도 떠올릴 수 있다.
이 경우 CDN 장애와 교차 출처 설정은 줄지만 업데이트와 라이선스, 보안 패치를 직접 관리하게 된다.
카카오가 안내하는 배포 경로와 약관을 확인하지 않은 채 파일을 복사하는 것을 기본 해법으로 삼지는 않았다.
이번 사례에서는 공식 CDN의 버전 고정 URL과 공식 SRI 값을 한 쌍으로 유지하는 편이 가장 작은 수정이었다.
고친 뒤에는 로그인 전체를 다시 지나가야 한다
문제는 SDK 로드 단계에 있었지만 검증을 SDK 객체 생성에서 끝내면 안 된다.
해시가 맞아 스크립트가 실행돼도 JavaScript 키, 플랫폼 도메인이나 redirect 설정이 틀리면 로그인은 여전히 실패할 수 있다.
같은 문제를 고친 뒤에는 다음 경계를 차례로 확인해야 한다.
- SDK 파일을 브라우저가 차단하지 않는가.
- SDK 초기화가 한 번만 완료되는가.
- 로그인 버튼이 인증 창을 정상적으로 여는가.
- 인증 결과를 받아 처리하는 callback 단계가 기존 서버 인증 흐름으로 이어지는가.
- 실패하거나 창을 닫았을 때 로딩 상태가 풀리는가.
업무는 2025년 12월 28일 완료됐고 관련 Git 변경이 두 건 이상 확인됐다.
장애 시간과 영향 사용자 수는 기록에 없어 복구율이나 영향을 추정하지 않았다.
이번 문제에서 오래 걸릴 수 있었던 부분은 카카오 인증 로직이 아니었다.
로그인 코드가 실행되기 전에 브라우저가 외부 파일을 검증하는 경계를 먼저 봤기 때문에 원인을 좁힐 수 있었다.
외부 SDK가 멈췄을 때는 API 키부터 바꾸기 전에 파일이 내려왔는지, 실행됐는지와 초기화됐는지를 나눠 확인해야 한다.
이번에는 버전과 해시를 한 쌍으로 되돌리는 것으로 기존 로그인 경로를 정상화했다.