Ccxt: Como desativar a verificação de certificado SSL no Python?

Criado em 29 jun. 2019  ·  51Comentários  ·  Fonte: ccxt/ccxt

Eu li os documentos e não consigo encontrar uma referência para desativar a verificação de certificado SSL. No momento, tenho um projeto em que estou fazendo um ataque man-in-the-middle intencional para alternar proxies conforme a necessidade.

client <-> Proxy Switcher (server acting as proxy)
Proxy Switcher (emulated client) <-> Exchanges

No retorno de qualquer coisa que não seja 200 , o alternador de proxy muda automaticamente o proxy e tenta novamente. Um man-in-the-middle é necessário para verificar se as solicitações HTTPS estão voltando com os cabeçalhos adequados, e essa parte parece funcionar bem. No entanto, a comunicação entre o cliente e o alternador de proxy parece estar retornando os problemas de certificado SSL (esperados), pois o alternador de proxy gera automaticamente seu próprio certificado local. Eu gostaria de desativar isso.

Sem adicionar o certificado ao meu ambiente confiável local, recebo o erro:

(Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))

O que é garantido, mas seria melhor se pudesse ser desativado por alguma bandeira de troca. Ao adicionar o certificado ao meu ambiente confiável local, recebo o erro

(Caused by SSLError(SSLCertVerificationError("hostname 'pro.coinbase.com' doesn't match 'Felipes-MacBook-Pro.local'")))

O que também é garantido, mas um cheque que prefiro desativar. Qualquer ajuda seria apreciada. Minha ideia seria algo simples como:

ex = getattr(ccxt, exchange)(
    {
        "session": cfscrape.create_scraper(),
        "enableRateLimit": False,
        "verify_ssl_certificates": False,
    }
)

Observação: tentei o sinalizador verify sem sucesso.

question

Comentários muito úteis

Todos 51 comentários

@synchronizing

  1. Qual é a sua versão do Python?
  2. Você está usando a versão sincronizada ou assíncrona do lib?

@synchronizing ↓ isso ajuda?

session = cfscrape.create_scraper()
session.verify = False
ex = getattr(ccxt, exchange)(
    {
        "session": session,
        "enableRateLimit": False,
    }
)

@synchronizing

  1. Qual é a sua versão do Python?
  2. Você está usando a versão sincronizada ou assíncrona do lib?

Python 3.7.2 e usando sincronização (testado com cfscrape e sem). Também tentarei assíncrono, só para ter certeza, pois sei que aiohttp tem menos verificações SSL.

@synchronizing, deixe-nos saber se o comentário acima não resolver o problema para você: https://github.com/ccxt/ccxt/issues/5394#issuecomment -506918563

@synchronizing ↓ isso ajuda?

session = cfscrape.create_scraper()
session.verify = False
ex = getattr(ccxt, exchange)(
    {
        "session": session,
        "enableRateLimit": False,
    }
)

Testado com o acima com o mesmo erro de verificação SSL, infelizmente.

Testado com ccxt_async , e parece funcionar bem - passa pelo localizador de proxy também, sem apresentar nenhum problema. SSL certificado adicionado em env (não tenho certeza se funcionaria sem.)

No entanto, cfscrape ainda é desejado para coinbasepro.

Esta página informa que deveria ter funcionado com a versão de sincronização também: https://2.python-requests.org/en/master/user/advanced/#ssl -cert-verification

Screen Shot 2019-06-29 at 05 13 33

@synchronizing você pode postar um pequeno trecho completo de seu código para reproduzi-lo, digamos, 10-20 linhas? Precisamos ter certeza de que não há outra interferência, portanto, precisamos de um trecho completo, incluindo a instanciação.

Com certeza, @kroitor - a partir de agora o código está empacotado em um servidor de API, então me dê alguns para extrair as linhas relevantes para um arquivo de texto separado para facilitar o teste do seu lado.

Além disso: session.verify um booleano ou uma string de localização de certificado? Pelas edições anteriores que vi aqui, pensei que era simplesmente um sinalizador bool.

Além disso: session.verify é um booleano ou uma string de localização de certificado? Pelas edições anteriores que vi aqui, pensei que era simplesmente um sinalizador bool.

Deve funcionar de qualquer maneira, como um booleano ou como um caminho de string, se os documentos estiverem corretos.

Além disso: session.verify é um booleano ou uma string de localização de certificado? Pelas edições anteriores que vi aqui, pensei que era simplesmente um sinalizador bool.

