Nowadays, we do virtually everything online: book flights, pay for goods, transfer bank funds, message friends, store documents, and so on. Many things we do require giving out sensitive information like our credit card details and banking information. If a website uses an unsecured network, a malicious hacker can easily steal user information. This is why encryption is so important.
The transport layer security (TLS) protocol is the ultimate safeguard of user information on websites and web applications. TLS uses a hard-to-crack cryptographic algorithm that ensures that no one other than the web server and web client can read or modify transmitted data.
In this article, we’ll explore TLS and how to use Python to check for a website’s TLS certificate validity. Then, we’ll walk through the steps for adding TLS to your Python application on Linux.
Understanding TLS/SSL
The TLS protocol, the successor of the secure socket layer (SSL) protocol, protects data using encryption. When users send their information to a website, TLS encrypts it before sending it. Then, only the server with the same public key as the client can open the message. This rule also applies when the server sends information back to the client. Only the client with the corresponding key can read the data.
For a website to use TLS protocol, you must install a valid TLS/SSL certificate (often called an SSL certificate). When you install the certificate, it upgrades the website from HTTP to HTTPS, a more secure transfer protocol. The certificate is a data file that contains the website’s identity and the public key for opening payload messages.
An SSL certificate must be valid to work. This means that not only must a credible certificate authority (CA) sign it, but the certificate also must be active. Every certificate has an issuance date and an expiration date. A certificate is no longer valid after its expiration date.
Websites without a valid SSL certificate have few visible indicators. For one, the URL in the address bar uses the HTTP://
prefix instead of HTTPS://
. Additionally, there is no lock icon — which browsers use to indicate a secure site — next to the URL. Be cautious about what you share if you notice either of these signs.
Now that we’ve explored TLS-over-SSL (TLS/SSL), let’s see how to implement it using Python.
Working with TLS/SSL in Python
When building a web server with Python, it’s crucial to know how to add TLS/SSL to our application. Before we learn how to do so, let’s see how to use Python to verify the validity of a website’s SSL certificate.
Checking if a website has a valid SSL certificate
If we want to check the validity of a website’s SSL certificate, we can easily do so by running a Python script like this:
import requests
response=requests.get('https://twitter.com/')
print(response)
The code above imports the requests
Python module and uses it to make a GET
request to the Twitter website. (To run the script, you must install the requests
module in Python using pip). We can replace Twitter’s URL with the URL of the website whose SSL certificate we want to verify. The response
variable stores the received value, which the code prints on the last line.
When we execute the code, we get a <Response [200]> (OK)
message, meaning that the Twitter site is using a valid SSL certificate (as expected).
Now, we execute a GET
request to another website. This time we use a website that we know lacks a valid SSL certificate.
import requests
response=requests.get('https://www.expired.badssl.com/')
print(response)
This time, we receive an error stating that the certificate verification process failed:
requests.exceptions.SSLError: HTTPSConnectionPool(host='www. expired.badssl.com', port=443): Max retries exceeded with url : / (Caused by SSLError (SSLCertVerificationError(1, '[SSL:CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1131)’)))
The Python SSL library
We use the Python SSL library to provide TLS encryption in socket-based communication between Python clients and servers. It uses cryptography and message digests to secure data and detect alteration attempts in the network. Digital certificates provide authentication.
The SSL library supports Windows, macOS, and other modern UNIX systems. It also requires OpenSSL to work.
Toward the end of this article, we’ll use the Python SSL library to wrap our connection-based socket with the SSL certificate we generate in the following section.
Create a self-signed SSL certificate in Python
Now that we know how to verify the validity of TLS/SSL on a website, let’s see how we can use it on a Python web server.
We can quickly generate and use a free self-signed certificate for local development. However, if we intend to deploy the site or app on the internet, we must purchase an SSL certificate from a trusted domain registrar (like GoDaddy and NameCheap).
The process of self-generating an SSL certificate for our local Python application has three steps:
- Create the private RSA key.
- Generate a certificate signing request (CSR) using the private key.
- Sign the CSR request to create the certificate.
After creating the SSL certificate, we’ll use it in a Python application when making API requests.
Again, always purchase an SSL certificate from an authorized certificate authority only. Many domain registrars include a free SSL certificate when you buy a domain from them.
Let’s start!
Prerequisite: Installing OpenSSL on Linux
For Linux users, likely, OpenSSLis already on your machine. However, if you don’t yet have it, then you can install it using your package manager. The following command installs OpenSSL in Debian and Ubuntu-based distributions:
sudo apt-get install openssl
If you’re not sure if you already have OpenSSL installed on your machine, you can check by running the following command:
openssl version
If you have it, you get the version number. But if you get an unrecognized command error after running the above command, you must install it.
Creating the private key
We can create the private key with or without a protective passphrase. To add a passphrase, we simply use a cipher in the command, like -aes256
.
Both options below are for generating a 2048-bit RSA private key, but the first option generates the key without a passphrase.
openssl genrsa -out key.pem 2048
openssl genrsa -aes256 -out key.pem 2048
Creating the CSR using the key
In this step, we use the private key generated in the previous step to generate a CSR. To do this, run the following command:
openssl req -new -key key.pem -out signreq.csr
You must fill in some extra information about the certificate in the command line. Provide it, and press Enter when done.
Signing the certificate with the key
The final step is to sign the request to create the certificate. Run the following command:
openssl x509 -req -days 365 -in signreq.csr -signkey key.pem -out certificate.pem
Here, we’re signing the certificate request with the same key used in creating it. This procedure explains why it’s called a “self-signed” certificate.
You can view the certificate details by running the following command:
openssl x509 -text -noout -in certificate.pem
Running a Python HTTPS server with TLS/SSL
Now that we have successfully generated a self-signed certificate, we use it to create an HTTPS server that uses TLS encryption throughout its communication with a client.
The Python program below starts up an HTTPS server on your localhost at port 443.
import http.server
import ssl
httpd = http.server.HTTPServer(('localhost', 443),
http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket,
certfile='./certificate.pem', server_side=True, ssl_version=ssl.PROTOCOL_TLS
httpd.serve_forever()
In the code above, we imported the ssl
and http.server modules
. We then called the HTTPServer
method on http.server
, passing in the server’s address and port number. Next, we wrapped the socket with SSL by specifying the path to our certificate in the wrap_socket
method. Finally, we ran the server at the bottom of the file.
To connect a client, you can use the Python requests module to make a GET request to the server address:
import requests
res = requests.get('https://localhost:443')
print(res)
Note that the above code should be added to a different file from the server code. Running this should connect the client to the server and return a [200] (OK)
message:
<Response [200]>
Summary
In this article, we learned about TLS/SSL and the importance of having a valid digital certificate on our websites. We also saw how to verify SSL on a website by using the requests.get
method.
After that, we introduced the Python SSL library and walked through the process of creating and using a TLS/SSL secured web server in Python. We generated a self-signed certificate with OpenSSL and added the certificate to our HTTP socket connection before running the server.
As the volume of online transactions continues to grow, cybercrime will keep growing in scale and complexity. Using SSL certificates on our websites not only thwarts most attempts to hack your site but also helps make the site more trustworthy to visitors. Check out this article to learn more about why you should use HTTPS.