0

I am writing a piece of code to verify that a given URL's SSL certificate is valid, however, the requests library does not seem to be working correctly. Here is the code:

import requests
    try:
        response = str(requests.get(url, verify=True, allow_redirects=True))
        print(response)
        if "SSL: CERTIFICATE_VERIFY_FAILED" in response:
            print("url \"" + url + "\" has an invalid SSL certificate")
        else:
            valid = True
            for command in commands:
                if command.title == "get info":
                    if command.expirationDate > datetime.date:
                        print("url has an expired SSL certificate.")
                        valid = False
            if valid:
                print("url \"" + url + "\" has a valid SSL certificate")
    except requests.exceptions.InvalidURL:
        print("Invalid url \"" + url + "\"")
    except requests.exceptions.MissingSchema:
        print("Invalid url \"" + url + "\"")
    except (socket.gaierror, urllib3.exceptions.NewConnectionError, urllib3.exceptions.MaxRetryError, requests.exceptions.ConnectionError):
        print("Could not resolve url \"" + url + "\" to host")

Putting in the URL "https://expired.badssl.com/ returns Could not resolve url "https://expired.badssl.com/" to host However, I can in fact navigate to this page. Furthermore, pages without a valid certificate are showing as valid. One of my friends ran this exact code on his beef-xss server, and the output was that it had a valid certificate. I've looked at many tutorials which say the same thing, however, I must be missing something given how nothing I have tried is working.

HullaBrian
  • 23
  • 6
  • Why do you think `SSL: CERTIFICATE_VERIFY_FAILED` is returned by `requests.get()` if certificate verification fails? – President James K. Polk Oct 17 '21 at 21:54
  • According to Geeks for Geeks, when you print out the response, if it failed to validate, the output string will contain that. Not sure if that is best practice, but that is the best way I could find. – HullaBrian Oct 17 '21 at 21:57
  • *...According to Geeks for Geeks...* Please provide a link to that claim. – President James K. Polk Oct 17 '21 at 21:58
  • Sure. https://www.geeksforgeeks.org/ssl-certificate-verification-python-requests/ – HullaBrian Oct 17 '21 at 22:07
  • Ah, I see your confusion. As the answer below notes, that string isn't **returned** by the call to `requests.get()`, it's part of an exception that is raised by the call. Exceptions are strange if you aren't familiar with them, you should read a tutorial about them. There are several, [here is one](https://realpython.com/python-exceptions/). – President James K. Polk Oct 17 '21 at 22:11
  • Thank you so much! I didn't know that I even needed to do that! – HullaBrian Oct 17 '21 at 22:17

1 Answers1

2

Your problems seems to be that your IF statement is not evaluated because requests already throws the exception when the SSL verification fails.

You will probably need to handle that with a dedicated try-except block, something like:

import requests

def has_valid_ssl_req(url):
    try:
        response = str(requests.get(url, verify=True, allow_redirects=True))
        print(response)
        print(url+" has valid SSL, response: "+response)

    except Exception as e:
        print(url+": has INVALID SSL, error:"+str(e))

has_valid_ssl_req('http://expired.badssl.com')
has_valid_ssl_req('http://google.com')

Based on: How can i get Certificate issuer information in python? I would probably use SSL directly

import socket
import ssl

def has_valid_ssl(url):
    try:
        ctx = ssl.create_default_context()
        with ctx.wrap_socket(socket.socket(), server_hostname=url) as s:
            s.connect((url, 443))

        print(url+" has valid SSL")

    except Exception as e:
        print(url+": has INVALID SSL, error:"+str(e))

has_valid_ssl('expired.badssl.com')
has_valid_ssl('google.com')
Dharman
  • 30,962
  • 25
  • 85
  • 135
Andres Bott
  • 690
  • 6
  • 7