LoginSignup
1
2

More than 5 years have passed since last update.

常時SSL化の対応状況を調べるスクリプトを書いてみた

Last updated at Posted at 2018-07-30

背景

7月24日にGoogle Chrome 68がリリースされ、HTTPSでないサイトには警告が出るようになった。

自分の会社サイトでは、2016年12月から検証開始→2017年4月にHSTS Preloadまで設定完了、としていたので、
今回のChrome 68リリースでは高みの見物をしていたのだけれど、警告があまり目立たないのか意外と騒がれずちょっとがっかり。

私の会社の競合他社で今回SSLに対応したところは皆無だったのだが、
逆に「今後どのタイミングでSSL化するのだろう?」と下世話な興味が湧いたので、
ウェブサイトの常時SSL化対応状況を調べるスクリプトを作ってみた。

作ったもの

概要

他社サイトのHTTPS対応状況を調べてみると、
対応していないサイトではだいたい下記のパターンになることがわかった。

  • HTTPS通信ができない
    • HTTPSのポート(443/tcp)が空いてない
    • 443ポートは開いてるけど、まともに応答しない
  • 証明書がおかしい
    • 自己署名証明書を使っている
    • 証明書の期限が切れている
    • SAN(Subject Alternative Name)が入っていない
  • 常時SSLのための対応が不足
    • HTTPページからHTTPSページへリダイレクトされていない
    • HSTSヘッダがない
    • HSTS Preloadに登録していない

なので、上記の点についてチェックする仕様とした。

トラストチェーンが正しいかの検証を行うのと、Mixed Contentsが含まれていないかの判定は
コマンドで簡単にはできそうじゃなかったので割愛。

Qualys SSL Labstestssl.shなどを使ってください。
(testssl.shのウェブサイトのSSL証明書の期限が切れてる!(笑))

スクリプト

check_https.sh
#!/bin/bash

hstspreload=`mktemp`
curl https://cs.chromium.org/codesearch/f/chromium/src/net/http/transport_security_state_static.json -s -o $hstspreload
trap 'rm $hstspreload' EXIT

if [ -p /dev/stdin ]; then
    cat -
else
    echo $@ | sed -E 's/\s+/\n/g'
fi | while read domain; do
  echo "${domain}"
  if nmap -p 443 $domain | grep -q "443/tcp open  https"; then
    echo "  Port 443: Open"
  else
    echo "  Port 443: Closed"
    continue
  fi

  cert=`mktemp`
  openssl s_client -connect $domain:443 -servername $domain < /dev/null 2>/dev/null | openssl x509 -text >$cert 2>/dev/null
  if [ "$?" -eq "0" ]; then
    issuer=`grep "Issuer:" $cert | sed -e 's/^\s\+Issuer:\s\+//'`
    subject=`grep "Subject:" $cert | sed -e 's/^\s\+Subject:\s\+//'`
    if [ "$issuer" = "$subject" ]; then
      echo "    Issuer: Self Singed (Not OK)"
    else
      echo "    Issuer: "$issuer
    fi

    startdate=`grep "Not Before:" $cert | sed -e 's/^\s\+Not Before://' | date -f - '+%s'`
    enddate=`grep "Not After :" $cert | sed -e 's/^\s\+Not After ://' | date -f - '+%s'`
    today=`date '+%s'`

    if [ $today -gt $startdate -a $enddate -gt $today ]; then
      echo "    Date: Valid"
    else
      echo "    Date: Expired"
    fi

    sancheck=`mktemp`
    echo "  SAN: Not OK" > $sancheck
    grep -A1 "Subject Alternative Name" $cert | sed -e '1,1d' | sed -E 's/\s+DNS://g' | sed -E 's/,/\n/g' | while read i; do
      pattern='^'`echo $i | sed -e 's/\./\\\./g' | sed -e 's/\*/[^.]\\\+\\\?/g'`'$'
      if echo $domain | grep -q -e $pattern; then
        echo "  SAN: OK" > $sancheck
        break
      fi
    done
    cat $sancheck
    rm $sancheck

    rm $cert
  else
    echo "  No SSL Certificates"
    rm $cert
    continue
  fi

  if curl --head http://$domain 2>/dev/null | grep -q "Location: https://$domain"; then
    echo "  HTTPS Redirect: Enabled"
  else
    echo "  HTTPS Redirect: Disabled"
  fi

  hsts=`curl --head https://$domain 2>/dev/null | grep -i "strict-transport-security: "`
  if [ "$hsts" != "" ]; then
    echo "  HSTS: Enabled"
    if grep -q `echo $domain | sed -e 's/\www\.//'` $hstspreload; then
      echo "    HSTS Preload: Enabled"
    else
      echo "    HSTS Preload: Disabled"
    fi
  else
    echo "  HSTS: Disabled"
  fi
