TechFeedTechFeed
Security

혼합 콘텐츠, Mixed Content, HTTPS | 자물쇠 페이지에서 요청만 막히면?

혼합 콘텐츠는 HTTPS 페이지의 HTTP 요청을 브라우저가 막는 줄입니다. 콘솔의 http 주소를 https로 바꾸고, 그림 업그레이드와 스크립트 차단을 나눕니다. 프리뷰에서만 카카오 스크립트가 죽는 자리와 CORS를 가릅니다. IP 호스트 이미지는 올라가지 않습니다. 보안, 버셀, 브라우저. 2026년 8월 MDN 기준.

by

혼합 콘텐츠는 HTTPS 페이지가 HTTP 주소를 불러 브라우저가 막거나, 그림과 영상과 소리만 HTTPS로 올려 치는 상황입니다. 콘솔의 Mixed Content 한 줄에서 http:// 주소를 찾아 HTTPS로 바꾸세요.


로컬 개발 서버는 http라 조용한데, 버셀 프리뷰에서만 로그인 스크립트가 실패하면 이 칸인 경우가 많습니다. 카카오 스크립트를 http로 두면 배포 페이지에서만 거절됩니다.


CORS는 다른 출처의 응답 헤더 문제이고, 혼합 콘텐츠는 페이지가 https인데 자원만 http인 짝입니다. MDN은 2026-08-15 문서에서 스크립트는 막고, 그림은 도메인이면 HTTPS로 올린다고 적습니다.


자물쇠 페이지가 http를 거절한다

페이지가 HTTPS이면, 그 안의 HTTP 요청은 이미 의심 대상입니다.


자물쇠는 그 문서가 변조되지 않았다는 표시인데, 문서 안 스크립트나 XHR이 평문 HTTP로 나가면 중간에서 바꿀 수 있습니다. 브라우저는 그래서 혼합을 줄입니다. MDN은 사이트가 혼합 콘텐츠와 혼합 다운로드를 피해야 한다고 적고, 브라우저는 그림, 영상, 소리의 HTTP를 HTTPS로 자동 업그레이드하고 그 밖의 자원은 막으며, 혼합 다운로드도 기본으로 막아야 한다고 설명합니다.


콘솔 문장에는 페이지 URL과 막힌 자원 URL이 같이 나옵니다. 자원 쪽이 http://이면 이번 칸입니다. 네트워크 탭의 스킴 열만 내려도 같은 목록이 나옵니다. 서버 로그에 요청이 없으면, 브라우저가 보내기 전에 자른 것입니다.


서버 랙 캐비닛의 자물쇠. HTTPS 페이지가 HTTP 요청을 막는 혼합 콘텐츠를 떠올리게 하는 사진
페이지 자물쇠가 HTTPS인데 자원만 HTTP이면 브라우저가 그 요청을 자른다

올려 주는 자원과 막는 자원

그림이라고 전부 올라가는 것은 아닙니다. IP 호스트는 막힙니다.


자원요즘 브라우저예
그림, 영상, 소리 (도메인)HTTP를 HTTPS로 올려 요청img src가 http인 CDN 도메인
같은 미디어인데 호스트가 IP업그레이드하지 않고 차단http://203.0.113.10/a.png
스크립트, 스타일, fetch, XHR, 폰트, 워커차단카카오 스크립트, API fetch
파일 다운로드혼합 다운로드는 기본 차단 대상http로 붙은 첨부

예전 스펙은 능동 혼합(스크립트, 스타일)을 반드시 막고, 표시용 혼합은 선택으로 뒀습니다. 2026년 MDN 본문은 그 둘을 업그레이드 대상과 차단 대상으로 다시 적습니다. 사파리는 혼합을 넓게 거절하는 쪽으로 알려져 있어, 크롬에서 그림이 떠도 사파리 검수는 따로 해야 합니다. HTTPS로 올린 주소에 파일이 없으면 HTTP로 되돌아가지 않고 그 요청은 실패합니다.


