Разработка веб-приложений часто требует защищенного соединения (HTTPS) даже на локальной машине. Это необходимо, например, для тестирования Service Workers, доступа к камере/микрофону или проверки работы безопасных cookie. К счастью, Python позволяет поднять HTTPS-сервер буквально за пару минут, используя встроенные библиотеки и самоподписанный сертификат. Рассмотрим, как это сделать.
Для работы HTTPS прежде всего необходим сертификат и приватный ключ. Поскольку мы работаем локально, мы можем сгенерировать самоподписанный сертификат с помощью утилиты openssl. Для этого откроем терминал, перейдем в папку нашего сервера и выполним следующую команду:
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem
Что делает эта команда:
req -newkey rsa:2048: создает новый запрос на сертификат и 2048-битный ключ RSA.
-nodes: указывает не шифровать приватный ключ паролем (чтобы сервер мог запуститься автоматически).
-days 365: сертификат будет валиден 1 год.
-out cert.pem и -keyout key.pem: сохраняет сертификат и ключ в файлы cert.pem и key.pem соответственно
В процессе выполнения вас могут попросить ввести информацию о стране и организации. Для локального теста можно просто нажимать Enter для пропуска, или ввести любые значения.
В итоге в текущей папке появятся сертификат и ключ - файлы cert.pem и key.pem
Определим в той же папке, где мы создали сертификаты, файл с именем app.py и пропишем в нем следующий код:
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html; charset=utf-8")
self.end_headers()
self.wfile.write("<h1>Hello METANIT.COM</h1>".encode("utf-8"))
# Настройка SSL контекста
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
# Настройки запуска
hostName = "localhost"
serverPort = 4443
# Инициализация сервера
webServer = HTTPServer((hostName, serverPort), MyHandler)
# "Оборачиваем" сокет сервера в SSL-защиту
webServer.socket = context.wrap_socket(webServer.socket, server_side=True)
print(f"Сервер запущен: https://{hostName}:{serverPort}")
# Бесконечный цикл прослушивания порта
try: webServer.serve_forever()
except KeyboardInterrupt: pass
webServer.server_close()
print("Сервер остановлен...")
Разберем основные моменты:
import ssl
Для шифрования подключаем модуль ssl
Далее создаем контекст безопасности ssl.SSLContext и загружаем в него сгенерированные на файлы cert.pem и key.pem
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")
Ключевой момент - берем обычный сокет нашего сервера и "оборачиваем" его в SSL, превращая HTTP в HTTPS.
webServer.socket = context.wrap_socket(webServer.socket, server_side=True)
Для теста просто будет отправлять клиенту строку с кодом html.
Запустим наш скрипт на выполнение, откроем браузер и перейдем по адресу https://localhost:4443
При переходе на сайт ваш браузер выдаст предупреждение о безопасности: "Your connection is not private" (Ваше подключение не защищено). Это нормально. Дело в том, что браузеры доверяют только сертификатам, подписанным авторитетными центрами сертификации. Наш автосгенерированный сертификат является самоподписанным (подписан нами же). Поэтому браузер не может подтвердить нашу личность. Что делать в этом случае? Для локальной разработки нажмем на кнопку "Advanced" (Дополнительно) и выберем "Proceed to localhost" (Перейти на сайт (небезопасно)).