Implementing TLS/SSL in Python
Tags: applicationsecurity, engineering
Published: 2022-10-18 08:20:45

---
title: Implementing TLS/SSL in Python
published: true
date: 2022-10-16 15:49:42 UTC
tags: ApplicationSecurity,Engineering
canonical_url: https://snyk.io/blog/implementing-tls-ssl-python/
---

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:

1. Create the private RSA key.
2. Generate a certificate signing request (CSR) using the private key.
3. 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, [OpenSSL](https://github.com/openssl/openssl)is 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](https://snyk.io/blog/10-reasons-to-use-https/) to learn more about why you should use HTTPS.