gokigenmaruのブログ

40から始めるクラウドエンジニア

TLS接続の証明書チェック

前回はcurlの-kオプションを使った時の挙動をcurlの出力から追ってみました。
今回はパケットから見てみようかなと思います。
毎回yahooさんだとアレなので、今回は世界のSonyさんに(勝手に)ご協力をいただきました。

サイトのFQDNとSNIのFQDNが違った場合

パケットキャプチャ1

これはSonyさんのWebサイトに接続した際のパケットをwiresharkで取得したものです。
3way handshakeの後にTLSネゴシエーションが始まっており、
・ClientHello(自PC→Webサイト)
・ServerHello(Webサイト→自PC)
・ServerKeyChange(Webサイト→自PC)
・ClinetKeyChange(自PC→Webサイト)
・ChangeCipher(自PC→Webサイト)
・ChangeCipher(Webサイト→自PC)
TLSネゴシエーションがされています。
見た感じはChangeCipherがお互いから出ているので、TLSネゴシエーションは終わっていると思います。

ポイントは最後のChangeCipher(Webサイト→自端末)が起きた後のEncrypted Alert(自端末→Webサイト)ののちのFinAck(自端末→Webサイト)です。
Encrypted AlertはTLSネゴシエーションを終わらせる時も出ますので、Alertの内容が大事になのですが、中身は見れません…。
Encrypted Alertの中身については以下のサイトを参照してください。
https://www.ipa.go.jp/security/rfc/RFC2246-07JA.html


ちなみに証明書に問題が無いときは下のキャプチャようにChangeCipherの後はApplicationDataとなります。

パケットキャプチャ2

上記のことからわかるのは、
証明書に問題があった場合、TLSネゴシエーションが終わった後に証明書の検証を行い、問題があれば接続元から通信を終わらせに行くということです。


-kオプションで証明書のエラーを無視すると

curlの-kで証明書のエラーを無視した場合のパケットを見てみました。

パケットキャプチャ3

証明書に問題が無い正常時と同じですね。
ChangeCipherの後はApplicationDataとなっています。




簡単なまとめ

証明書の検証は"接続元"が実施しているので、検証を実施するかしないかは接続元の処理に寄ることがわかります。
つまり、HTTPS通信にし、証明書のCNが異なる場合は通信を通さないというのは証明書だと抜けることが可能です。

じゃあどうすればいいかというと、以下のようにすれば証明書の検証に頼らずにこちらが用意したFQDNでアクセスが来た時だけ処理をするということが出来るのかなぁと考えます。

Apacheなら、VirtualHostとかにしてSNIで該当するVirtualHostに誘導し、SNIでVirtualHostが存在しない通信はDefaulltのVirtualHostのconfに飛ばす、Defaulltのconfは403を返すようにする。
AWSのALBであれば、リスナールールでHostヘッダをチェックしターゲットへ転送。ホストヘッダがマッチしない場合は固定レスポンスで403を返してしまう。


色々と試してやりましたが、もしかしたら間違っているかもしれません。
間違っているところがあれば指摘をもらえるとうれしいです。