OneWebDesk

혼합 콘텐츠(mixed content) 경고 해결

HTTPS 페이지의 혼합 콘텐츠 경고가 생기는 이유와 능동/수동 리소스별 해결 방법.

HTTPS로 잘 서비스되던 페이지인데 주소창 자물쇠가 안 뜨거나 “안전하지 않음”으로 바뀌고, 콘솔에는Mixed Content 경고가 줄줄이 찍힌 적이 있을 겁니다. 이건 인증서가 잘못된 게 아니라,HTTPS 페이지가 내부적으로 HTTP 리소스를 불러오고 있다는 신호입니다. 페이지 본문은 암호화돼 있는데 그 안의 이미지·스크립트·CSS 일부가 평문 HTTP로 전송되면, 브라우저는 그 페이지를 더 이상 “완전히 안전”하다고 보지 않습니다.

이 문제를 “혼합 콘텐츠(mixed content)”라고 부릅니다. 방치하면 자물쇠가 사라지는 미관 문제로 끝나지 않습니다. 능동적 혼합 콘텐츠는 최신 브라우저에서 아예 차단되어 스크립트나 스타일이 적용되지 않고, 결과적으로 레이아웃이 깨지거나 기능이 죽습니다. 이 가이드는 혼합 콘텐츠가 정확히 무엇인지, 어디서 새는지 찾는 법, 그리고 유형별 해결책을 실제 예시와 함께 정리합니다.

능동(active) vs 수동(passive) 혼합 콘텐츠

모든 혼합 콘텐츠가 똑같이 취급되지는 않습니다. 브라우저는 그 리소스가 페이지를 얼마나 통제할 수 있는지에 따라 두 부류로 나눕니다. 능동 콘텐츠는 페이지 전체를 조작할 수 있어 곧바로 차단되고,수동 콘텐츠는 표시 영역만 바꿀 수 있어 차단 대신 경고로 표시됩니다.

유형대표 리소스브라우저 동작
능동(active)<script>, <iframe>, <link rel="stylesheet">, fetch()/XHR, 웹폰트차단됨 — 아예 로드되지 않음. 콘솔에 “blocked” 오류.
수동(passive)<img>, <audio>, <video>, <object> 일부로드는 되지만 경고 표시 — 자물쇠가 사라지고 콘솔에 경고.

핵심은 이렇습니다. 자물쇠만 사라졌다면 보통 이미지 같은 수동 리소스가 범인이고, 스타일이 깨지거나 버튼이 동작하지 않는다면 차단된 능동 리소스(CSS·JS)가 범인입니다.

새는 곳 찾기

고치려면 먼저 어떤 HTTP 요청이 페이지에 섞여 있는지 정확히 알아야 합니다. 두 가지를 병행하세요.

  • 브라우저 개발자 도구: F12로 콘솔을 열면 차단·경고된 항목이 전체 URL과 함께 표시됩니다. Network 탭에서 http:// 요청만 필터링해도 한눈에 보입니다.
  • 페이지 전체 스캔: 콘솔은 “지금 화면에 로드된” 것만 보여주므로, 클릭해야 나오는 리소스나 동적으로 주입되는 자원을 놓치기 쉽습니다. 페이지 단위로 한 번에 점검하려면 혼합 콘텐츠 검사로 HTML을 스캔해 HTTP 참조를 빠짐없이 목록화하는 편이 안전합니다.

유형별 해결책

