[python] urllib 및 “SSL : CERTIFICATE_VERIFY_FAILED”오류

다음과 같은 오류가 발생합니다.

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        __bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in  run
self.__target(*self.__args, **self.__kwargs)
File "/Users/Matthew/Desktop/Skypebot 2.0/bot.py", line 271, in process
info = urllib2.urlopen(req).read()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 431, in open
response = self._open(req, data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 449, in _open
'_open', req)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 409, in _call_chain
result = func(*args)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1240, in https_open
context=self._context)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1197, in do_open
raise URLError(err)
URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)>

이 오류를 일으키는 코드입니다.

if input.startswith("!web"):
    input = input.replace("!web ", "")      
    url = "https://domainsearch.p.mashape.com/index.php?name=" + input
    req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXX' })
    info = urllib2.urlopen(req).read()
    Message.Chat.SendMessage ("" + info)

내가 사용하는 API는 HTTPS를 사용해야합니다. 확인을 우회하도록하려면 어떻게해야합니까?



답변

당신이 경우 단지 바이 패스 검증하려는 새 만들 수 의 SSLContext를 . 기본적으로 새로 작성된 컨텍스트는 CERT_NONE을 사용 합니다 .

섹션 17.3.7.2.1에 명시된대로주의하십시오.

SSLContext 생성자를 직접 호출 할 때 CERT_NONE이 기본값입니다. 다른 피어를 인증하지 않으므로 특히 대화하는 서버의 신뢰성을 보장하려는 대부분의 클라이언트 모드에서는 안전하지 않을 수 있습니다. 따라서 클라이언트 모드에서는 CERT_REQUIRED를 사용하는 것이 좋습니다.

그러나 다른 이유로 지금 작동하게하려면 다음을 수행해야합니다 import ssl.

input = input.replace("!web ", "")
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })
gcontext = ssl.SSLContext()  # Only for gangstars
info = urllib2.urlopen(req, context=gcontext).read()
Message.Chat.SendMessage ("" + info)

이것은 문제를 해결해야하지만 실제로 문제를 해결하지는 못하지만 [SSL: CERTIFICATE_VERIFY_FAILED]인증서를 확인하지 않았기 때문에 표시 되지 않습니다!

위의 내용을 추가하기 위해 이러한 문제가 발생하는 이유에 대해 더 알고 싶다면 PEP 476을 살펴보십시오 .

이 PEP는 기본적으로 Python의 HTTP 클라이언트에 대한 호스트 이름 확인뿐만 아니라 X509 인증서 서명의 검증을 활성화하여 호출별로 옵트 아웃하도록 제안합니다. 이 변경 사항은 Python 2.7, Python 3.4 및 Python 3.5에 적용됩니다.

위의 조언과 다르지 않은 조언이 있습니다.

import ssl

# This restores the same behavior as before.
context = ssl._create_unverified_context()
urllib.urlopen("https://no-valid-cert", context=context)

또한 파이썬에서 자주 볼 수없는 원숭이 패치 를 통해 매우 낙담 한 옵션을 제공합니다.

import ssl

ssl._create_default_https_context = ssl._create_unverified_context

확인되지 않은 컨텍스트를 작성하는 기능으로 컨텍스트 작성의 기본 기능을 대체합니다.

PEP에 명시된대로이 점에 유의하십시오.

이 지침은 주로 HTTPS 연결에서 인증서 확인을 지원하지 않는 레거시 환경에서이 PEP를 구현하는 최신 버전의 Python을 채택하려는 시스템 관리자를 대상으로합니다. 예를 들어, 관리자는 Python의 표준 운영 환경에서 위의 monkeypatch를 sitecustomize.py에 추가하여 옵트 아웃 할 수 있습니다. 응용 프로그램과 라이브러리는이 변경 프로세스를 광범위하게 만들어서는 안됩니다 (시스템 관리자 제어 구성 설정에 대한 응답을 제외하고).

소프트웨어에서 인증서 확인이 나쁜 이유에 대한 논문을 읽으려면 여기에서 찾을 수 있습니다 !


답변

이것은 귀하의 특정 문제에 대한 해결책은 아니지만이 스레드가 “SSL : CERTIFICATE_VERIFY_FAILED”에 대한 Google의 최고 결과이므로 여기에 두겠습니다.

