2

Python の HTTPServer と BaseHTTPRequest を利用するアプリケーションを作成しています。ある時点で、ユーザーが送信したいデータは機密性が高いため、SOCKS の実装が役立つと考えました。問題は、アプリケーションが非標準ポートで実行される予定であるため、プレーンテキスト接続と SSL 接続の両方で通信​​できると便利だということです。HTTPServer で SSL を使用する方法を見つけました。

import BaseHTTPServer, SimpleHTTPServer
import ssl

httpd = BaseHTTPServer.HTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket, certfile='path/to/localhost.pem', server_side=True)
httpd.serve_forever()

SSL 接続とプレーンテキスト接続の両方を処理するソケット クラスを作成する方法はありますか? SSL を検出するきちんとした方法 (つまり、いくつかのマジック バイト)? 別の方法として、2 つのポートを割り当てることもできますが、それはあまりクールではありません。

4

3 に答える 3

4

問題を少し調べてみました。ソケットを 2 つの異なるサーバーのように動作させるのは簡単です (受信したデータの種類によって異なります)。ここで悪いのは、python の _ssl ライブラリが、ネイティブの python オブジェクトである socket._socket から直接読み取るため、正常にフックできないことです。

1 つの方法は、ネイティブの Python ソケットをフックする C モジュールを作成することです。もう 1 つの解決策は、1 つのフロントエンドと 2 つのバックエンド (https と http) を持つことです。フロントエンドは 4443 をリッスンし、https バックエンドと http バックエンドのどちらと接続するかを決定します。両方のサーバーに同じハンドラーを追加すると、同じように動作します。もう 1 つの問題は、バックエンドではクライアントの IP がわからないことですが、回避策があります (dict {(Frontend to backend source port number): Client IP} のように、フロントエンドが保持し、バックエンドが参照します)。 .

C のソリューションと比較すると、2 番目のソリューションはかなり汚れているように見えますが、ここにあります。

import BaseHTTPServer, SimpleHTTPServer
import ssl
import socket
import select
import threading

FRONTEND_PORT = 4443
BACKEND_PORT_SSL = 44431
BACKEND_PORT_HTTP = 44432
HOST = 'localhost'

httpd_ssl = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_SSL), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd_ssl.socket = ssl.wrap_socket (httpd_ssl.socket, certfile='key.pem', server_side=True)

httpd_direct = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_HTTP), SimpleHTTPServer.SimpleHTTPRequestHandler)

def serve_forever(http_server):
    http_server.serve_forever()

def categorize(sock, addr):
    data = sock.recv(1)
    if data == '\x16':
        port = BACKEND_PORT_SSL
    else:
        port = BACKEND_PORT_HTTP
    other_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    other_sock.connect((HOST, port))
    other_sock.send(data)
    inp = [sock, other_sock]
    select_timeout = 1.0
    try:
        while 1:
            r,w,x = select.select(inp,[],[],select_timeout)
            if not r:
                continue
            for s in r:
                o_s = inp[1] if inp[0]==s else inp[0]
                buf = s.recv(4096)
                if not buf:
                    raise socket.error
                o_s.send(buf)
    except socket.error:
        pass
    finally:
        for s in inp:
            s.close()

threading.Thread(target=serve_forever, args=(httpd_ssl,)).start()
threading.Thread(target=serve_forever, args=(httpd_direct,)).start()

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, FRONTEND_PORT))
sock.listen(10)

while True:
    conn, addr = sock.accept()
    threading.Thread(target=categorize, args=(conn, addr)).start()
于 2012-11-10T23:40:00.040 に答える
0

はい、実際にあります。

しかし、HTTP に STARTLS を実装しているクライアントやサーバーは知りません。IMAP と SMTP で一般的に使用されますが、残念ながら HTTP の実装はないようです。HTTPS とは別のポートで HTTP を提供するのが一般的な方法です。

于 2012-11-10T20:32:58.367 に答える