はじめに
そう、それは2020年の12月。急に寒くなった、その第二週の週末。
Google社のWebブラウザ、Chromeを使って作成しているWEBサービスのサイトにアクセスするときに事件は起こった。
また、Chromeの気まぐれだろう、何日かすればBugfixのバージョンアップで消えるさ、こちとら天下のAmazon様のWeb Serviceの御謹製(御禁制ではない)のELB様の証明書をつかってるんでい。天下御免の紋所、G様のCブラウザだけがガタガタぬかしやがっても、A社のSブラウザやM社のEブラウザは何も言わねぇから・・・てやんでい。きっとうちの装置云々の問題でなく、コンテンツに文句いってやがんだろう?ショウガないじゃないか、外部サイトの情報キュレーションサイト、httpなコンテンツも中継してまうから・・・。
と、思っていたが、なんと身の回りにCブラウザ利用者の多いことよ、あっという間に問題視され、技術チームに集合命令がくだった。
「諸兄らに集まってもらったのはほかでもない、この表示のことだ」元帥がそうのたまわり、御前会議は神妙な雰囲気に包まれる。
「報告はすでに聞いている。当サイト側でなく、コンテンツに問題があるとすると運営の継続は難しい。コンテンツの収集をやめてしまうことで問題は解決するのかね?参謀」
「は!当方の戦力、兵糧、弾薬とも十分、兵士も気力充実にて連戦連勝間違いなしであります。」
・・・参謀よ、その解答こそが頓珍漢だぞ。
問題点の発見
参謀が根拠もなく戦いを楽観視していることを危惧した、若手のジェネラル(当社内ではジャーマネと呼ばれている)が冷静にブラウザの動作を分析し、とある問題点に気づいた。
「この情報表示、当サイトにログイン完了する前に発せられております。矢張、当サイトとの通信において情報の保護がなされていないのでは」
「なんだって?!」
・・・いきなりざわつく首脳陣。だが、確かにジャーマネの示した資料は根拠もしかり。すなわち、ユーザーがhttps通信でブラウザでアクセスしたところにブラウザのresponseではhttpのアドレスを返答しているのである。
「さすがは、ジャーマネ君だね。では、現状が正確に把握できたところで如何にして解決を図るのか」
・・・とはいえ、解決策はすぐにはわからない。何かが原因でアプリケーションがhttpなスキーマでの通信返答をしている、という状況がわかっただけでも大きな一歩だったのだが。
現状
問題が発生しているネットワークシステムは、AWSのサービスを用いて次のような構成になっている。前段にELBがあり、SSLの解決はELBで行っている。httpアクセスもhttpsに変えてELBのSSLポートにリダイレクトさせるように設定してある。そしてELBからEC2までの通信はhttpとし、EC2側ではhttpポートしか開けていない。EC2の中でNginxを作動させ、Webサービスを動かしている。Responseは、このNginxを通じて発せられているのはわかるのだが・・・。Nginxの下、動作しているアプリケーションがスキーマをhttpと設定しているのか、と思って調べたが、アプリケーションの中ではスキーマの指定を行っていない。誰がresponseスキーマをhttpと決めているのか、犯人が分からない。
疑問
なぜ、Nginxはhttpと決めてレスポンスしているのだろうか。
調査
そこは天下のAWS、利用者の多くが設定のテクニックを記録、ネットで公開している。我々が行っている設定なぞ、世の中のゴマンとあるサーバーの設定によくあるものだろう。そう、道を歩いていたらマスクをしている人に出会うぐらい普通の設定のはずだ。つまり、同じ悩みの人がいる・・・と思ったが、案外、「悩んでない」。
「・・・なんてことだ。我々、”常人が悩むはずがないレベルのこと”で悩んでいるのか・・・」
システムの立ち上げにかかわった、最古参の参謀(社内では師匠と呼ばれている)の額に脂汗が浮かんだ。元帥の顔を見ることもできない。・・・とその時、元帥が察したのか、会議の中断を提起した。
「・・・眠い。続きは明日に」
会議から退出する技術チームの面々。日曜深夜のネットワーク会議だったので、みな退散も早々だ。だが、一人、この状況を面白く思っていない人物がいる。そう、師匠だ。
「このままでは、元帥はじめチームともどもサービスは沈ヴぉっぅつ!」
彼は一人、調査を続行することとした。そして賢明な読者ならお気づきとは思うが、彼とは私のことだ。
私は思った。
サービスを沈ヴぉっつさせてはならない。サービスを提供し続けることに意味がある。継続は力なり。(やや古い商売の発想だ。WEBサービスの常識ではないかもしれない。)
調べていると、”ELBからNginxにセキュアな通信であることを伝える”という見出しが目にとまった。
Nginx のリバースプロキシ設定のメモ
https://qiita.com/HeRo/items/7063b86b5e8a2efde0f4
・・・なるほど、直接的解決策ではないが、AWS ELBが、通信の種類を知らせるヘッダー情報を発信してくれていることはわかった。これをEC2インスタンス上のNginxで受け取って、そこからアプリケーションプログラムに渡せば・・・
どうやって渡すんじゃい?
Nginxの設定
状況を整理しよう。問題の発生しているサイトは、ログイン情報の入力が必要なサイトであり、httpsのサイトとなっている。ブラウザがhttpsアクセスしたのに、返信がhttpで帰ってくる矛盾が発生しているのである。
さて、ここでポイントは、アプリからの返答をhttpsスキーマで返す方法だ。
アプリを調べてみると、phpでは通信のスキーマを次の方法で読み取ることができる。
$scheme = $_SERVER['REQUEST_SCHEME']
https://www.php.net/manual/ja/reserved.variables.server.php
返信のスキーマは、アプリの中でこれを使ってスキーマを決めていることがわかった。ということは、アプリに対して、スキーマをhttpsと知らせればいい。先の調査でnginxまで、X-forwarded-protoヘッダにhttpsというスキーマ情報が渡されていることがわかっており、ここにアプリ側の受け取り手順がわかった。・・・のだが・・・この2つをどうやってつなぐのだろう。
nginxからphpアプリに情報を渡す・・・というわけだ・・・
調べてみると、nginxにおいて、fastcgi_param に HTTPSを設定することで、$_SERVERのスキーマ情報を勘違いさせる方法があることを発見。
fastcgi_param HTTPS on;
ヒントになったサイト。
https://cloudpack.media/27602
さて、この設定を /etc/nginx/sites-available に収まっている(Virtual Host)の設定ファイルに書き込み、nginxを再起動したら、それでいいはずだ。
結果
そして、ブラウザCでアクセスする。何事もなく、サイトが開く。
そう、それだけ。世の中、当然と思われるものは、そういうもの。
そして僕たちは、大人に・・・なっとるわ!ったく。なんなんじゃ、この騒動は!・・・っていうか、こんな常識、どこの誰から習えというのだよ!小学校の理科の時間に教えておいてくれよ!
そんなおじさんの叫びも、冬のつめたい空気のなかで、白い水蒸気へと変わり、そしてあっというまに夜闇の中に消えていく。・・・むなしい、そしてあまりにも無知で無力な自分がいたたまれない気持ちになる。冬の冷たい空気はそんな心をちょっとだけ他人のものにしてくれる。眠ろう。仕事は終わった。眠ってしまおう・・・。
常識を知らなかったおじさんの記録として、そして、もしかしたら誰か役に立ててくれる後輩のためにこの情報を書き残しておく。