запросы Python проверяют сертификат SSL - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь получить данные из API, который защищен SSL.Я написал скрипт на Python для извлечения данных.Предварительно мне нужно преобразовать файл .p12 в сертификат openSSL.Когда я использую следующий код, он работает просто отлично:

# ----- SCRIPT 1 -----
def pfx_to_pem(pfx_path, pfx_password):
    ''' Decrypts the .pfx file to be used with requests. '''
    with tempfile.NamedTemporaryFile(suffix='.pem') as t_pem:
        f_pem = open(t_pem.name, 'wb')
        pfx = open(pfx_path, 'rb').read()
        p12 = OpenSSL.crypto.load_pkcs12(pfx, pfx_password)
        f_pem.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey()))
        f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate()))
        ca = p12.get_ca_certificates()
        if ca is not None:
            for cert in ca:
                f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
        f_pem.close()
        yield t_pem.name

# read some config
with open('config.json') as config_json:
    config = json.load(config_json)
    api_url = config['api_url']
    cert = config['cert']

    cert_pem_path = cert['file']
    cert_key_file = cert['pass']

# make the request
with pfx_to_pem(cert_pem_path, cert_key_file) as cert:
    r = requests.get(api_url, cert = cert)

Поскольку я также использую те же функции для аутентификации своего веб-сервиса Flask на сервере, я разбил файл сертификата на три файла:

# ----- SCRIPT 1 -----
# get certificate
f_pem.write(OpenSSL.crypto.dump_certificate(
    OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate())
)

# get keyfile
f_key.write(OpenSSL.crypto.dump_privatekey(
    OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())
)

# get CA_BUNDLE
ca = p12.get_ca_certificates()
    if ca is not None:
        for cert in ca:
            f_ca.write(
                OpenSSL.crypto.dump_certificate(
                    OpenSSL.crypto.FILETYPE_PEM, cert
            ))

Затем я запускаю веб-сервис со следующим кодом:

# ----- SCRIPT 2 -----
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(cert_ca)
context.load_cert_chain(cert_pem, cert_key)

app.run(ssl_context = context, host = '0.0.0.0')

и изменил вызов запросов на

# ----- SCRIPT 1 -----
r = requests.get(api_url, cert = (cert_pem, cert_key), verify = cert_ca)

При попытке извлечь данные изAPI Я получаю сообщение об ошибке

requests.exceptions.SSLError: HTTPSConnectionPool(host='some.host', port=443): Max retries exceeded with url: /some/path/var?ID=xxxxxx (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:847)'),))

Вопрос 1. Что я делаю неправильно при создании CA_BUNDLE?

Вопрос 2. Правильно ли я занимаюсь созданием веб-службы?Моя цель состоит в том, чтобы проверить мой сервер на сервере, на котором хранятся данные, чтобы в конечном итоге иметь возможность получать данные посредством push-запроса.

РЕДАКТИРОВАТЬ: при подключении к моей веб-службе (в браузере) я получаю предупреждение о том, что соединение небезопасно, поскольку сертификат недействителен, несмотря на то, что я импортировал сертификат .p12 в свой браузер.

1 Ответ

0 голосов
/ 21 февраля 2019

Поэтому я использую библиотеку запроса и json для вызова API, в моем случае я могу настроить запрос на игнорирование сертификата, и это быстро решило мою проблему

requests.get(url, headers=headers, verify=False) 

аргумент verify =Ложь игнорирует сертификат, но когда вы запускаете свой код, он выводит предупреждающее сообщение в виде вывода о том, что сертификат неверен, поэтому вы можете добавить этот другой фрагмент кода, чтобы не показывать предупреждение запроса:

import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

Я знаю, что это не отвечает на ваш вопрос, но, возможно, вы можете попытаться выяснить, если без сертификата вы можете получить информацию без проблем.

...