본문 바로가기
프로그래밍 언어/Python

[Python/Flask] self-signed certificate verify failed 에러 해결하기

by Kallunar 2023. 12. 3.

https 구현해보려고
OpenSSL로 인증서를 하나 생성해서
nginx 웹서버에 적용시켰더니
Flask 앱서버에서 다음과 같이 URLError가 발생했다

 

대충 보아하니 Flask 서버 입장에서
자신이 모르는 인증서이기 때문에
믿을 수 없다는 이유로 해당 인증서를 거부한 것 같은데

 

 

urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error

I am getting the following error: Exception in thread Thread-3: Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in...

stackoverflow.com

stackoverflow에서 찾아보니
MacOS라면 Certificates.command 파일로
간단하게 해결할 수 있는 것 같지만

다른 OS는 그딴게 없으므로
직접 내 인증서를 등록해줘야 하는 것으로 보인다

pip install certifi

그런데 그에 앞서
certifi 모듈이 제대로 없어서
에러가 발생하기도 하는 것 같으니
일단 설치해 보고
여전히 이상이 있다면 인증서 등록으로 넘어간다

파이썬의 certifi 폴더 안에 있는 cacert.pem 파일에
각종 인증서 정보가 들어있는데
여기에 나의 인증서 내용을 복붙하여 추가한다

cacert.pem 파일은 어디있나 찾아보니
리눅스 기준

/usr/local/lib/python3.10/site-packages/certifi

여기에 들어있었다
docker container에서 돌리기 때문에
여기서 찾을 수 있었고

윈도우라면 파이썬 설치 시
기본 경로로 설정했다는 전제 하에

C:\Users\[사용자명]\AppData\Local\Programs\Python\Python[설치된 버전]\Lib\site-packages\certifi

여기에서 찾을 수 있었다

 

이제 cacert.pem 파일을 열고
맨 끝에 내 인증서를 복붙한 뒤 저장한다

그러면 끝인가 했는데
추가만 하는 것으로는 택도 없고

그 후 Flask 서버 구현 파일
(여기서는 app.py)로 와서
cacert.pem 파일로 context를 생성해
urlopen에 파라미터로 줘야 했다

from flask import Flask, render_template, Blueprint, request, redirect
import urllib, json, ssl, certifi

context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_verify_locations(certifi.where())
context.check_hostname = False

...

@bp.route(f'/', methods=['GET'])
@bp.route(f'/index.html', methods=['GET'])
def get_index():
    count_users = 0
    url = f'{endpoint}/users/'
    data = None
    headers = {'Accept': 'application/json'}
    method = 'GET'
    req = urllib.request.Request(url=url,
                                 data=data,
                                 headers=headers,
                                 method=method)
    with urllib.request.urlopen(req, context=context) as f:
        data = json.loads(f.read())
        count_users = len(data)

이렇게 했더니 에러 없이 잘 실행되었다

그런데 알고보니 사실
이건 어차피 서버 내부의 요청이라
기냥 검증 없이 http로 요청해도 무방했다

그런 경우라면
인증서 정보 추가 그딴거 다 필요없고
검증을 우회하는 context를 생성해
urlopen에 파라미터로 넘겨주면 된다

from flask import Flask, render_template, Blueprint, request, redirect
import urllib, json, ssl

context = ssl._create_unverified_context()

...

@bp.route(f'/', methods=['GET'])
@bp.route(f'/index.html', methods=['GET'])
def get_index():
    count_users = 0
    url = f'{endpoint}/users/'
    data = None
    headers = {'Accept': 'application/json'}
    method = 'GET'
    req = urllib.request.Request(url=url,
                                 data=data,
                                 headers=headers,
                                 method=method)
    with urllib.request.urlopen(req, context=context) as f:
        data = json.loads(f.read())
        count_users = len(data)

댓글