Как я могу тестировать https-соединения с Django так же легко, как я могу не-https-соединения с помощью runserver?

109

У меня есть приложение, использующее «безопасные» файлы cookie, и я хочу протестировать его функциональность без необходимости настраивать сложный сервер разработки с поддержкой SSL. Есть ли способ сделать это так же просто, как я могу тестировать незашифрованные запросы с помощью ./manage.py runserver?

Эван Грим
источник
Разве вы не можете просто указать runserver 443, чтобы сервер работал на порту 443?
Furbeenator 05
@Furbeenator: К сожалению, нет - это просто сделает HTTP-сервер на 443, мне нужен реальный SSL-сервер.
Эван Грим

Ответы:

110

Это не так просто, как встроенный сервер разработки, но не так уж сложно получить что-то близкое, используя stunnel в качестве SSL-посредника между вашим браузером и сервером разработки. Stunnel позволяет вам настроить легкий сервер на вашем компьютере, который принимает соединения через настроенный порт, обертывает их с помощью SSL и передает их другому серверу. Мы будем использовать это, чтобы открыть порт stunnel (8443) и передать любой трафик, который он получает, экземпляру сервера запуска Django.

Сначала вам понадобится stunnel, который можно скачать здесь или который может быть предоставлен системой пакетов вашей платформы (например :) apt-get install stunnel. Я буду использовать stunnel версии 4 (например, /usr/bin/stunnel4в Ubuntu), версия 3 также будет работать, но имеет другие параметры конфигурации.

Сначала создайте каталог в вашем проекте Django, чтобы хранить необходимые файлы конфигурации и материалы SSLish.

mkdir stunnel
cd stunnel

Затем нам нужно создать локальный сертификат и ключ, которые будут использоваться для связи SSL. Для этого обратимся к openssl.

Создайте ключ:

openssl genrsa 1024 > stunnel.key

Создайте сертификат, который использует этот ключ (вам будет предложено множество информации, которая будет включена в сертификат - просто ответьте тем, что вам нравится):

openssl req -new -x509 -nodes -sha1 -days 365 -key stunnel.key > stunnel.cert

Теперь объедините их в один файл, который stunnel будет использовать для связи SSL:

cat stunnel.key stunnel.cert > stunnel.pem

Создайте файл конфигурации для stunnel с именем dev_https со следующим содержимым:

pid=

cert = stunnel/stunnel.pem
sslVersion = SSLv3
foreground = yes
output = stunnel.log

[https]
accept=8443
connect=8001
TIMEOUTclose=1

Этот файл сообщает stunnel то, что ему нужно знать. В частности, вы говорите ему не использовать файл pid, где находится файл сертификата, какую версию SSL использовать, что он должен работать на переднем плане, где он должен регистрировать свой вывод и что он должен принимать соединение на порту 8443 и переместите их к порту 8001. Последний параметр (TIMEOUTclose) указывает ему автоматически закрыть соединение через 1 секунду бездействия.

Теперь вернитесь в каталог проекта Django (тот, в котором есть manage.py):

cd ..

Здесь мы создадим сценарий с именем runserver, который будет запускать stunnel и два сервера разработки django (один для обычных подключений, а другой для SSL-подключений):

stunnel4 stunnel/dev_https &
python manage.py runserver&
HTTPS=1 python manage.py runserver 8001

Давайте разберем это построчно:

  • Строка 1: запускает stunnel и указывает его на только что созданный файл конфигурации. У этого stunnel прослушивает порт 8443, оборачивает любые соединения, которые он получает, в SSL и передает их на порт 8001.
  • Строка 2: запускает обычный экземпляр сервера запуска Django (на порту 8000).
  • Строка 3: запускает другой экземпляр сервера выполнения Django (на порту 8001) и настраивает его для обработки всех входящих подключений, как если бы они выполнялись с использованием HTTPS.

Сделайте только что созданный файл runscript исполняемым с помощью:

chmod a+x runserver