done

使い方

スクリプトの引数に調べたいドメインを並べてください。

./check_https.sh (調べたいドメイン1) (調べたいドメイン2)...

もしくは、別ファイルにドメインのリストを作っておき、パイプでつなげます。

domains.txt
www.cao.go.jp
www.kunaicho.go.jp
www.mof.go.jp
www.moj.go.jp
www.soumu.go.jp
cio.go.jp
cat domains.txt | ./check_https.sh

このやり方は標準入力を受け取れるシェルスクリプト、関数の作成(パイプで繋げられるようにする)を参考にしました。

上記サンプルでは政府のサイトをダミーで入れてます。

HSTS Preloadに登録済みのサイトを調べるため、
毎回6MB程度のファイルをChromiumのリポジトリからダウンロードするので、
ネットワークが細いところではご注意を。
あとwww.以外のサブドメインではHSTS Preloadに含まれているか正しく判定できません。

相手サーバに対して行儀の悪いことはしていない(443ポートが開いてるかのチェックと、証明書とHTTPヘッダのダウンロードのみ)ので、1日1回チェックする程度であれば問題ないと思うのだけれど、もし問題であれば消します。

出力例

出力は以下のような感じ。

  • 443ポートが開いているか
  • 証明書のIssuer (Self Signedか、そうでなければ認証局)
  • 証明書の期限が切れていないか
  • 証明書のSANに自分のサーバのFQDNが入っているか(ワイルドカードにも一応対応)
  • HTTPSへのリダイレクトが行われているか
  • HSTSヘッダは出力されているか
  • HSTS Preloadに登録されているか

を順に調べます。

上記のdomains.txtにある政府系のサイトを調べた結果は以下のような感じ。

www.cao.go.jp
    Port 443: Closed
www.kunaicho.go.jp
    Port 443: Open
    Issuer: C = JP, O = Japanese Government, OU = GPKI, CN = ApplicationCA2 Sub
    Date: Valid
    SAN: OK
    HTTPS Redirect: Disabled
    HSTS: Disabled
www.mof.go.jp
    Port 443: Open
    Issuer: C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
    Date: Valid
    SAN: OK
    HTTPS Redirect: Enabled
    HSTS: Disabled
www.moj.go.jp
    Port 443: Open
    Issuer: C = JP, O = Japanese Government, OU = GPKI, CN = ApplicationCA2 Sub
    Date: Valid
    SAN: OK
    HTTPS Redirect: Disabled
    HSTS: Disabled
www.soumu.go.jp
    Port 443: Open
    Issuer: C = JP, O = Japanese Government, OU = GPKI, CN = ApplicationCA2 Sub
    Date: Valid
    SAN: OK
    HTTPS Redirect: Disabled
    HSTS: Disabled
cio.go.jp
    Port 443: Open
    Issuer: C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Domain Validation Secure Server CA
    Date: Valid
    SAN: OK
    HTTPS Redirect: Enabled
    HSTS: Enabled
    HSTS Preload: Enabled

感想

この記事を書いている2018年7月30日現在、政府系のウェブサイト(.go.jp)で、HSTSのプリロードまで対応しているのは2件だけ。
マイナポータルは知ってたけれど、政府CIOポータルというサイトは初めて知った。

HSTS Preload対応かどうかはブラウザのソースコードにハードコーディングされているのだけれど、
今後対応サイトが増加していったらどうするのだろう?

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2