프리뷰에서 로컬 API를 부르는 자리

https 프리뷰가 http://localhost를 부르면 배포에서만 막힙니다.


개발 서버 페이지가 http://localhost:3000이면 그 문서 자체는 보안 문맥이 아니라서 혼합 규칙이 느슨합니다. 같은 코드를 버셀 프리뷰의 https:// 도메인에 올리면, http://localhost:4000이나 http://로 박힌 API는 혼합이 됩니다. 환경 변수에 스킴까지 넣고, 프리뷰 값만 https 공개 주소로 바꿉니다. 로컬용 http 기본값을 프로덕션 번들에 남기지 마세요.


한국 서비스에서 자주 남는 하드코딩은 카카오 SDK, 지도 타일, 예전에 http로 받던 이미지 호스트입니다. 페이지는 200인데 버튼만 죽은 화면이면 네트워크에서 막힌 스크립트 이름을 먼저 보세요. 인증서 오류(UNABLE_TO_VERIFY_LEAF_SIGNATURE)는 서버가 HTTPS로 나갔는데 노드가 인증서를 못 믿는 줄이라, 브라우저가 http를 자른 이번 칸과 다릅니다.


스킴을 환경에 두고 http를 남기지 않기
// 프리뷰와 프로덕션 값은 https로 시작해야 한다 const api = process.env.NEXT_PUBLIC_API_BASE; // 나쁜 예: https 페이지에서 http 절대 경로 // fetch('http://api.example.com/orders') fetch(api + '/orders');

upgrade-insecure-requests의 한계

이 지시문은 주소를 올려 치울 뿐, 없는 HTTPS를 만들어 주지 않습니다.


MDN의 Content-Security-Policy: upgrade-insecure-requests는 사이트의 안전하지 않은 URL을 HTTPS로 바꿔 요청하라고 브라우저에 알립니다. 메타 태그로도 같은 내용을 넣을 수 있습니다. 탐색이 아닌 자원 요청은 네트워크에 나가기 전에 스킴이 바뀝니다. 대상 호스트가 443을 안 열면 실패만 남고 HTTP 폴백은 없습니다.


이 지시문은 다른 사이트에 걸린 링크로 들어온 최상위 이동까지 HTTPS로 보장하지 않습니다. MDN은 그래서 HSTS를 대신할 수 없고, max-age가 있는 Strict-Transport-Security를 따로 두라고 합니다. 예전 block-all-mixed-content에만 기대던 설정도 지금 문서의 업그레이드와 차단 구분으로 다시 읽어야 합니다. 소스의 http를 지우는 작업이 먼저이고, CSP는 남은 주소를 올리는 보조입니다.


남은 http를 https로 올리되 HSTS는 별도
Content-Security-Policy: upgrade-insecure-requests Strict-Transport-Security: max-age=31536000
어두운 모니터 앞 책상. HTTPS 페이지에서 막힌 HTTP 요청을 콘솔로 찾는 장면
콘솔에 찍힌 http 주소만 골라 https로 바꾸면 혼합 한 줄은 사라진다

콘솔에서 주소만 골라 고치기

고칠 목록은 콘솔에 이미 적혀 있습니다.


보안 패널이나 콘솔의 혼합 경고를 위에서부터 적습니다. 각 줄의 자원 URL을 소스에서 찾습니다. 내 코드의 문자열이면 https로 바꿉니다. HTML을 내려 주는 CMS나 마크다운에 http://가 남아 있으면 저장 값을 고칩니다. 상대 경로(/api/orders)는 페이지 스킴을 따라가므로 혼합이 아닙니다. 프로토콜 상대(//cdn.example.com/a.js)는 페이지가 https면 https로 나가니, 그 호스트가 443을 여는지 따로 확인합니다.


