ローカルで動作確認するときHTTPSでないと動かないAPIがあるので。
ブツ
動機
主要なAPIが、HTTPSであることを求めており、実質HTTPSサーバでないと動作確認すらできません。
- mpurse API
- JavaScript API
これではDOMでHTMLを作るくらいしかできません。困ります。
HTTPなら簡単
私は今まで、HTTPでやっていました。以下でHTTPローカルサーバを立てられます。
PORT=8000
URL="http://0.0.0.0:$PORT/"
chromium-browser $URL
python3 -m http.server $PORT
HTTPであっても、それなりに動作確認する環境としての価値はあります。ローカルのindex.htmlファイルを直接参照したfile://
プロトコルだと実行できないものもあるためです。
ですが、先述のAPIは動作しません。
HTTPSが必要なAPIを動作させるときはGitHub Pagesにアップして動作確認していました。が、デプロイに時間がかかるし、リクエスト上限にひっかかって確認できなくなったりして開発が滞ります。いいかげん、環境を整えねばと思い、重い腰を上げました。
今までの試み
らいうさんの記事mpurseを使ったアプリ開発のための環境構築で、HTTPSサーバをローカルで立てる方法が紹介されていました。このうちオレオレ証明書の方法をやってみたのですが、うまくできませんでした。
おそらく証明書を作ってブラウザに読み込ませるだけでは足りなかったのでしょう。でも、そこから先どうしたらいいかわからなかったので、そこで断念していました。
vueを導入すればイケたかもしれませんが、余計なものはできるだけ省きたかったのです。その環境構築のための学習からはじめねばならず、長い間コーディングできない状態になりそうだったので。
基礎も知らないうちからフレームワークだのライブラリだのを導入したら、わけがわからなくなるんです。経験上。はたしていつになったらそこまで行けることやら。
また、ラズパイがシステムクラッシュを半年に一回ペースで起こしやがるので、できるだけ開発環境はシンプルにしたかった事情もありました。
どうやるか
やっと本題。ググったところ、PythonでHTTPSサーバを動作させる方法があるようです。
以下のようなファイル構成になります。
- project-root/
- index.html
- localhost.pem
- run_server.py
index.html
<h1>Hello HTTPS !!</h1>
<input id="address" value="" placeholder="モナコインのアドレス">
<script>
window.addEventListener('DOMContentLoaded', async(event) => {
document.getElementById('address').value = await window.mpurse.getAddress()
});
</script>
自己証明書をつくる
openssl req -x509 -new -days 365 -nodes \
-keyout localhost.pem \
-out localhost.pem \
-subj "/CN=localhost"
localhost.pem
ファイルが作成されます。これをindex.html
があるところに配置します。
ところで、-days 365
が不穏な気がします。もしかして365日後に期限切れで使えなくなるのでは? そのときはまた作成する必要があるのかもしれません。
HTTPSサーバを作る
run_server.py
import ssl
from http.server import HTTPServer, SimpleHTTPRequestHandler
PORT = 443
CERTFILE = "./localhost.pem"
Handler = SimpleHTTPRequestHandler
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(CERTFILE)
with HTTPServer(("", PORT), Handler) as httpd:
print("serving at address", httpd.server_address, "using cert file", CERTFILE)
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
httpd.serve_forever()
run_server.py
をindex.html
がある場所に配置します。
HTTPSサーバを起動する
index.html
がある場所で以下コマンドを叩きます。
URL="https://localhost/"
chromium-browser $URL
sudo python3 run_server.py
するとサーバが起動し、ブラウザがそれを表示します。
以下のように「プライバシーが保護されません」と警告されます。ここで「詳細設定」ボタンをクリックします。
すると証明書がうんたらと説明があります。ここで「localhost にアクセスする(安全ではありません)」をクリックする。
これで表示できました。
APIも動作しています。これでローカルでも動作テストができそうです。
すでに開発をはじめて一ヶ月くらい経っていますが、ようやくローカルでHTTPS環境ができました。
疑問
- 自己証明書があるのに、なんで警告されるの?
保護されてない通信
になってるけどいいの?
ネットワークの知識がなさすぎてヤバイ。
セキュリティの懸念
たぶんこうしてローカルサーバが起動している間は、指定したポートに穴があいている状態なのでしょう。今回でいうと443
。このポートは外部からの侵入経路になると思われます。
なのでポート番号を変えたり、テストが終わったらサーバを閉じたりしたほうがいいのでしょう。でも、ポート総当りとかされるのでは?
でもそれは今までHTTPでやっていたときも同じだったはずで。HTTPとHTTPSの違いすら理解できていない。HTTPSのほうがセキュアらしいことしか知らない。知らなかったらセキュリティもクソもない。危ないことをやっていても気づけない。あかん。
所感
こんなに何もわからずにやっちゃって大丈夫なのか。ファイアウォールがどうとかも理解できていないし。やはり今の私にサーバを立てることは無謀すぎる。
とりあえずローカルで動作確認さえできればいいので、今回はこれで良しとします。