I want to make a request to the api site using pycurl.

An example of a working request from the command line.

curl -k "https://192.168.2.1/api/login?username=admin&password=admin" 

python code

 buffer = BytesIO() c = pycurl.Curl() c.setopt(c.URL, 'https://192.168.2.1/api/login?username=admin&password=admin') c.setopt(c.WRITEDATA, buffer) c.perform() c.close() body = buffer.getvalue() # Body is a byte string. # We have to know the encoding in order to print it to a text file # such as standard output. print(body.decode("iso-8859-1")) 

gives an error message

 pycurl.error, (60, 'server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none') 

The question is how to make a similar request work on python.

curl command without the -k option :

curl: (60) SSL certificate problem: self signed certificate

urlopen(url, context=ssl.create_default_context()) causes an exception:

 urllib.error.URLError, <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)> 
  • And urllib / requests you are not satisfied? Why pycurl? - Vladimir Martyanov
  • @ Vladimir Martiyanov I am a newbee in python, I was told to do better through pycurl. For me it does not matter. - SkiF
  • @ Vladimir Martianov, but I still want to understand what my problem is right now. - SkiF
  • It is written in Russian in white: PyCURL cannot verify the certificate. Probably, there are no certificates in the repository used by PyCURL - Vladimir Martyanov
  • @ Vladimir Martiyanov okay, and where to get it and how to put it? - SkiF

3 answers 3

server certificate verification failed CAfile: /etc/ssl/certs/ca-certificates.crt

The error message says that according to the information in the specified CAfile, the certificate sent from this site does not pass verification.

For comparison, with the yandex site the same code works without problems:

 import pycurl c = pycurl.Curl() c.setopt(c.URL, 'https://ya.ru') c.perform() 

The curl -k command works for you as the -k key ( --insecure ) turns off checking, which allows third parties to eavesdrop / change messages from / to the site (makes the connection vulnerable to a MITM attack ). It is expected to just curl <url> error returns :

curl: (60) SSL certificate problem: self signed certificate

The private IP in the question is indicated, ask the site administrator for the certificate, which can be curl --cacert to curl --cacert . If you are unable to obtain a certificate directly, in order not to use an insecure connection with each connection, you can download the certificate once:

 $ openssl s_client -prexit -servername $host -connect $host:443 </dev/null | openssl x509 >server.crt 

where host=192.168.2.1 .

If we assume that the connection was not compromised when you received server.crt , then after that you can safely request the url:

 $ curl --cacert server.crt https://$host/path?query 

or in Python:

 import pycurl c = pycurl.Curl() c.setopt(c.URL, url) c.setopt(c.CAINFO, 'server.crt') c.perform() 

or using the requests module:

 import requests r = requests.get(url, verify='server.crt') print(r.text) 

or using urllib from the standard library:

 import ssl import urllib.request context = ssl.create_default_context(cafile='server.crt') with urllib.request.urlopen(url, context=context) as r: print(r.read().decode(r.headers.get_content_charset('utf-8'))) 

Certificate validation is enabled by default since Python 2.7.9 and Python 3.4.3 .


To disable certificate verification ( not recommended ) for pycurl:

 c.setopt(c.SSL_VERIFYPEER, 0) # default 1 c.setopt(c.SSL_VERIFYHOST, 0) # default 2 

for module requests , you can pass verify=False to disable the protection.

To open yourself to the MITM attack using the standard library: urlopen(url, context=ssl._create_stdlib_context()) .

    Example with urllib2. Better at least because you do not need an additional package, and even less code:

     import urllib2 f = urllib2.urlopen("https://ya.ru") print f.read() 
    • thanks, adapted your code for Python 3 - SkiF
    • this also on modern versions of Python 2.7 will not work, since certificate checking is enabled by default. - jfs
    • @jfs on 2.7.6 works. - SkiF
    • @jfs 2.7.13 also works - Vladimir Martyanov
    • @SkiF it "works" for yandex because it has a valid certificate in the chain. The author in question, not yandex, but another site. Read the error message in the question (do not know English, then at least in any translator shove). What do you think the -k option does with curl? Why does c.setopt (c.SSL_VERIFYPEER, 0) exist? - jfs

    Python 3 working code

     import urllib.request f = urllib.request.urlopen('https://192.168.2.1/api/login?username=admin&password=admin') print (f.read()) 
    • What is your version of Python 3? This should not work on modern versions of Python, where certificates are checked by default. curl -k works because it turns off certificate checking. The full name of the option is --insecure . Without verification, the MITM attack is possible. - jfs
    • @jfs version of python 3.4.3 - SkiF
    • On version 3.4.3, verification may be enabled (pep-476). Do I understand correctly the curl <url> command with an error completes (60 returned code), and does curl -k <url> work for you? What happens if the code in the response to run? - jfs
    • curl -k returns the correct jason like this code. - SkiF
    • without the -k option? - jfs