Прокси-сервер Python с ошибкой TLS: ошибка SSLContext с PROTOCOL_TLS_SERVERPython

Программы на Python
Ответить
Anonymous
 Прокси-сервер Python с ошибкой TLS: ошибка SSLContext с PROTOCOL_TLS_SERVER

Сообщение Anonymous »

Я написал прокси-сервер на основе Python, который поддерживает как HTTP, так и HTTPS. Целью является перенаправление или блокировка определенных доменов, например, перенаправление определенных вредоносных веб-сайтов на защищенную страницу (например, Google). Я хочу развернуть прокси-сервер в безопасной среде с помощью TLS.
Текущее поведение
Сообщение об ошибке:

Код: Выделить всё

SSL error occurred: Cannot create a client socket with a PROTOCOL_TLS_SERVER context (_ssl.c:806). Closing connection gracefully.
If the SSL handshake fails, please make sure the self-signed certificate is properly installed in the client as a trusted authority.
Прокси-сервер корректно перенаправляет HTTP-соединения и работает без шифрования.
Однако при подключении через HTTPS (порт 443) происходит сбой SSL-квитирования, что приводит к этой ошибке.
Минимальный воспроизводимый пример
Вот мой код Python:

Код: Выделить всё

import http.server
import socketserver
import requests
import socket
import select
import ssl
import urllib3
from urllib.parse import urlparse, quote

# Suppress InsecureRequestWarning warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# List of blocked domains
BLOCKED_DOMAINS = [
"example.com",
"blocked.com",
"malicious-site.com"
]

# Certificate files for SSL connections
CERT_FILE = "cert.pem"
KEY_FILE = "key.pem"

class ProxyHandler(http.server.BaseHTTPRequestHandler):
def do_CONNECT(self):
target_host, target_port = self.path.split(":")
target_port = int(target_port)

# Check if the domain should be blocked
if any(blocked_domain in target_host for blocked_domain in BLOCKED_DOMAINS):
print(f"CONNECT request to blocked domain: {target_host}. Redirecting to Google.")
target_host = "www.google.com"
target_port = 443

try:
# Establish connection to the target
context = None
if target_port == 443:
# SSL context for secure connection with custom certificate
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.maximum_version = ssl.TLSVersion.TLSv1_3
context.check_hostname = False  # Disable to avoid hostname verification
context.verify_mode = ssl.CERT_NONE  # Disabled for local testing
context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)

# Specify secure cipher suites
context.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20:ECDHE+SHA256:!aNULL:!MD5:!3DES')
raw_sock = socket.create_connection((target_host, target_port))
if context:
# `server_hostname` must be set for `check_hostname` to work
conn = context.wrap_socket(raw_sock, server_hostname=target_host)
else:
conn = raw_sock

# Connection established successfully, send response to client
self.send_response(200, "Connection established")
self.end_headers()

# Data transfer between client and target server
client_socket = self.connection
sockets = [client_socket, conn]

while True:
readable, _, _ = select.select(sockets, [], sockets, 10)
if not readable:
break
for sock in readable:
other = conn if sock is client_socket else client_socket
data = sock.recv(4096)
if not data:
break
other.sendall(data)
except ssl.SSLError as ssl_error:
print(f"SSL error occurred: {ssl_error}. Closing connection gracefully.  If the SSL handshake fails, please make sure the self-signed certificate is properly installed in the client as a trusted authority.")
except (ConnectionAbortedError, socket.error) as e:
print(f"Connection error during data transfer: {e}")
except Exception as e:
print(f"Failed to establish connection: {e}")
if not self.wfile.closed:
try:
self.send_error(502, "Failed to establish connection")
except BrokenPipeError:
print("Broken pipe when attempting to send error response.")
finally:
try:
if 'conn' in locals() and conn:
conn.close()
except Exception as e:
print(f"Error while closing connection: {e}")

if __name__ == "__main__":
port = 8080
with socketserver.ThreadingTCPServer(('', port), ProxyHandler) as httpd:
httpd.allow_reuse_address = True
print(f"Proxy server running on port {port} with HTTPS support")
httpd.serve_forever()

Возможные вопросы
Использую ли я неправильный контекст SSL (ssl.PROTOCOL_TLS_SERVER) в контексте прокси-сервера? Должен ли я вместо этого использовать другой контекст?
Может ли проблема быть связана с использованием самозаверяющего сертификата? Если да, то как я могу гарантировать, что клиент принимает сертификат как заслуживающий доверия?
Нужны ли дополнительные шаги по настройке в контексте SSL для достижения успешного подтверждения SSL?
Нужно ли настроить контекст SSL по-другому, потому что прокси действует как на стороне сервера, так и на стороне клиента?
Я весь день пытался решить эту проблему, но застрял. Этот проект очень важен для меня, потому что я хочу создать что-то, что защитит и детей, и взрослых от порнографии. Если кто-то готов помочь, буду очень благодарен! Я полон решимости найти решение и буду благодарен за любую поддержку.

Подробнее здесь: https://stackoverflow.com/questions/792 ... tls-server
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»