Не работает SSL на сервере python

271 просмотра
0
0 Комментариев

Пытаюсь поставить на Ubuntu 16.04 сервер python 3.5.2 и столкнулся с проблемой — при добавлении строчки с функцией wrap_socket сервер работает, но на запросы со стороны клиента и по http, и по https совсем не отвечает, при этом исключениями не бросается. Файлы сертификата и ключа получены ботом и точно корректны, а стоит закомментировать строку с wrap-socket — и сервер правильно отвечает на любые запросы по протоколу http. Параметр do_handshake_on_connect результат не меняет.

Исходный код сервера таков:

from multiprocessing import Process
from http.server import BaseHTTPRequestHandler, HTTPServer
from cgi import parse_header, parse_multipart
from urllib.parse import parse_qs
import ssl
 
# function that filters a  comment
def f(gid, pid, cid, uid):
    print('Comment validation in process...')
 
# launcher that triggers a function
class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
 
    def do_GET(self):
        self._set_headers()
        self.wfile.write(b'ok')
        print('Got a _GET! Yaaay!')
 
    def do_HEAD(self):
        self._set_headers()
 
    def parse_POST(self):
        ctype, pdict = parse_header(self.headers['content-type'])
        if ctype == 'multipart/form-data':
            postvars = parse_multipart(self.rfile, pdict)
        elif ctype == 'application/x-www-form-urlencoded':
            length = int(self.headers['content-length'])
            postvars = parse_qs(
                    self.rfile.read(length),
                    keep_blank_values=1)
        else:
            postvars = {}
 
    def do_POST(self):
        self._set_headers()
        postvars = self.parse_POST()
        #launching process...
        p = Process(target=f, args=(0,0,0,0))
        p.start()
        p.join()
        self.wfile.write(b'ok')
        print('Got a _POST! Yaaay!')
 
# launcher that launches previous launcher
def run(server_class=HTTPServer, handler_class=S, port=80):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print ('Starting httpd...')
    # SSL LAUNCH
    httpd.socket = ssl.wrap_socket (httpd.socket, server_side=True, certfile='/etc/letsencrypt/live/antispam-system.ru/cert.pem', keyfile='/etc/letsencrypt/live/antispam-system.ru/privkey.pem', do_handshake_on_connect=False)
    httpd.serve_forever()
 
# main part
if __name__ == "__main__":
    from sys import argv
    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()


Добавить комментарий

2 Answers

Python Опубликовано 09.12.2018
0

HTTPS работает через порт 443, а не через порт 80, поэтому следовало указать его, что будет выглядеть так:

def run(server_class=HTTPServer, handler_class=S, port=443):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print ('Starting httpd...')
    # SSL LAUNCH
    httpd.socket = ssl.wrap_socket (httpd.socket, server_side=True, certfile='/etc/letsencrypt/live/antispam-system.ru/cert.pem', keyfile='/etc/letsencrypt/live/antispam-system.ru/privkey.pem', do_handshake_on_connect=False)
    httpd.serve_forever()

Добавить комментарий
0

Вот упрощённый аналог python3 -mhttp.server команды, который работает по https:

#!/usr/bin/env python3
import os
import ssl
import sys
from http.server import SimpleHTTPRequestHandler, HTTPServer
script_dir = os.path.dirname(os.path.realpath(__file__))
keypath = os.path.join(script_dir, 'server.key')
certpath = os.path.join(script_dir, 'server.crt')
def test(HandlerClass=SimpleHTTPRequestHandler,
         ServerClass=HTTPServer, protocol="HTTP/1.0", port=8443, bind="localhost"):
    server_address = (bind, port)
    HandlerClass.protocol_version = protocol
    with ServerClass(server_address, HandlerClass) as httpd:
        httpd.socket = ssl.wrap_socket(
            httpd.socket, keyfile=keypath, certfile=certpath, server_side=True)
        sa = httpd.socket.getsockname()
        serve_message = "Serving HTTP on {host} port {port} (https://{host}:{port}/) ..."
        print(serve_message.format(host=sa[0], port=sa[1]))
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\nKeyboard interrupt received, exiting.")
            sys.exit(0)
if __name__ == '__main__':
    test()

[/apcode]

Основное отличие от python3 -mhttp.server команды в ssl.wrap_socket() строчке.

Чтобы попробовать, необходимо положить рядом с кодом частный ключ (server.key) и сертификат (server.crt) сервера. Самоподписанные версии, можно сгенерировать командой:

$ openssl req -new -x509 -nodes -out server.crt -keyout server.key

Чтобы текущую директорию по https расшарить:

$ python3 https-server.py

Чтобы проверить, что сервер правильный сертификат отдаёт:

$ openssl s_client -CAfile server.crt -verify 9 -connect localhost:8443
...
Verify return code: 0 (ok)
<Ctrl-C>

Чтобы запросить страничку по https:

$ curl --cacert server.crt https://localhost:8443

Чтобы её в браузере открыть:

$ python -mwebbrowser https://localhost:8443

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up