Deve funcionar de qualquer maneira, como um booleano ou como um caminho de string, se os documentos estiverem corretos.

Parece bom. Dê-me alguns para compilar o problema em algumas linhas de código.

Utilizando o seguinte código:

import ccxt

exchange = ccxt.binance()
exchange.session.verify = False # With, or without line.
fetch = exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
print(fetch)

Com a exportação para um proxy man-in-the-middle:

export http_proxy=http://127.0.0.1:8888
export https_proxy=http://127.0.0.1:8888

Ainda recebo erros na versão de sincronização de ccxt . Se quiser testá-lo com o man-in-the-middle, você pode encontrá-lo em meu repositório aqui . Basta executar o arquivo example/example_server.py .

Acabei de perceber que o motivo pelo qual pode ter funcionado com aiohttp é que mesmo com a configuração exchange.session.trust_env e exchange.session.trust_env_aiohttp , nenhuma das bandeiras respeita o conjunto http_proxy e https_proxy env variável.

Atualização: aiohttp também não funciona.

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch


print(asyncio.get_event_loop().run_until_complete(asyncio.gather(fetch_stuff())))

Com aiohttp_proxy definido implícito (uma vez que http_proxy e https_proxy não parecem ser respeitados), as verificações SSL ainda retornam erro. Eu sei que aiohttp usa o sinalizador ssl (em vez de verify , como a biblioteca requests , para ativar / desativar as verificações SSL), mas presumo não há bandeira existente para ccxt .

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

↑ Esta não é uma maneira correta de configurá-lo. Você deve adicionar uma sessão assíncrona e definir verify = False nela, antes de passá-la para o construtor binance. A classe de troca derivada não suporta a opção verify .

Mais sobre isso aqui:

O mau comportamento de sincronização pode ser um bug no proxy MITM: https://www.google.com/search?q=python+https+proxy+ssl+verify+requests. Parece que você não é a única pessoa com dificuldades ao usar proxies + verificação SSL.

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

↑ Esta não é uma maneira correta de configurá-lo. Você deve adicionar uma sessão assíncrona e definir verify = False nela, antes de passá-la para o construtor binance. A classe de troca derivada não suporta a opção verify .

Quando você diz isso, este seria o formato correto?

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888"})
    exchange.session.verify = False
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

print(asyncio.get_event_loop().run_until_complete(asyncio.gather(fetch_stuff())))

Pode ser um bug no proxy MITM: https://www.google.com/search?q=python+https+proxy+ssl+verify+requests. Parece que você não é a única pessoa com dificuldades ao usar proxies + verificação SSL.

Conte-me sobre isso - os proxies SLL + são um pesadelo, como descobri 😩. No entanto, mitm está agindo como o servidor de destino para o cliente, portanto, não está realmente comunicando a solicitação de encaminhamento ao servidor de destino como faria um proxy normal. Em vez disso, ele inicia um cliente emulado que faz isso e, em seguida, retorna a solicitação do cliente emulado para o cliente real, lendo a solicitação no meio. O problema é a comunicação inicial entre mitm e o cliente com ccxt , principalmente devido a um certificado autoassinado no meio. Mesmo com o sinalizador verify definido como falso, o erro parece persistir.

seria este o formato correto?

Não. Este seria o formato correto:

import aiohttp
import asyncio

event_loop = asyncio.get_event_loop()

async def fetch_stuff():
    connector = aiohttp.TCPConnector(ssl=False, loop=event_loop)
    session = aiohttp.ClientSession(loop=event_loop, connector=connector, trust_env=True)
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", 'session': session})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

print(event_loop.run_until_complete(asyncio.gather(fetch_stuff())))

Isso ajuda?

seria este o formato correto?

Não. Este seria o formato correto:

import aiohttp
import asyncio

event_loop = asyncio.get_event_loop()

async def fetch_stuff():
    trust_environment_variables = False
    connector = aiohttp.TCPConnector(ssl=False, loop=event_loop)
    session = aiohttp.ClientSession(loop=event_loop, connector=connector, trust_env=trust_environment_variables)
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", 'session': session})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

print(event_loop.run_until_complete(asyncio.gather(fetch_stuff())))

Isso ajuda?

Sim, é verdade! Recebi uma solicitação no mitm que foi processada, mas não foi devolvida corretamente (que é falha de mitm ). Muito apreciado homem! Deixe-me tentar com a sincronização ccxt .