Теперь, когда вы хотите запустить сервер разработки, просто выполните его ./runserverиз каталога проекта. Чтобы попробовать, просто укажите в браузере http: // localhost: 8000 для обычного HTTP-трафика и https: // localhost: 8443 для HTTPS-трафика. Обратите внимание, что ваш браузер почти наверняка будет жаловаться на используемый сертификат и потребовать от вас добавить исключение или иным образом явно указать браузеру продолжить просмотр. Это потому, что вы создали свой собственный сертификат, и браузер не верит, что он говорит правду о том, кто это. Это хорошо для разработки, но, очевидно, не подойдет для производства.

К сожалению, на моей машине этот сценарий runserver не завершается нормально, когда я нажимаю Ctrl-C. Мне нужно вручную убить процессы - у кого-нибудь есть предложения, как это исправить?

Благодаря Майклу Gilė по почте и Джанго переплетения в запись вики для справочного материала.

Эван Грим
источник
4
Я только что наткнулся на этот ответ. Некоторые примечания: вам не обязательно запускать отдельный экземпляр разработки на 8001, вы также можете позволить ему подключиться к порту 8000. Если вы хотите, чтобы stunnel был убит автоматически, добавьте функцию и ловушку выхода: kill_stunnel () { kill $ stunnel_pid} trap kill_stunnel exit stunnel4 stunnel / dev https & stunnel_pid = $ 1
Фрик 01
2
Второй экземпляр вызывается с HTTPS = 1, что означает, что он request.is_secure()отправит отчет True. Если вам это не нужно, тогда вы правы - вы можете просто навести stunnel на один экземпляр.
Эван Грим
Если вы запустите stunnel, режим fips не поддерживается .... добавьте fips = no в файл dev_https, чтобы отключить его
yeahdixon 09
2
Я только что пробовал это, поскольку я пытаюсь создать копию разработки сайта, работающего над проектом, разработанным кем-то другим, но я получаю "sslVersion = SSLv3": SSLv3 not supported.
HenryM
1
@HenryM использовать TLSv1.2вместо устаревшего SSLv3. Я отредактировал ответ, чтобы учесть устаревание SSLv3.
доктор Sybren
86

Я бы рекомендовал использовать пакет django-sslserver .

Текущий пакет PyPI поддерживает только Django версии 1.5.5, но исправление было выполнено через 5d4664c . С этим исправлением система работает нормально и представляет собой довольно простое и понятное решение для тестирования https-соединений.

ОБНОВЛЕНИЕ: с тех пор, как я опубликовал свой ответ, приведенный выше коммит был объединен с основной веткой, а новый выпуск был помещен в PyPI. Таким образом, нет необходимости указывать фиксацию 5d4664c для этого конкретного исправления.

Devonbleibtrey
источник
5
Это выглядит многообещающе - возможно, мне придется обновить принятый ответ на этот вопрос. Кто-нибудь еще хочет взвесить?
Эван Грим,
3
это должен стать принятым ответом, который некоторое время используется в довольно сложном проекте, который просто не может работать без работы по https и никогда не имеет проблем.
simone cittadini
2
Работает хорошо ... Спасибо! :)
nidHi
5
Работает с Python 3.6.2 и Django 1.11.3.
phoenix
2
Работает с Python 3.5 и Django 1.11
Hansel,
64

Подобно django-sslserver, вы можете использовать RunServerPlus из django-extensions.

Он зависит от Werkzeug (так что вы получаете доступ к отличному отладчику Werkzeug) и pyOpenSSL (требуется только для режима ssl), поэтому для установки выполните:

pip install django-extensions Werkzeug pyOpenSSL

Добавьте его в INSTALLED_APPS в файле settings.py вашего проекта:

INSTALLED_APPS = (
    ...
    'django_extensions',
    ...
)

Затем вы можете запустить сервер в режиме ssl с помощью:

./manage.py runserver_plus --cert /tmp/cert

Это создаст файл сертификата /tmp/cert.crtи файл ключа, /tmp/cert.keyкоторый затем можно будет повторно использовать для будущих сеансов.

В django-extensions есть множество дополнительных вещей, которые могут вам пригодиться, поэтому стоит быстро просмотреть документацию.

