Django development server и тестирование HTTPS

Выбрав фреймворк Django для разработки корпоративного сайта, я столкнулся с проблемой тестирования его работы по протоколу HTTPS при использовании встроенного веб-сервера. Несмотря на поддержку работы с безопасными соединениями в Django, поставляемый в комплекте веб-сервер не обслуживает запросы по HTTPS.

Первое, что пришло в голову, поднять полноценный веб-сервер (например, Apache) для разработки и тестирования, но что если не хочется отказываться от удобств и простоты использования встроенного веб-сервера Django?

Поиск в Интернете по запросу «django + https» выдал несколько статей датированных 2009 и 2012 годами, в которых для тестирования HTTPS предлагается использовать stunnel.

Данная статья является инструкцией полученной в результате настройки stunnel под среду разработки Django на Ubuntu 12.04.1 LTS x64.

Программная среда

 

  • Ubuntu 12.04.1 LTS (x64)
  • OpenSSL 1.0.1 14 Mar 2012
  • Python 2.7.3
  • virtualenv 1.8.4
  • Django 1.5.1

Установка и настройка stunnel

Для начала необходимо установить stunnel (версии 4.х, ветка 3.х более не поддерживается):

$ sudo apt-get install stunnel4

Базовые настройки stunnel находятся в файле /etc/default/stunnel4:

# /etc/default/stunnel
# Julien LEMOINE <speedblue@debian.org>
# September 2003

# Change to one to enable stunnel automatic startup
ENABLED=0
# Configuration file loacation mask
FILES="/etc/stunnel/*.conf" 	
OPTIONS=""

# Change to one to enable ppp restart scripts
PPP_RESTART=0

В нашем случая изменения вносить не нужно, так как stunnel будет использоваться лишь в связке с веб-сервером Django на время разработки и тестирования.

А вот то, что понадобится обязательно — сертификат X.509.

Генерация сертификата

В руководстве stunnel указаны следующие требования к сертификату:

…. Each SSL enabled daemon needs to present a valid X.509 certificate to the peer. It also needs a private key to decrypt the incoming data. The easiest way to obtain a certificate and a key is to generate them with the free OpenSSL package …

… The order of contents of the .pem file is important. It should contain the unencrypted private key first, then a signed certificate (not certificate request). There should be also empty lines after certificate and private key. Plaintext certificate information appended on the top of generated certificate should be discarded. So the file should look like this:

——BEGIN RSA PRIVATE KEY——
[encoded key]
——END RSA PRIVATE KEY——
[empty line]
——BEGIN CERTIFICATE——
[encoded certificate]
——END CERTIFICATE——
[empty line]

Для генерации приватного ключа и сертификата воспользуемся OpenSSL (должен присутствовать в Ubuntu 12.04.1):

$ cd ~
$ openssl genrsa -out private.key
$ openssl req -new -x509 -key private.key -out stunnel.cert -days 365

Во время генерации необходимо ввести данные о владельце (коды стран для удобства).

На выходе получаем два файла private.key и stunnel.cert, которые необходимо объединить и добавить пустые строки согласно шаблона:

$ (cat private.key ; echo ; cat stunnel.cert ; echo) > stunnel.pem

Теперь создадим файл конфигурации для туннеля.

Файл конфигурации

Пример файла конфигурации stunnel.conf-sample находится в /usr/share/doc/stunnel4/examples/, а описание параметров можно посмотреть в man stunel4 или в документации. Плюс ко всему, раздел FAQ на сайте программы содержит некоторые полезные советы.

Создадим файл конфигурации в домашнем каталоге:

$ cd ~
$ vim stunnel.conf

В нашем случая он имеет следующее содержимое:

