Fixing SSL certificate error in exe compiled with

2019-04-05 09:22发布

I've just finished testing a Python programme which involves logging into a site and requires a CSRF cookie to be set. I've tried packaging it as an exe using py2exe and got a socket error. I have the same problem when I try with PyInstaller. Googling the Errno I found a few other people with the same problem and so I know the problem is to do with the location of SLL certificates.

This is my site_agent class including the logging calls.

    class site_agent:
        self.get_params()
        URL = root_url + '/accounts/login/'        
        # Retrieve the CSRF token first
        self.agent = requests.session()
        self.agent.get(URL)  # retrieves the cookie # This line throws the error
        self.csrftoken = self.agent.cookies['csrftoken']    
        # Set up login data including the CSRF cookie
        login_data = {'username': self.username,
                      'password': self.password,
                      'csrfmiddlewaretoken' : self.csrftoken}
        # Log in
        logging.info('Logging in')
        response = self.agent.post(URL, data=login_data, headers=hdr)

The error comes at the self.agent.get(URL) line and the Traceback shows:

Traceback (most recent call last):
  File "<string>", line 223, in <module>
  File "<string>", line 198, in main
  File "<string>", line 49, in __init__
  File "C:\pyinstaller-2.0\pyinstaller-2.0\autoresponder\b
uild\pyi.win32\autoresponder\out00-PYZ.pyz\requests.sessions", line 350, in get
  File "C:\pyinstaller-2.0\pyinstaller-2.0\autoresponder\b
uild\pyi.win32\autoresponder\out00-PYZ.pyz\requests.sessions", line 338, in requ
est
  File "C:\pyinstaller-2.0\pyinstaller-2.0\autoresponder\b
uild\pyi.win32\autoresponder\out00-PYZ.pyz\requests.sessions", line 441, in send

  File "C:\pyinstaller-2.0\pyinstaller-2.0\autoresponder\b
uild\pyi.win32\autoresponder\out00-PYZ.pyz\requests.adapters", line 331, in send

requests.exceptions.SSLError: [Errno 185090050] _ssl.c:336: error:0B084002:x509
certificate routines:X509_load_cert_crl_file:system lib

Does this mean that the problem is in requests.adapters?

If so, can I just edit it in my installed Python packages to look for cacert.pem somewhere else, rebuild my exe with py2exe or PyInstaller, then change it back in my installed version of Python?

EDIT

I now have the programme running after compiling with PyInstaller and setting verify=False in all requests.get() and requests.post() calls. But SSL is there for a a reason and I'd really like to be able to fix this error before letting anyone use the tool.

3条回答
聊天终结者
2楼-- · 2019-04-05 10:07

In addition to the answer given by frmdstryr, I had to tell requests where the cacert.pem is. I added the following lines right after my imports:

# Get the base directory
if getattr( sys , 'frozen' , None ):    # keyword 'frozen' is for setting basedir while in onefile mode in pyinstaller
    basedir = sys._MEIPASS
else:
    basedir = os.path.dirname( __file__ )
    basedir = os.path.normpath( basedir )

# Locate the SSL certificate for requests
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(basedir , 'requests', 'cacert.pem')

This solution is derived from this link: http://kittyandbear.net/python/pyinstaller-request-sslerror-manual-cacert-solution.txt

查看更多
贪生不怕死
3楼-- · 2019-04-05 10:14

This can be solved easily if you are using "requests" module.

1) Place the below code in your main python file where "requests" module is used

os.environ['REQUESTS_CA_BUNDLE'] = "certifi/cacert.pem"

2) Within your distributable folder where exe is present, create a folder called "certifi" and place the "cacert.pem" file within it.

3) You can find the "cacert.pem" file by

pip install certifi

import certifi
certifi.where()

Awesome.. now your distributable includes the necessary certificates to validate ssl calls.

查看更多
淡お忘
4楼-- · 2019-04-05 10:27

If using pyinstaller... create a hook-requests.py file in PyInstaller\hooks\ for the requests lib containing

from hookutils import collect_data_files

# Get the cacert.pem
datas = collect_data_files('requests') 
查看更多
登录 后发表回答