찾았다면 대부분 다음 세 가지로 정리됩니다.

  1. http://https://로 바꾸기 — 가장 기본이자 권장 방법. 해당 리소스가 HTTPS를 지원하는지 먼저 직접 https://로 열어 확인한 뒤 교체하세요.
  2. 프로토콜 상대 경로(//host/asset.js)는 피하기 — 한때 흔하던 방식이지만 이제는 권장하지 않습니다. 모든 사이트가 HTTPS인 지금은 명시적으로 https://를 적는 편이 의도가 분명하고 디버깅도 쉽습니다.
  3. Content-Security-Policy: upgrade-insecure-requests로 일괄 승격 — 본문 HTML을 전부 손볼 수 없을 때 안전망이 됩니다. 이 지시어는 페이지가 요청하는 http:// URL을 브라우저가 요청 직전에 자동으로 https://로 끌어올려 줍니다. 보안 헤더 설정은 보안 헤더 검사로 적용 여부를 확인할 수 있습니다.

실전 예시: HTTPS 페이지의 HTTP 이미지

https://shop.example.com 상품 페이지에 다음 마크업이 있다고 합시다.

  • 문제 코드: <img src="http://cdn.example.com/p/1.jpg">
  • 증상: 이미지는 보이지만 주소창 자물쇠가 사라지고, 콘솔에 Mixed Content: ... was loaded over HTTP 경고.
  • 1차 확인: 브라우저에서 https://cdn.example.com/p/1.jpg를 직접 열어 정상 표시되는지 본다.
  • 정석 수정: <img src="https://cdn.example.com/p/1.jpg">s 하나만 더하면 끝.
  • 대량 대응: 본문 곳곳에 같은 패턴이 흩어져 있으면, 응답 헤더에 Content-Security-Policy: upgrade-insecure-requests를 추가해 한꺼번에 승격.

수정 후에는 강력 새로고침(Ctrl+Shift+R)으로 캐시를 비우고 자물쇠가 정상으로 돌아왔는지, 그리고 다시 혼합 콘텐츠 검사로 남은 HTTP 참조가 0인지 확인하면 마무리됩니다.

자주 묻는 질문

이미지가 보이는데도 왜 '안전하지 않음'이 뜨나요?
이미지(수동 콘텐츠)는 차단되지 않고 로드되지만, HTTP로 받은 순간 페이지가 완전 암호화 상태가 아니게 됩니다. 그래서 콘텐츠는 보여도 자물쇠가 사라지거나 '완전히 안전하지 않음'으로 표시됩니다. src를 https로 바꾸면 해결됩니다.
스크립트나 CSS가 적용이 안 돼요.
스크립트·스타일시트·iframe은 능동 콘텐츠라 HTTP로 불릴 경우 브라우저가 아예 차단합니다. 그래서 로드 자체가 실패해 레이아웃이 깨지거나 기능이 동작하지 않습니다. 콘솔의 'blocked: mixed-content' 오류에 나온 URL을 https로 바꾸세요.
프로토콜 상대 경로 //cdn.example.com/x.js를 써도 되나요?
기술적으로는 동작하지만 더 이상 권장하지 않습니다. 과거 HTTP/HTTPS 혼용 시대의 관행이며, 지금은 모든 사이트가 HTTPS이므로 명시적으로 https://를 적는 것이 의도가 분명하고 로컬 file:// 환경 등에서 생기는 혼란도 없습니다.
upgrade-insecure-requests만 켜면 다 끝나나요?
같은 출처/HTTPS 지원 리소스의 http URL을 자동으로 승격해 주므로 매우 유용한 안전망입니다. 다만 대상 서버가 HTTPS를 지원하지 않으면 승격된 요청이 실패할 수 있으니, 근본적으로는 소스에서 https로 고치고 이 헤더를 추가 방어선으로 함께 쓰는 것이 가장 안전합니다.
고쳤는데도 경고가 계속 남아 있어요.
브라우저·CDN 캐시 때문일 가능성이 큽니다. 강력 새로고침(Ctrl+Shift+R)이나 캐시 비우기를 하고, CDN을 쓴다면 캐시 무효화를 하세요. 그래도 남으면 클릭으로만 나타나는 동적 리소스를 콘솔이 놓쳤을 수 있으니 페이지 전체를 다시 스캔해 보세요.

이 가이드와 함께 쓰면 좋은 도구