Skip to main content

PythonでTLS/SSLを実装する

著者

Kingsley Ubah

feature python code purple

2022年10月16日

0 分で読めます

今では、航空券の予約、商品の購入、銀行口座間の送金、友人とのメッセージのやり取り、書類の保存など、ほとんどすべてのことをオンラインで行っています。その多くは、クレジットカード情報や銀行情報などの機密情報を提供する必要があります。Webサイトが安全でないネットワークを使用していると、悪意のあるハッカーにユーザー情報を簡単に盗まれてしまう可能性があります。だからこそ、暗号化が重要なのです。

トランスポート層セキュリティ(TLS)プロトコルは、WebサイトやWebアプリケーション上のユーザー情報を守るための重要な仕組みです。TLSは解読が非常に困難な暗号アルゴリズムを使用し、WebサーバーとWebクライアント以外の第三者が、送信中のデータを読み取ったり改ざんしたりできないようにします。

この記事では、TLSについて解説し、Pythonを使ってWebサイトのTLS証明書が有効かどうかを確認する方法をご紹介します。さらに、Linux上のPythonアプリケーションにTLSを追加する手順を説明します。

TLS/SSLを理解する

TLSプロトコルは、Secure Socket Layer(SSL)プロトコルの後継であり、暗号化によってデータを保護します。ユーザーがWebサイトに情報を送信すると、TLSは送信前にその情報を暗号化します。その後、クライアントに対応する公開鍵を持つサーバーだけがメッセージを開けます。この仕組みは、サーバーからクライアントへ情報を送信する場合にも当てはまります。対応する鍵を持つクライアントだけがデータを読み取れます。

WebサイトでTLSプロトコルを使用するには、有効なTLS/SSL証明書(一般にSSL証明書と呼ばれます)をインストールする必要があります。証明書をインストールすると、WebサイトのプロトコルがHTTPから、より安全な通信プロトコルであるHTTPSに切り替わります。証明書は、Webサイトの身元情報と、ペイロードメッセージを開くための公開鍵を含むデータファイルです。

SSL証明書が機能するには、有効でなければなりません。信頼できる認証局(CA)が署名しているだけでなく、証明書が有効期間内である必要があります。すべての証明書には発行日と有効期限があります。有効期限を過ぎると、その証明書は無効になります。

有効なSSL証明書がないWebサイトには、見分けるための表示がいくつかあります。たとえば、アドレスバーのURLがHTTP://で始まり、HTTPS://ではありません。また、安全なサイトを示すためにブラウザーが表示する鍵アイコンも、URLの横にありません。いずれかの兆候に気づいたら、情報を共有する際には注意してください。

TLSとSSL(TLS/SSL)について理解したところで、Pythonを使った実装方法を見ていきましょう。

PythonでTLS/SSLを扱う

PythonでWebサーバーを構築する際は、アプリケーションにTLS/SSLを追加する方法を知っておくことが重要です。その方法を学ぶ前に、Pythonを使ってWebサイトのSSL証明書が有効かどうかを確認する方法を見てみましょう。

Webサイトに有効なSSL証明書があるか確認する

WebサイトのSSL証明書が有効かどうかは、次のようなPythonスクリプトを実行すれば簡単に確認できます。

import requests

response=requests.get('https://twitter.com/')

print(response)

上記のコードでは、Pythonのrequestsモジュールをインポートし、TwitterのWebサイトにGETリクエストを送信しています。(スクリプトを実行するには、pipを使ってPythonにrequestsモジュールをインストールする必要があります。)TwitterのURLを、SSL証明書を確認したいWebサイトのURLに置き換えられます。response変数には受信した値が格納され、コードの最後の行で出力されます。

コードを実行すると、<Response [200]> (OK)というメッセージが表示されます。これは、想定どおりTwitterのサイトが有効なSSL証明書を使用していることを意味します。

次に、別のWebサイトにGETリクエストを送信します。今回は、有効なSSL証明書がないことがわかっているWebサイトを使います。

import requests

response=requests.get('https://www.expired.badssl.com/')

print(response)

今度は、証明書の検証に失敗したことを示すエラーが返されます。

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)’)))

PythonのSSLライブラリ

PythonのSSLライブラリは、Pythonのクライアントとサーバー間のソケットベース通信にTLS暗号化を適用するために使用します。暗号技術とメッセージダイジェストを用いてデータを保護し、ネットワーク上での改ざんを検知します。また、デジタル証明書によって認証を行います。

SSLライブラリは、Windows、macOS、その他の最新のUNIXシステムに対応しています。また、動作にはOpenSSLが必要です。

この記事の後半では、次のセクションで作成するSSL証明書を使って、接続ベースのソケットをラップするためにPythonのSSLライブラリを使用します。

