“연결이 비공개로 설정되어 있지 않습니다”: SSL 인증서 경고
· 읽는 데 2분
오류의 의미
브라우저가 서버에 연결했고, 서버가 인증서를 제시했으며, 브라우저가 이를 신뢰하기를 거부했습니다. Chrome은 아래에 오류 코드와 함께 “연결이 비공개로 설정되어 있지 않습니다”를, Firefox는 “경고: 잠재적인 보안 위험이 있습니다”를, Safari는 “이 연결은 비공개로 설정되어 있지 않습니다”를 표시합니다. 사이트가 해킹된 것도, 컴퓨터가 감염된 것도 아닙니다. 서버가 보낸 인증서가 브라우저가 수행하는 검사를 통과하지 못한 것입니다.
오류 코드는 어떤 검사가 실패했는지 알려 줍니다.
NET::ERR_CERT_DATE_INVALID: 인증서가 만료되었거나 시작일이 미래입니다(또는 방문자의 시계가 잘못되었습니다).NET::ERR_CERT_COMMON_NAME_INVALID: 인증서가 다른 이름용입니다. 예를 들어www.example.com용이지만example.com용은 아닙니다.NET::ERR_CERT_AUTHORITY_INVALID: 브라우저가 인증서를 신뢰할 수 있는 인증 기관까지 추적할 수 없습니다. 자체 서명, 알 수 없는 발급자, 또는 누락된 중간 인증서입니다.NET::ERR_CERT_REVOKED: 발급자가 인증서를 폐기했습니다.SSL_ERROR_BAD_CERT_DOMAIN과SEC_ERROR_EXPIRED_CERTIFICATE는 이름 오류와 날짜 오류에 대한 Firefox의 표시입니다.
흔한 원인
- 인증서가 만료되었습니다. Let's Encrypt 인증서는 90일 동안 유효합니다. 자동 갱신이 몇 주 동안 실패했는데 만료되는 날까지 아무도 알아차리지 못했습니다. 유료 인증서는 1년 후 만료되며 갱신 안내 메일이 예전 주소로 갔습니다.
- 갱신했지만 다시 불러오지 않았습니다. certbot이 새 인증서를 디스크에 기록했지만, 다시 불러오는 훅이 없어서 웹 서버가 메모리에 있는 예전 인증서를 계속 제공합니다.
- 잘못된 이름. 인증서가
example.com을 포함하지만 방문자는www.example.com으로 접속하거나, 인증서 없이 새 서브도메인이 추가되었습니다. - 누락된 중간 인증서. 서버가 체인 없이 자신의 인증서만 보냅니다. 데스크톱 브라우저는 캐시로 빈틈을 메우는 경우가 많지만, 휴대폰과 앱은 실패합니다.
- 시계 문제. 방문자의 컴퓨터에서는 잘못된 날짜가 모든 인증서를 만료되었거나 아직 유효하지 않은 것처럼 보이게 합니다. 서버에서는 잘못된 시계가 갱신을 망가뜨립니다.
- 앞단의 CDN이나 프록시가 자체 인증서를 사용하는데 그 인증서가 만료되었거나 이름을 포함하지 않으며, 원본 서버는 정상인 경우입니다.
방문자인 경우
먼저 컴퓨터의 날짜와 시간을 확인하세요. CMOS 배터리가 죽었거나 시간 동기화가 꺼져 있으면 모든 사이트가 실패합니다. 그런 다음 다른 네트워크를 시도하세요. 경고가 한 사이트에서만, 그리고 모든 기기에서 나타난다면 사이트의 인증서가 문제이며 소유자가 해결해야 합니다. 아는 사이트라면 “안전하지 않음으로 이동”을 클릭해도 괜찮지만, 로그인이나 결제가 있는 곳에서는 안 됩니다.
직접 운영하는 사이트라면: 먼저 확인할 것
SSL 검사 도구를 실행하세요. 브라우저 캐시 없이 외부에서 만료일, 인증서가 유효한 이름, 체인이 완전한지 보여 줍니다. 그런 다음 직접 운영하는 서버에서:
# 서버가 실제로 무엇을 보내는가?
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -subject -ext subjectAltName
# 디스크에는 무엇이 있는가?
sudo certbot certificates
# 서버 시계가 맞는가?
timedatectl
디스크의 날짜가 서버가 보내는 날짜보다 최신이라면 2번의 경우입니다. 갱신했지만 다시 불러오지 않은 것입니다.
직접 운영하는 서버에서의 해결 방법
1. certbot으로 갱신
sudo certbot renew
# 또는 renew가 "not yet due"라고 하지만 제공 중인 인증서가 오래된 경우:
sudo certbot renew --force-renewal
sudo systemctl reload nginx # 또는 apache2
갱신에 실패하면 출력에 이유가 나옵니다. 흔한 이유는 80 포트가 차단되었거나 certbot이 예상하지 못한 곳으로 리디렉션되는 경우(HTTP-01 챌린지는 /.well-known/acme-challenge/에 일반 HTTP로 접근할 수 있어야 합니다), DNS 레코드가 다른 서버를 가리키는 경우, 또는 여러 번 실패한 후 요청 속도 제한에 걸린 경우입니다. 원인을 해결하고 sudo certbot renew --dry-run이 통과할 때까지 실행하세요.
2. 다시 불러오기 자동화
# Debian/Ubuntu: certbot이 타이머를 설치하므로 확인
systemctl list-timers | grep certbot
# 웹 서버가 새 인증서를 가져가도록 배포 훅 추가
printf '#!/bin/sh\nsystemctl reload nginx\n' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-web.sh
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-web.sh
3. 누락된 이름 추가
sudo certbot --nginx -d example.com -d www.example.com -d shop.example.com --expand
--expand 플래그는 기존 인증서를 나열된 모든 이름을 포함하는 인증서로 교체합니다.
4. 체인 수정
certbot을 사용한다면 웹 서버가 cert.pem이 아니라 항상 fullchain.pem을 가리키게 하세요.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
Apache: SSLCertificateFile에 fullchain.pem. 구매한 인증서라면 발급자에게서 중간 인증서(“CA 번들”)를 내려받아 인증서 파일에 덧붙이세요. sudo nginx -t(Apache: sudo apachectl configtest)로 테스트하고, 다시 불러온 후 SSL 검사 도구로 체인을 확인하세요.
5. 시계 수정
sudo timedatectl set-ntp true
timedatectl
시계가 몇 분 이상 어긋난 서버는 양방향 모두에서 인증서 검증에 실패합니다.
6. 공유 호스팅 또는 사이트 빌더
대부분의 호스팅 업체는 제어판(“SSL/TLS”, “보안”, “Let's Encrypt”)에서 Let's Encrypt 인증서를 발급하고 갱신합니다. 제어판을 열어 인증서가 example.com과 www.example.com을 모두 포함하는지 확인하고 갱신 또는 재발급을 클릭하세요. 제어판에는 인증서가 유효하다고 나오는데 브라우저가 동의하지 않는다면, 호스팅 업체 쪽에 다시 불러오기 또는 체인 문제가 있는 것입니다.
호스팅 업체의 문제인 경우
안녕하세요. 약 06:00 UTC부터 제 웹사이트 example.com에서 브라우저가 “연결이 비공개로 설정되어 있지 않습니다”(NET::ERR_CERT_DATE_INVALID)를 표시합니다. 제어판에는 유효한 인증서가 표시되므로 웹 서버가 예전 인증서를 제공하고 있는 것으로 보입니다. 서버에서 인증서를 다시 불러오고 제 도메인의 자동 갱신을 확인해 주시겠습니까?
다음번을 막으려면
만료된 인증서는 날짜를 미리 알 수 있는 유일한 장애입니다. SSL 인증서 모니터링은 만료 전에 경고하고, 체인이나 이름이 잘못되었을 때도 다시 경고합니다. 5개의 확인은 무료입니다. 직접 운영하는 서버에서는 Quick Fix가 certbot이 설정된 곳의 인증서를 갱신하고 웹 서버를 다시 불러오며 고정 가격입니다. 아직 갱신이 없는 곳에는 Deep Fix가 갱신을 설정합니다.