ди-джутто
источник
2
На самом деле лучший ответ для Django 1.6+, поскольку django-sslserver не поддерживает автоматическую перезагрузку для новой версии
Zat42
Лучший ответ по отладке + активация SSL.
Юда Правира
Интересно, почему это не работает в контейнерном приложении для
докеров
@Roel быстро попробовал, и, похоже, он работает для приложения hello world. может случиться так, что у вашего базового образа нет необходимых зависимостей (например, если вы используете -alpine) или вам может потребоваться открыть диапазон IP-адресов, например./manage.py runserver_plus --cert /tmp/cert 0.0.0.0:8000
djsutho
FileNotFoundError: [Errno 2] Нет такого файла или каталога: '/tmp\\cert.crt'
Марк Энтони Либрес
38

просто установите

sudo pip install django-sslserver

включить sslserver в установленные aps

INSTALLED_APPS = (...
"sslserver",
...
)

теперь ты можешь бежать

 python manage.py runsslserver 0.0.0.0:8888
Рябченко Александр
источник
2
Самое чистое решение!
SexyBeast 04
действительно чистое решение, но по какой-то причине оно очень медленное
Bhanu Tez
Хм, Chrome выдает предупреждение, что сертификат недействителен.
zerohedge
@zerohedge предназначен только для разработки, так что это не имеет значения.
Sharpless512
это очень элегантно, но есть ли какое-нибудь решение для тестирования безопасных соединений? например, если вы хотите протестировать Facebook Graph API? developers.facebook.com/docs/graph-api/webhooks#setup
frednikgohar
14

Зарегистрируйтесь на https://ngrok.com/ . Вы можете использовать https для тестирования. Это может помочь людям, которые просто хотят быстро протестировать https.

Нил
источник
6
Для быстрой проверки это отличное решение. И мне не нужно было ни для чего регистрироваться, просто скачайте и запустите ./ngrok http 8000, 8000 - это мой порт localhost.
GavKilbride
4

Для тех, кто ищет передовую версию опции stunnel для целей отладки:

stunnel.pem - это сертификат, созданный в соответствии с наиболее популярным ответом Эвана Гримма.

Слушайте все локальные интерфейсы на порту 443 и перенаправляйте на порт 80 на localhost

sudo stunnel -f -p stunnel.pem -P ~/stunnel.pid -r localhost:80 -d 443

sudo необходимо только для входящих портов (-d [host:] port) ниже 1024

Майкл Ланни
источник
4
  1. Установите ngrok. ссылка для скачивания: https://ngrok.com/download
  2. Выполните следующую команду на терминале

    ngrok http 8000

Это запустит сеанс ngrok. В нем будут перечислены два URL-адреса. Один отображается на http: // localhost: 8000 . Второй отображается на https: // localhost: 8000 . Пожалуйста, проверьте скриншот ниже. Используйте любой URL. Он будет отображаться на вашем локальном сервере.

пример снимка экрана сеанса ngrok

ABN
источник
Самый простой способ сделать это, но не забудьте поместить новый URL https вallowed_host
Роэль
2

Это можно сделать в одной строке с socat:

socat openssl-listen:8443,fork,reuseaddr,cert=server.pem,verify=0 tcp:localhost:8000

, где 8443 - порт для прослушивания входящих HTTPS-соединений, server.pem - самозаверяющий сертификат сервера, а localhost: 8000 - отладочный HTTP-сервер, запускаемый как обычно.

Подробнее: http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html

uri.z
источник
0

Обрабатывайте SSL / TLS с помощью прокси, такого как Nginx, а не Django. Nginx можно настроить для прослушивания порта 443, а затем перенаправления запросов на ваш сервер Django dev (обычно http://127.0.0.1:8000). Конфигурация Nginx для этого может выглядеть следующим образом:

server {
    listen 443 ssl;
    server_name django-dev.localhost;

    ssl_certificate /etc/ssl/certs/nginx_chain.pem;
    ssl_certificate_key /etc/ssl/private/nginx.pem;    

    location / {
        proxy_pass http://127.0.0.1:8000/;
        proxy_set_header Host $host;
    }
}

Вам также необходимо сопоставить django-dev.localhostс 127.0.0.1и добавить django-dev.localhostк ALLOWED_HOSTSв settings.py. В Linux вам нужно добавить следующую строку /etc/hosts:

127.0.0.1   django-dev.localhost

После этого вы сможете получить доступ к своему сайту разработчика, перейдя https://django-dev.localhostв свой браузер (вам нужно будет обойти предупреждение системы безопасности вашего браузера).

пятьдесят две карты
источник