@synchronizing algo como o acima deve funcionar para a versão sync também. Só preciso cavar a internet sobre a maneira adequada de configurá-lo. No entanto, isso está além do CCXT, infelizmente.

@synchronizing algo como o acima deve funcionar para a versão sync também. Só preciso cavar a internet sobre a maneira adequada de configurá-lo. No entanto, isso está além do CCXT, infelizmente.

Perfeitamente compreensível - tudo que eu esperava era um CONNECT adequado e GET com mitm , pois dali em diante eu sabia que ccxt tinha completado o correto etapas SSL.

@synchronizing, tudo bem se fecharmos isso agora?

Perdoe-me pelo questionamento repetitivo: mas com cfscraper e a funcionalidade de sincronização padrão, podemos definir um session ? Enquanto eu tenho você na escuta.

Se isso estiver além do projeto devido a cfscraper , não se preocupe. A ajuda acima já foi fantástica e eu realmente aprecio isso.

Além disso, completamente irrelevante: não caia em AdBlocker Pro - eles foram comprados por alguma empresa há algum tempo e ainda exibem anúncios. A solução de código aberto é o uBlock Origin, que muito poucas pessoas parecem saber que existe e também é um excelente bloqueador em comparação (incluindo anúncio no YouTube, graças a Deus).

Perdoe-me pelo questionamento repetitivo: mas com cfscraper e funcionalidade de sincronização padrão, podemos definir uma sessão?

Sim, isso deveria ser possível. No entanto, pode haver bugs fora do CCXT:

Em breve adicionarei a opção exchange.verify para a versão sync e precisarei de sua ajuda para testá-la em seu proxy.

Perdoe-me pelo questionamento repetitivo: mas com cfscraper e funcionalidade de sincronização padrão, podemos definir uma sessão?

Sim, isso deveria ser possível. No entanto, pode haver bugs fora do CCXT:

Em breve adicionarei a opção exchange.verify para a versão sync e precisarei de sua ajuda para testá-la em seu proxy.

Soa como um plano! Mais uma vez, agradeço a ajuda. Sinta-se à vontade para fechar este problema e reabri-lo quando for necessário para o teste.

@synchronizing não deve demorar muito,

@synchronizing não deve demorar muito,

Parece bom para mim, estarei aqui.

Ok, aqui está o que precisamos fazer:

  1. Aguarde 15 minutos para a versão 1.18.844 chegar
  2. Atualize sua versão CCXT (certifique-se de que esteja atualizada corretamente)
  3. Experimente o seguinte código:

# sync 

import ccxt
exchange = ccxt.binance({'verify': False})
fetch = exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
print(fetch)

ou


# async

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

Ficaremos felizes se você nos informar se isso resolveu o problema para você ou não.

Ficaremos felizes se você nos informar se isso resolveu o problema para você ou não.

Ofc, ficaremos felizes em ajudar. Para o async , recurso pretendido para atribuir verify diretamente no construtor binance ?

Para o assíncrono, o recurso pretendido para atribuição de verificação diretamente no construtor binance?

Sim, adicionei a opção de construtor verify às versões sync e async . Você também pode defini-lo depois de criar a instância de troca:

exchange = ccxt.binance()
exchange.verify = False

Para o assíncrono, o recurso pretendido para atribuição de verificação diretamente no construtor binance?

Sim, adicionei a opção verify às versões sync e async .

Bonito. Vou dar uma chance agora.

@synchronizing encontrou alguns pequenos problemas ao longo do caminho, adicionou as correções, portanto, chegará em breve (5-10 minutos). Em espera.

@synchronizing encontrou alguns pequenos problemas ao longo do caminho, adicionou as correções, portanto, chegará em breve (5-10 minutos). Em espera.

Qual versão devo procurar?