OSX에 Python 3.6을 설치하고 https : // 사이트에 연결하려고 할 때 “SSL : CERTIFICATE_VERIFY_FAILED”오류가 발생하는 경우 OSX의 Python 3.6에는 인증서가 전혀없고 SSL을 확인할 수 없기 때문일 수 있습니다. 사이. 이는 OSX에서 3.6에 대한 변경 certifi이며 인증서 패키지 를 설치하는 설치 후 단계가 필요합니다 . 이것은 ReadMe에 문서화되어 있습니다./Applications/Python\ 3.6/ReadMe.rtf

ReadMe는이 설치 후 스크립트를 실행할 것입니다 certifi./Applications/Python\ 3.6/Install\ Certificates.command

릴리스 정보에는 https://www.python.org/downloads/release/python-360/에 대한 추가 정보가 있습니다.


답변

Craig Glennie의 답변을 확장하려면 :

MacOs Sierra의 Python 3.6.1

bash 터미널에 이것을 입력하면 문제가 해결되었습니다.

pip install certifi
/Applications/Python\ 3.6/Install\ Certificates.command


답변

Windows에서 Python은 시스템 인증서를 보지 않고에있는 자체 인증서를 사용합니다 ?\lib\site-packages\certifi\cacert.pem.

문제에 대한 해결책 :

  1. 도메인 확인 인증서를 * .crt 또는 * pem 파일로 다운로드
  2. 편집기에서 파일을 열고 내용을 클립 보드에 복사
  3. 당신의 cacert.pem위치를 찾으십시오 :from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)
  4. cacert.pem파일을 편집하고 파일 끝에 도메인 유효성 검사 인증서를 붙여 넣습니다.
  5. 파일을 저장하고 요청을 즐기십시오!

답변

Mac OS X에 대한 내 솔루션 :

1) 공식 Python 언어 웹 사이트 https://www.python.org/downloads/ 에서 다운로드 한 기본 앱 Python 설치 프로그램을 사용하여 Python 3.6.5로 업그레이드

이 설치 프로그램이 homebrew보다 새로운 Python의 링크 및 심볼릭 링크를 훨씬 더 잘 관리하고 있음을 발견했습니다.

2) 새로 고친 Python 3.6 디렉토리에있는 “./Install Certificates.command”를 사용하여 새 인증서를 설치하십시오.

> cd "/Applications/Python 3.6/"
> sudo "./Install Certificates.command"


답변

이것을 환경 변수에 추가해 볼 수 있습니다.

PYTHONHTTPSVERIFY=0 

이렇게하면 모든 HTTP 확인 이 비활성화 되므로 약간의 쇠약 한 접근 방식이지만 확인이 필요하지 않은 경우 효과적인 솔루션 일 수 있습니다.


답변

Python 3.4, 3.5 및 3.6urllib.request.urlopen 에서 사용하고 있었지만 비슷한 문제가 발생했습니다 . (이것은 Python 2의 문서 페이지 헤드에있는 메모에 따라 Python 3에 해당하는 부분입니다 .)urllib2urllib2

내 솔루션은 pip install certifi설치 certifi하는 것이 었습니다 .

… TLS 호스트의 신원을 확인하면서 SSL 인증서의 신뢰성을 검증하기 위해 신중하게 선별 된 루트 인증서 모음입니다.

그런 다음 이전에 방금했던 코드에서 :

import urllib.request as urlrq

resp = urlrq.urlopen('https://example.com/bar/baz.html')

나는 그것을 다음과 같이 수정했다.

import urllib.request as urlrq
import certifi

resp = urlrq.urlopen('https://example.com/bar/baz.html', cafile=certifi.where())

urllib2.urlopen설명서를 올바르게 읽으면 cafile인수도 있습니다. 따라서 urllib2.urlopen([...], certifi.where())Python 2.7에서도 작동 할 수 있습니다.


UPDATE (2020년 1월 1일) : 파이썬 3.6의 바와 같이, 에 인수가 사용되지 않습니다 로, 가정 인수 대신 지정해야합니다. 3.5에서 3.8까지 다음과 같이 잘 작동한다는 것을 알았습니다.cafileurlopencontext

import urllib.request as urlrq
import certifi
import ssl

resp = urlrq.urlopen('https://example.com/bar/baz.html', context=ssl.create_default_context(cafile=certifi.where()))