「無理せんと、リバースプロキシ(nginx)使えば?」
ここのところ、Websocket通信のセキュア化のコーディングで、かなり嵌ってしまっている私に、師匠のSさんから、
GoのサーバーでWSSやHTTPSのプロトコルを直接扱うことをせず、かわりに、リバースプロキシサーバーでHTTPSやWSSプロトコルを扱い、GoのサーバーではHTTPやWSプロトコルを扱うように構成を変更する、というのはいかがでしょうか?
とのご提言を頂きました。
あ、そりゃそうだ ―― と思いました。私は、Websocket通信のアタックさえ回避できれば、なんでも良いわけでして、何がなんでもwssをやりたい訳ではありません。
インターネットの中でセキュアが担保できれば、内部システムなんぞスカスカでも構いません(そもそも、システム内部に侵入されたら、その時点で"システムとしては、"The END"です)。
とりあえずPC(Windows10 Box)の中でnginx(Webサーバ)を立てようと思いました。
いや、驚くほど簡単。「インストールから実行まで10秒を切ったWebサーバ」というのは生まれて始めてかもしれません。
http://nginx.org/en/download.html から、Stable versionをダウンロードして、
解凍して、"nginx.exe"を叩くだけ。(私の場合、ダウンロードの場所は、C:\の直下にしておきました)
これで、ブラウザから、http://localhost と入力して稼動確認
ちなみに、トップページは、htmlフォルダの中にあるので、適当に変更すれば、普通のWebサーバにもなります。
それはさておき。
今回の場合、クライアントからnginxまでのセキュアが確保できれば足り、その後ろは、普通のwebsocketの通信ができれば良い、とします(golangでwebsocketのセキュア通信って、もう気が狂いそうになるほど面倒)。
Sさんからは、nginx.confを送付して貰ったのですが、まあ、当然ですが、一発では動きませんでしたので、先ず、セキュア通信なしのリバースプロキシを動かしてみます。
nginxでポート8000で受けて、それを、エコーサーバ(8080)に転送するだけのものですが、NginxのリバースプロキシでWebソケットを通す際の設定 とSさんから送って頂いた設定ファイルを参考にさせて頂いて、以下のようにconf/nginx.confの内容を書き換えました。
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_read_timeout 86400;
}
}
}
ちなみにエコーサーバは、以下のものをそのまま使っています。
でもって、こんな感じでちゃんと動いています。もちろんlocalhost:8080でも動きます。
ーーーー
では、ここから、ngnixまでのセキュア化の検討を開始します。
ここでしばしスタック中。TLSがちゃんと動いているのか不安になったので、普通のWebでできるか、以下のようなnginx.confを使って、index.htmlで試してみました。
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate algo.crt; # https://wp.kobore.net/2020/09/post-1124/で作ったもの
ssl_certificate_key algo.key; # 同上
location / {
root html;
index index.html index.htm;
}
}
}
https://localhost/ でも、http://localhost/ でも動いていますので、algo.crt, algo.keyについては(多分)大丈夫だと思われます。
では、元の問題に戻りましょう。(4時間格闘)
どうやら、外向けをセキュアにするには、nginx.confを3箇所だけ変更追加すれば良い、と記載されていたので、以下のようなnginx.confに改造した "#change"と、"#add"のところだけ。
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
#listen 8000;
listen 443 ssl; # change
server_name localhost;
ssl_certificate algo.crt; #add
ssl_certificate_key algo.key; #add
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_read_timeout 86400;
}
}
}
ところが、https://localhost を実施しても、サーバ側から、以下のエラーがでてきて、どうにもならない。
upgrade:websocket: the client is not using the websocket protocol: 'websocket' token not found in 'Upgrade' header
Visual Studio Codeにかけて、サーバでトレースしても読めないし(htmlの部分だから無理ない)、正直もうどうして良いか分からなくなってきたとき、「あ、chromoのディベロッパーツールを使えばいいか」と気が付きました。
そんでもって、
これで気がつきました。ここって"ws:"ではなくて、"wss:"にしないとアカンのじゃないかな、と。
で、ここを修正して、ECHOサーバを立ち上げ直したら、無事稼動することが確認できました。
まあ、まだまだ課題山積ですが、とりあえず、家(システム)の外はセキュアにする目処が立ちましたので、wssの通信プログラムで苦労するのは「やめる方向」で決定しました。
nginxをリバースプロキシにして、そこまではガチガチにしておき、家の中はユルユルに作るで、進めていくことにします。
以上