@synchronizing 1.18.844 (o que

Ok, chegou, ansioso por ouvir de você.

sync versão está funcionando como esperado em 1.18.844 :

import ccxt as ccxt

exchange = ccxt.binance(
    {
        "proxies": {"http": "http://127.0.0.1:8888", "https": "http://127.0.0.1:8888"},
        "verify": False,
    }
)
fetch = exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
print(fetch)

async version não funciona com o seguinte:

import ccxt.async_support as ccxt
import asyncio

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

print(asyncio.get_event_loop().run_until_complete(asyncio.gather(fetch_stuff())))

O erro SSL é lançado para o código acima. No entanto, ela não funciona durante o carregamento session , como mostrado anteriormente aqui . Presumivelmente, verify pode não estar configurando a bandeira ssl em TCPConnector para False internamente dentro de ccxt .

Supostamente, a verificação pode não estar definindo o sinalizador ssl no TCPConnector como False internamente no ccxt.

Ok, adicionei mais uma edição a ele, informe-nos se 1.18.845 não resolver o problema do lado async . Fechando isso por enquanto. Sinta-se à vontade para reabri-lo ou apenas fazer mais perguntas, se houver. Ficaremos felizes se você relatar de qualquer maneira.

Parece bom - vou fazer uma tentativa, obrigado novamente.

async ainda não está trabalhando com 1.18.845 com "verify" : False definido.

import ccxt.async_support as ccxt
import asyncio

async def fetch_stuff():
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    print(exchange.verify)
    fetch = await exchange.fetch_ohlcv("ETH/BTC", "1m", 1514764800000)
    await exchange.close()
    return fetch

print(asyncio.get_event_loop().run_until_complete(asyncio.gather(fetch_stuff())))

@synchronizing não funciona com verify: False , mas funciona com https://github.com/ccxt/ccxt/issues/5394#issuecomment -506921151?

@synchronizing não funciona com verify: False , mas funciona com # 5394 (comentário) ?

Correto, infelizmente.

@synchronizing, você tem certeza disso? Isso é estranho, porque eles deveriam ser tecnicamente iguais ...

@synchronizing ah, nvm, encontrei outro bug ali com a ordem das chamadas, vai consertar em um momento.

@synchronizing, você tem certeza disso? Isso é estranho, porque eles deveriam ser tecnicamente iguais ...

Eles parecem ser diferentes em mais testes:

import ccxt.async_support as ccxt
import asyncio
import aiohttp

async def fetch_stuff():
    connector = aiohttp.TCPConnector(ssl=False, loop=asyncio.get_event_loop())
    exchange = ccxt.binance({"aiohttp_proxy": "http://127.0.0.1:8888", "verify": False})
    print(exchange.session._connector._ssl)
    print(connector._ssl)
    await exchange.close()

asyncio.get_event_loop().run_until_complete(fetch_stuff())

Saídas:

<ssl.SSLContext object at 0x10f55c480>
False

@synchronizing ah, nvm, encontrei outro bug ali com a ordem das chamadas, vai consertar em um momento.

Incrível, lmk!

@synchronizing ok, vamos tentar novamente com 1.18.846. Infelizmente, não posso realmente testá-lo do meu lado, atm, sua ajuda com a depuração é muito apreciada! A autoconstrução leva de 10 a 15 minutos.

@synchronizing ok, vamos tentar novamente com 1.18.846. Infelizmente, não posso realmente testá-lo do meu lado, atm, sua ajuda com a depuração é muito apreciada! A autoconstrução leva de 10 a 15 minutos.

Meu prazer homem - eu agradeço todo o trabalho em sua extremidade Estarei atento ao novo lançamento para fazer uma tentativa.

https://travis-ci.org/ccxt/ccxt/builds

Funcionando como esperado! Obrigado novamente, felicidades.

@kroitor
Devemos registrar um aviso se os certificados SSL forem desativados ou substituídos, já que isso pode resultar em chaves roubadas? Ataque MITM e há algumas trocas usando dados de login como chaves (por exemplo, dx.exchange).

@kroitor
Devemos registrar um aviso se os certificados SSL forem desativados ou substituídos, já que isso pode resultar em chaves roubadas? Ataque MITM e há algumas trocas usando dados de login como chaves (por exemplo, dx.exchange).

Deixe-me apenas adicionar:

  • aiohttp ( ccxt.async_support ) não descarta o aviso de certificado SSL.
  • requests ( ccxt ) faz aviso de certificado SSL lance através urllib3 .

@brandsimon , neste caso específico, o ataque MITM é feito deliberadamente pelo proprietário. Mas no geral sim, acho que seria ótimo ter um aviso para que a gente fique atento! )

@synchronizing thx pelas dicas!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

jjhesk picture jjhesk  ·  3Comentários

hippylover picture hippylover  ·  3Comentários

ljianyih picture ljianyih  ·  3Comentários

nashse picture nashse  ·  3Comentários

slideup-benni picture slideup-benni  ·  3Comentários