私は、flask-socketio と python-socketio を使用してプロジェクトに取り組んでいます。通信を保護するには、システムを SSL にアップグレードする必要があります。Mac と Python 3.7 を使用しています。
openssl ( rootCA.pem
) を使用して証明書を作成し、Mac のキーチェーンに追加しました。その後、 と を発行server.cert
しserver.key
ましたrootCA.pem
。Flask-socketio を使用して Web サーバーを構築し、その側に追加server.cert
しました。server.key
最終的に、Web サイトは ssl でうまく機能しました。
この問題は、flask-socketio サーバーと python-socketio クライアントの間の通信を保護したいときに発生しました。クライアントがサーバーに接続しようとすると、接続が拒否され、発生しましたunknown ca error
:
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:2488)
私はいくつかの調査を行い、この問題は Python 3.7 が OpenSSL の独自のプライベート コピーを使用していることが原因である可能性があることに気付きました。そのため、SocketIO クライアントは自己署名証明書を検証できませんでした。そして、これは Python 3.7 のインストールからの情報です:
この Python 3.7 の亜種には、OpenSSL 1.1.1 の独自のプライベート コピーが含まれています。非推奨の Apple 提供の OpenSSL ライブラリは使用されなくなりました。 これは、キーチェーン アクセス アプリケーションとセキュリティ コマンド ライン ユーティリティによって管理されるシステム キーチェーンとユーザー キーチェーンの信頼証明書が、Python ssl モジュールによってデフォルトとして使用されなくなったことを意味します。 サンプル コマンド スクリプトが /Applications/Python 3.7 に含まれており、サードパーティの certifi パッケージ ( https://pypi.org/project/certifi/ ) からデフォルトのルート証明書の精選されたバンドルをインストールします。certifi の使用を選択した場合は、プロジェクトの電子メール更新サービスに登録して、証明書バンドルが更新されたときに通知を受けることを検討してください。
だから私はのフォルダに行き/Applications/Python 3.7
、Install Certificates.command
.
しかし、それは問題の鍵ではありません。python certifi は、ルート証明書の厳選されたコレクションであるためです。もちろん、私の自己署名証明書は含まれていません。したがって、問題を解決するには、Python にrootCA.pem
.
python certifi のフォルダに、 という名前のドキュメントがありますcacert.pem
。これにはルート証明書が含まれます。そこでrootCA.pem
、 の最後にの内容を追加しましたcacert.pem
。
その後、コマンドラインで次のコードを試しました。
openssl verify -CAfile cacert.pem server.crt
そして出力:
server.crt: OK
cacert.pem
この場合、サーバーの証明書を検証できると思います。私はそれがエレガントな解決策ではないことを知っています。Python に自己署名証明書を見つけさせるより良い方法があれば教えてください。
その後、python-socketioでflask-socketioサーバーに接続してみました。今回は、別のエラーが発生しました。サーバー側では、ログ情報は次のとおりです。
(57183) accepted ('127.0.0.1', 56322)
0fd838477c534dfda802bfb0d130d358: Sending packet OPEN data {'sid': '0fd838477c534dfda802bfb0d130d358', 'upgrades': ['websocket'], 'pingTimeout': 60000, 'pingInterval': 25000}
0fd838477c534dfda802bfb0d130d358: Sending packet MESSAGE data 0
127.0.0.1 - - [10/Oct/2019 08:50:36] "GET /socket.io/?transport=polling&EIO=3&t=1570706436.665149 HTTP/1.1" 200 349 0.000436
(57183) accepted ('127.0.0.1', 56324)
http://localhost:3000 is not an accepted origin.
127.0.0.1 - - [10/Oct/2019 08:50:36] "GET /socket.io/?transport=websocket&EIO=3&sid=0fd838477c534dfda802bfb0d130d358&t=1570706436.685631 HTTP/1.1" 400 122 0.000182
クライアント側では、次のようにエラーがスローされました。
Traceback (most recent call last):
File "simple_client.py", line 18, in <module>
sio.connect('https://localhost:3000', namespaces="/channel_A")
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/socketio/client.py", line 262, in connect
engineio_path=socketio_path)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/engineio/client.py", line 170, in connect
url, headers, engineio_path)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/engineio/client.py", line 308, in _connect_polling
if self._connect_websocket(url, headers, engineio_path):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/engineio/client.py", line 346, in _connect_websocket
cookie=cookies)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websocket/_core.py", line 514, in create_connection
websock.connect(url, **options)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websocket/_core.py", line 226, in connect
self.handshake_response = handshake(self.sock, *addrs, **options)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websocket/_handshake.py", line 79, in handshake
status, resp = _get_resp_headers(sock)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/websocket/_handshake.py", line 160, in _get_resp_headers
raise WebSocketBadStatusException("Handshake status %d %s", status, status_message, resp_headers)
websocket._exceptions.WebSocketBadStatusException: Handshake status 400 BAD REQUEST
なぜそれが起こるのか分かりません。Flask-socketio サーバーと python-socketio クライアント間の通信は、SSL なしでうまく機能します。したがって、コードに問題はないと思いますが、ここにコードを示します。そして、これはサーバー用です:
from flask import Flask, render_template
from flask_socketio import SocketIO
from flask_socketio import Namespace
import eventlet
app = Flask(__name__, template_folder="templates")
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, engineio_logger=True, logger=True)
# Create a URL route in our application for "/"
@app.route('/')
def home():
"""
This function loads the homepage
"""
return render_template('index.html')
class MyCustomNamespace(Namespace):
def on_connect(self):
print("Client just connected")
def on_disconnect(self):
print("Client just left")
def on_messages(self, data):
print(f"\nReceived data from client: \n {data}\n")
return data
socketio.on_namespace(MyCustomNamespace('/channel_A'))
if __name__ == "__main__":
eventlet.wsgi.server(
eventlet.wrap_ssl(eventlet.listen(("localhost", 3000)),
certfile='server.crt',
keyfile='server.key',
server_side=True), app)
# socketio.run(app, host="localhost", port=3000, debug=True)
これはクライアント用です:
import socketio
sio = socketio.Client()
def message_received(data):
print(f"Message {data} received")
@sio.on('connect', namespace="/channel_A")
def on_connect():
print("Connect...")
@sio.on('disconnect', namespace="/channel_A")
def on_disconnect():
print(f"Disconnected from server")
sio.connect('https://localhost:3000', namespaces="/channel_A")
助けてください!私の質問が冗長であることは承知しています。しかし、問題を解決しようとした方法を示したいだけです。何か問題がある場合は、お知らせください。ありがとうございました!