파이썬 requests SSL 인증서 오류, verify=False 없이 원인부터 구분하는 법

브라우저에서는 열리는데 Python 자동화에서 CERTIFICATE_VERIFY_FAILED가 발생하면 패키지를 다시 설치하거나 verify=False부터 넣기 쉽습니다. 핵심은 verify=False로 우회하는 것이 아니라, 오류 메시지와 실행 환경을 확인한 뒤 신뢰할 CA 번들을 verify 또는 REQUESTS_CA_BUNDLE로 지정하는 것입니다. 다만 호스트명 불일치라면 CA 경로를 바꿔도 해결되지 않습니다.

먼저 오류를 세 가지로 나눠 보세요

requests는 HTTPS 서버 인증서의 신뢰성과 호스트명을 검증합니다. 따라서 같은 예외 이름이라도 다음 계층을 나눠야 합니다.

  • unable to get local issuer certificate처럼 보이면 인증서 체인의 발급자를 실행 환경이 신뢰하지 못하는 경우를 먼저 봅니다. 사내 프록시가 TLS를 중간에서 검사하거나 자체 CA를 사용하는 환경도 여기에 포함될 수 있습니다.
  • hostname mismatch라면 접속한 호스트명과 서버 인증서의 이름이 맞지 않는 문제입니다. 올바른 URL인지, 프록시가 다른 인증서를 내놓는지 확인해야 합니다.
  • CERTIFICATE_VERIFY_FAILED만 보이면 예외의 verify_message와 verify_code를 출력해 더 구체적인 단서를 확인합니다. Python의 SSLCertVerificationError는 이 두 정보를 제공합니다.
import requests

try:
    response = requests.get("https://example.com", timeout=10)
    response.raise_for_status()
except requests.exceptions.SSLError as exc:
    print(type(exc).__name__, exc)
    cause = exc.__cause__
    if cause is not None:
        print(getattr(cause, "verify_code", None))
        print(getattr(cause, "verify_message", None))

이 코드는 원인을 판별하기 위한 로그 예시입니다. 실제 운영 로그에는 토큰이나 응답 본문을 함께 남기지 않는 편이 안전합니다.

CA 번들 경로를 확인하고 verify에 지정하기

공개 인증기관으로 발급된 사이트인데도 로컬 환경의 CA 경로가 맞지 않는다면, 먼저 현재 CA 번들의 위치를 확인할 수 있습니다.

import certifi
import requests

ca_bundle = certifi.where()
response = requests.get(
    "https://example.com",
    verify=ca_bundle,
    timeout=10,
)

certifi.where()는 설치된 Certifi 번들의 경로를 반환합니다. 이 방법은 공개 루트 CA로 검증되는 연결에서 기준 경로를 명시할 때 유용합니다. 반대로 사내 프록시나 자체 CA가 원인이라면 해당 환경에서 공식적으로 배포한 CA 번들을 받아야 하며, 임의의 인증서를 내려받아 추가해서는 안 됩니다.

여러 요청에 같은 경로를 적용해야 한다면 환경변수를 사용할 수 있습니다.

export REQUESTS_CA_BUNDLE="/경로/회사에서_배포한_ca_bundle.pem"

이 변수는 실행 프로세스의 requests 요청에 영향을 주므로, 운영 작업에서는 배포 설정과 로그에 어떤 CA 파일을 사용했는지 남겨 두는 것이 좋습니다. verify는 서버 인증서 검증용이고, 클라이언트 인증서를 보내는 cert와는 역할이 다릅니다.

verify=False가 해결책이 아닌 이유

verify=False는 서버 인증서와 호스트명 검증을 허용하지 않습니다. 개발 중 원인을 좁히는 임시 진단에 쓰더라도, 자동화 코드의 정상 경로에 남기면 중간자 공격을 탐지할 수 없습니다. 경고를 숨기는 설정 역시 인증서 문제를 고친 것이 아닙니다.

운영 관점에서는 다음 순서가 안전합니다.

  1. 예외의 verify_message와 verify_code, 요청 URL, 프록시 사용 여부를 확인합니다.
  2. 호스트명 불일치인지 CA 체인 문제인지 구분합니다.
  3. 신뢰할 수 있는 CA 번들의 실제 경로를 verify 또는 REQUESTS_CA_BUNDLE에 지정합니다.
  4. 같은 환경에서 다시 요청하고, 재발 방지를 위해 CA 경로와 실행 환경을 설정으로 관리합니다.

이 글의 범위를 넘어 운영체제의 신뢰 저장소를 설치·수정하는 방법은 환경마다 달라 별도 절차로 다뤄야 합니다. requests의 CA와 프록시를 함께 점검하는 더 좁은 사례는 파이썬 requests SSL 인증서 오류: verify=False 없이 CA와 프록시 점검하는 법에서 이어서 확인할 수 있습니다.

결국 판단 기준은 간단합니다. 호스트명이 틀렸다면 URL이나 프록시 구성을 고치고, 신뢰할 CA가 없다면 검증된 CA 번들을 지정합니다. 둘 중 어느 쪽인지 모르는 상태에서 verify=False로 넘어가는 것은 오류를 해결한 것이 아니라 검증을 없앤 것입니다.

Leave a Comment