프록시로 같은 출처의 https 경로에 외부 HTTP를 숨기는 방법은, 서버가 그 평문을 대신 받으므로 브라우저 혼합은 피합니다. 대신 서버가 사설망이나 메타데이터 주소를 따라가지 않게 호스트를 제한해야 합니다. 공개 페이지만 자물쇠를 맞추면 되는 경우에는 소스의 스킴 교체가 더 짧습니다. 한국 결제 화면처럼 스크립트가 하나라도 빠지면 버튼이 죽으니, 프리뷰 콘솔을 배포 체크에 넣으세요.


CORS 헤더로 이 경고가 풀리지 않음 | Access-Control-Allow-Origin은 다른 출처의 HTTPS 응답에 붙는 헤더입니다. 브라우저가 http 요청을 보내기 전에 자른 혼합에는 서버 헤더가 도착하지 않습니다.


  • [ ] 페이지가 https인지, 막힌 자원이 http인지 콘솔에서 읽었다
  • [ ] 스크립트와 fetch, 그림과 영상을 표대로 나눴다
  • [ ] IP 호스트 미디어는 업그레이드되지 않는다는 점을 확인했다
  • [ ] 프리뷰 환경 변수의 스킴을 https로 바꿨다
  • [ ] CSP 업그레이드만 켜고 소스의 http를 남기지 않았다

참고 자료


내부 연계: CORS 프리플라이트, 인증서 리프 검증, 리다이렉트 루프


브라우저 동작은 2026년 9월 MDN 공개 문서 기준입니다.


자주 묻는 질문

로컬은 되는데 프리뷰만 스크립트가 죽어요.

로컬 페이지가 http이고 프리뷰만 https이면 혼합은 프리뷰에서만 켜집니다. 콘솔의 막힌 URL이 http인지 보고, 그 주소를 https 환경 변수로 바꾸세요. 로컬에서 새로고침만 해서는 프리뷰 스킴이 재현되지 않습니다.


이미지는 나오는데 fetch만 실패해요.

도메인 그림은 HTTPS로 올라가고, fetch 같은 요청은 차단 대상입니다. 그림이 보인다고 API가 허용된 것은 아닙니다. 네트워크에서 막힌 fetch의 스킴을 따로 보세요.


IP로 건 이미지가 안 떠요.

MDN은 호스트가 IP이면 업그레이드하지 않고 막는다고 적습니다. 도메인으로 HTTPS를 열거나, 페이지와 같은 https 출처로 프록시하세요. http IP를 그대로 두면 크롬에서도 빈 칸이 됩니다.


CSP만 켜면 소스의 http는 둬도 되나요?

브라우저가 요청 전에 https로 바꿉니다. 그 호스트에 인증서가 없으면 실패하고 http로 돌아가지 않습니다. 소스에서 스킴을 고치는 편이 로그가 짧고, HSTS는 최상위 이동용으로 따로 둡니다.


CORS랑 같이 떠요.

스킴을 https로 맞춘 뒤에 출처가 아직 다르면 CORS가 남습니다. 혼합을 먼저 없애야 프리플라이트가 서버에 도착합니다. 헤더만 추가하고 http를 남기면 요청이 나가지 않습니다.


카카오 스크립트만 프리뷰에서 안 붙어요.

스크립트 주소가 http로 박혀 있으면 https 페이지가 차단합니다. 공식 SDK 주소를 https로 두고, 콘솔에 그 파일명이 막힘으로 찍히는지 확인하세요. 리다이렉트 URI 불일치와는 로그 문장이 다릅니다.


혼합 콘텐츠는 HTTPS 페이지 안의 HTTP 자원입니다. 콘솔의 http 주소를 https로 바꾸고, 그림 업그레이드와 스크립트 차단을 같은 약으로 보지 않으면 됩니다. 관련 글: CORS, 인증서 검증, 리다이렉트 루프.


혼합 콘텐츠Mixed ContentHTTPSHTTPCSP브라우저카카오버셀보안개발자

함께 보면 좋은 문제 해결

EXPLORE / Security

이어서 읽어보기

전체 토픽 둘러보기 →