Pythonで自己署名SSL証明書を作成する

WebサイトのTLS/SSLが有効かどうかを確認する方法がわかったところで、PythonのWebサーバーでTLS/SSLを使う方法を見ていきましょう。

ローカル開発用であれば、無料の自己署名証明書をすぐに生成して使用できます。ただし、サイトやアプリをインターネット上に公開する場合は、信頼できるドメイン登録事業者(GoDaddyやNameCheapなど)からSSL証明書を購入する必要があります。

ローカルのPythonアプリケーション用にSSL証明書を自分で生成する手順は、次の3つです。

  1. 秘密RSA鍵を作成する。

  2. 秘密鍵を使って証明書署名要求(CSR)を生成する。

  3. CSRに署名して証明書を作成する。

SSL証明書を作成したら、APIリクエストを行うPythonアプリケーションで使用します。

SSL証明書は、必ず認定された認証局から購入してください。多くのドメイン登録事業者では、ドメインの購入時に無料のSSL証明書が付属します。

それでは始めましょう。

前提条件:LinuxにOpenSSLをインストールする

Linuxをお使いの場合、OpenSSLはすでにマシンにインストールされている可能性があります。まだインストールされていない場合は、パッケージマネージャーを使ってインストールできます。次のコマンドは、DebianおよびUbuntuベースのディストリビューションにOpenSSLをインストールします。

sudo apt-get install openssl

OpenSSLがすでにマシンにインストールされているかわからない場合は、次のコマンドを実行して確認できます。

openssl version

インストールされていれば、バージョン番号が表示されます。上記のコマンドを実行して「コマンドが認識されません」というエラーが表示された場合は、インストールが必要です。

秘密鍵を作成する

秘密鍵は、保護用のパスフレーズを設定してもしなくても作成できます。パスフレーズを追加するには、コマンドで-aes256のような暗号方式を指定します。

以下のどちらの方法でも2048ビットのRSA秘密鍵を生成できますが、最初の方法ではパスフレーズなしで鍵を生成します。

openssl genrsa -out key.pem 2048

openssl genrsa -aes256 -out key.pem 2048

鍵を使ってCSRを作成する

この手順では、前の手順で生成した秘密鍵を使ってCSRを生成します。次のコマンドを実行してください。

openssl req -new -key key.pem -out signreq.csr

コマンドラインで証明書に関する追加情報を入力する必要があります。情報を入力し、完了したらEnterキーを押してください。

鍵を使って証明書に署名する

最後に、リクエストに署名して証明書を作成します。次のコマンドを実行してください。

openssl x509 -req -days 365 -in signreq.csr -signkey key.pem -out certificate.pem

ここでは、CSRの作成に使用したのと同じ鍵で証明書署名要求に署名しています。これが「自己署名」証明書と呼ばれる理由です。

次のコマンドを実行すると、証明書の詳細を確認できます。

openssl x509 -text -noout -in certificate.pem

TLS/SSLを使ってPythonのHTTPSサーバーを実行する

自己署名証明書を正常に生成できたので、クライアントとの通信全体でTLS暗号化を使用するHTTPSサーバーを作成します。

以下のPythonプログラムは、ローカルホストのポート443でHTTPSサーバーを起動します。

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()

上記のコードでは、sslとhttp.server modulesをインポートしています。次に、http.serverのHTTPServerメソッドを呼び出し、サーバーのアドレスとポート番号を渡します。その後、wrap_socketメソッドで証明書のパスを指定し、ソケットをSSLでラップします。最後に、ファイルの末尾でサーバーを実行します。

クライアントを接続するには、Pythonのrequestsモジュールを使ってサーバーアドレスにGETリクエストを送信します。

import requests
res = requests.get('https://localhost:443')

print(res)

上記のコードは、サーバーのコードとは別のファイルに追加してください。実行するとクライアントがサーバーに接続し、[200] (OK)というメッセージが返されます。

<Response [200]>

まとめ

この記事では、TLS/SSLと、Webサイトに有効なデジタル証明書を用意することの重要性について学びました。また、requests.getメソッドを使ってWebサイトのSSLを確認する方法も見てきました。

続いてPythonのSSLライブラリを紹介し、PythonでTLS/SSL対応のWebサーバーを作成して使用する手順を説明しました。OpenSSLで自己署名証明書を生成し、サーバーを実行する前にHTTPソケット接続へ証明書を追加しました。

オンライン取引が増え続けるにつれ、サイバー犯罪の規模と複雑さも拡大していきます。WebサイトでSSL証明書を使用すれば、サイトへのハッキングを試みる攻撃の多くを防げるだけでなく、訪問者からの信頼も高まります。HTTPSを使うべき理由について詳しくは、こちらの記事をご覧ください。