; Certificate & Key
cert = ./stunnel.pem
; Use SSL version 3, which is more secure
sslVersion = SSLv3
; If next argument is empty, then no pid file will be created
pid =
; if 'yes' stay in foreground (don't fork) and log to stderr instead of via syslog
foreground = no

; Performance tweak from FAQ (https://www.stunnel.org/faq.html)
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1

; Enable compression
compression = zlib

; Debugging - emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), or debug (7)
debug = 7
output = /var/log/stunnel4/stunnel.log

; HTTPS service section
[https]
; Port to listen incoming client connections
accept = 8443
; Port which Django development server listens to
connect = 8000
; Tweak for MSIE (see FAQ or manual)
TIMEOUTclose = 0

Давайте проверим, что получилось?

Создание туннеля и запуск веб-сервера

Запустим stunnel и встроенный веб-сервер Django для тестового проекта (пустой проект, сразу после django-admin.py startproject):

$ cd ~
$ stunnel4 stunnel.conf
$ source django/bin/activate
(django)$ cd django/projects
(django)$ django-admin.py startproject testone
(django)$ cd testone/
(djanho)$ HTTPS=on python manage.py runserver

Переменная окружения HTTPS=on необходима для корректной симуляции HTTPS в Django, без нее метод request.is_secure() будет возвращать False.

Проверим «прослушиваемые» порты:

$ netstat –an

 

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
...
tcp        0      0 0.0.0.0:8443            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:8000          0.0.0.0:*               LISTEN
...

Туннель успешно создан — stunnel слушает на всех внешних интерфейсах порт 8443, а веб-сервер локальные соединения на порту 8000.

Для «уничтожения» туннеля подойдет команда killall:

$ ps -e | grep stunnel4

 

12530 pts/1 00:00:00 stunnel4
12531 pts/1 00:00:00 stunnel4
12532 pts/1 00:00:00 stunnel4
12533 pts/1 00:00:00 stunnel4
12534 pts/1 00:00:00 stunnel4
12535 ? 00:00:00 stunnel4

 

$ killall stunnel4

Проверка работы

Откроем в браузере любой существующий на сервере URL, используя https:// вместо http://. При первом запросе мы должны увидеть предупреждения о ненадежном сертификате, т.к. подписан он был нами лично, а не аккредитованным центром (Certificate Authority). После подтверждения исключения безопасности, перед нами появится запрошенная страница, полученная по протоколу HTTPS.

7a88631abe386c890e618019342f1d62
Было

848fe1fc973cb0a41ac442dd5bf5f666
Стало

Заключение

В результате мы получаем возможность отладки работы проекта Django с использованием HTTPS без необходимости держать полноценный веб-сервер.

Хочу отметить, что на сайте stunnel присутствует версия для Windows и Android, так что попытаться собрать подобную схему можно и на этих операционных системах.

Всем большое спасибо за внимание и надеюсь, что данная информация будет кому-то полезной.

Под конец перечислю те преимущества и недостатки, которые отметил для себя, а также приведу список ссылок.

Преимущества

+ не требуется установка полноценного веб-сервера;
+ возможность построения туннелей для нескольких Django веб-серверов;
+ использование преймуществ встроенного веб-сервера.

Недостатки

— это не полноценный веб-сервер с поддержкой HTTPS;
— необходимость в установке и настройки дополнительного ПО;
— фактически веб-сервер Django обрабатывает HTTP запросы (см. логи ниже).

Логи веб-сервера

Validating models…

0 errors found
July 26, 2013 — 10:06:33
Django version 1.5.1, using settings ‘testone.settings’
Development server is running at 127.0.0.1:8000/
Quit the server with CONTROL-C.

[26/Jul/2013 10:07:25] «GET / HTTP/1.1» 200 1955
[26/Jul/2013 10:07:30] «GET / HTTP/1.1» 200 1955

Материалы

 

  1. Security in Django
  2. Testing HTTPS with Django’s Development Server
  3. stunnel manual
  4. Running a Django (or any other) dev instance over HTTPS
  5. Installing Stunnel to Enable SSL Connections in Pan Newsreader