t-hom’s diary

主にVBAネタを扱っているブログです。

はてなブログ(このサイト)を常時SSL化したので備忘録

本日このブログを常時SSL化したので、備忘録も兼ねてここに記しておく。
切り替えそのものはダッシュボードから簡単にできるのでまぁ簡単。
問題はその後。

まぁただ、以下の広野さんの記事を読んで、面倒な後処理が発生することは想定内ではあった。心の準備ができたので感謝!
www.mayoinu.com

目次

SSLとは

SSLとは、Secure Socket Layerの略で、暗号通信に使われる技術のことだ。
これをWebサイトの配信に用いたものがhttps。最後のエスがセキュアであることを示す。

これまでの常識では、単に情報を発信するページは暗号化されていないhttpで行い、訪問者にフォーム入力させるようなページ(とりわけクレジットカード番号や個人情報など)では、そのページだけSSLに対応したhttpsで通信するのがセオリーだった。

しかし米国NSAがhttpの性質を利用して、本来無害なサイトへのアクセスを改ざんしてスパイプログラムをインストールさせているという事実がエドワード・スノーデン氏により暴露され、以降は単に情報を発信するだけのサイトであっても全てのページをhttpsで通信させる方法(常時SSL)が常識化しつつある。

アドレスバー表示について

サイトがhttpsに対応して通信が暗号化されているとき、ブラウザのアドレスバーがそれぞれ次のように変化する。

Google Chromeのアドレスバー表示

通信が保護されている場合
f:id:t-hom:20180707200005p:plain

通信が保護されていない場合
f:id:t-hom:20180707204326p:plain

Microsoft Edgeのアドレスバー表示

通信が保護されている場合
f:id:t-hom:20180707200041p:plain

通信が保護されていない場合
f:id:t-hom:20180707204537p:plain

このように、ブラウザによってどちらを明示的に表示させるかが違うので、SSL通信が上手くいってるかどうかは自分のブラウザのバージョンや仕様を確認したうえで判断が必要となる。

混在コンテンツについて

サイト本体がhttpsで暗号化されているとき、画像やCSSJavascriptなど、ページのパーツとして同時に読み込まれる資源へのアクセスがhttpだと、保護されていない通信という扱いになってしまう。

これらの資源はページ本体をリクエストした際にサブリクエストで同時にダウンロードされるため、資源への通信がhttp通信だと折角ページ本体をhttpsで通信していても暗号化されていない通信が混じってしまう。
これを混在コンテンツ(Mixed-Contents)といい、ブラウザによっては通信が保護されていないと表示されてしまう(あるいは保護された通信と表示されない)。

単なる他ページへのリンクがhttpになっている分には問題ない。なぜならそれは資源ではないので、同時に読み込まれることはないから。
ただし常時SSL化の流れが加速すれば、将来ブラウザでHTTPサイトへのリンクをクリックした際に警告が表示されるなんてことになるだろうと私は予測している。

はてなブログ全体のhttps化

冒頭で述べたように、まずはダッシュボードの詳細設定で切り替えるだけ。ただし元のhttpには戻せないので注意。

それからデザインでサイドバー等に資源リンクがあればhttpをhttpsに書き換えるか、http:を消す必要がある。まぁ自分でカスタマイズした方であればそのあたりは大丈夫かと思う。HTMLタグだと単純にhttp:を消して//からアドレスを始めればサイトと同じ方式で通信してくれるので便利。※はてな記法でこの方法が使えないのが残念。

個別の記事のhttps化

これが一番大変。上手く行かないパターンは2つある。

保護されていない通信になるパターン

Amazon等のリンクや古い記事の画像等がうまくhttps化されてない。
ただ通常は画像やAmazonリンクの張替えまでは不要で、ページを編集して保存するだけで大抵の場合は直る。
編集といっても何も変更する必要はないのだが、それだと保存できないので、適当な場所に半角スペースでも入れて、更新ボタンが有効になったらスペースを消して更新すれば良い。

稀にAmazonリンクで古い商品を指してる場合はこれで治らないので最新の商品リンクを探してきて張り替える。

埋め込み資源が空白になるパターン

過去記事や他のブログを埋め込みリンクにしてる場合、資源としてサムネなどを取りに行くのでそこはhttpのままになっている。
Microsoft Edgeで試したところ、セキュリティ保護は問題なかったけど埋め込みコンテンツが取得できておらず真っ白。
つまり、http通信部分をカットしてるからセキュリティ保護が問題ないだけ。

自分の過去記事も含めて真っ白なので残念。
埋め込みコンテンツの中身をちゃんと表示させようと思ったら、httpsに書き換えていかないといけない。

埋め込む相手がhttps対応してない場合は?

試したところ、埋め込むコンテンツがはてなブログの場合は、対象のブログがhttps化されてなくても、httpsと書いて大丈夫っぽい。
それ以外の場合は逐一httpsに対応してるかどうか調べて対応させていったけれど、httpしか無いコンテンツは変更できない。でもなぜかそれは書き換えなくても表示が上手く行ってるので謎。

Mixed-Contentsが存在する個別記事をスクリプトで探す方法

全ページ開いて。。なんてやってられない。
以下のサイトで良さげなスクリプトが紹介されているのでこれを活用させていだいた。
tech.innovation.co.jp

ただこのサイト、ソースコードが画像になっててとても残念。。
コピペできるようにこちらに引用再掲させていただく。
これをerror_scan.jsというファイル名でc:\workなど分かりやすいところに保存しておく。
※私の場合はe:\scriptに置いた。

//出典:https://tech.innovation.co.jp/2017/09/17/mixed-content-checker.html
var system = require('system');
var url = system.args[1];
 
if (!/^https?:\/\//.test(url)) {
	console.log( 'URLを指定して下さい');
	phantom.exit();
}

var page = require('webpage').create();

page.onResourceRequested = function(request) {
	if (request.url.substr(0, 8) !== 'https://'
      && request.url.substr(0, 5) !== 'data:') {
        console.log('[mixed content]', request.url);
    }
};

page.open(url, function(status) {
    phantom.exit();
});

次にこれを使うためにはPhantomJSというツールが必要。
PhantomJSを使うと、コマンドでWebコンテンツにアクセスできるようになるので、以下のサイトからまずこれを入手して任意のパスに解凍しておく。
http://phantomjs.org/download.html

PhantomJSのbinがあるフォルダを環境変数Pathに登録しておく。
f:id:t-hom:20180707213623p:plain

次にコマンドプロンプトでerror_scan.jsを保存したフォルダに移動し、
「phantomjs error_scan.js チェックしたいURL」とコマンドを打つ。
f:id:t-hom:20180707214011p:plain

上のように、mixed-contentsと表示されていたらHTTPS通信できてない資源があるということ。
問題ない時は何も表示されない。

次に、先ほど紹介したサイトにはPythonでSitemap.xmlを解読しつつ全ページスキャンするコードも書かれている。
こちらも画像なので、テキストで引用させていただく。
このスクリプトはchecker.pyというファイル名でerror_scan.jsと同じフォルダに入れておく。

# 出典:https://tech.innovation.co.jp/2017/09/17/mixed-content-checker.html
import re
import sys
import ssl
import subprocess
import urllib.request
from bs4 import BeautifulSoup

def getMixedContentError(url):
    msg = ""
    result = subprocess.getoutput("phantomjs error_scan.js " + url)
    for line in result.split("\n"):
        if ("[mixed content]" in line):
            msg += line + "\n"
    return msg

ssl._create_default_https_context = ssl._create_unverified_context
sitemap_url = sys.argv[1]

sitemap = urllib.request.urlopen(sitemap_url).read()
soup = BeautifulSoup(sitemap)

for url in soup.findAll("loc"):
    errorMessage = getMixedContentError(url.text)
    if (errorMessage):
        print("x " + url.text)
        print(errorMessage)
    else:
        print("v " + url.text)

Pythonのインストール方法はググっていただくとして、このスクリプトを使うにはbs4というライブラリをインストールする必要がある。
Python3.4以降に同梱されているpipというツールを使ってインストールするけど、Pythonをインストールしただけではpipにパスが通ってなかったので、環境変数にパスを追加しても良いけど、とりあえずpipのあるパスで実行することにした。

whereコマンドでPythonの場所を調べ、そこのScriptsフォルダに移動し、「pip install bs4」を実行。
f:id:t-hom:20180707215350p:plain

これでPythonスクリプトの方も実行できるようになった。

実行するにはコマンドプロンプトでchecker.pyを保存したパスに移動し、
python checker.py サイトマップのURL」を実行する。
f:id:t-hom:20180707215838p:plain

はてなブログサイトマップは「ブログURL/sitemap.xml」にある。
例えばこのブログなら、https://thom.hateblo.jp/sitemap.xml

そのxmlに更にページ番号がついたサイトマップが記載されており、実際にはこのページ番号付きのサイトマップをcheckr.pyに引き渡すことになる。
1ページ目はこんな感じ。
python checker.py https://thom.hateblo.jp/sitemap.xml?page=1

暫く待ってればpage1の中の全URLがチェックされるので、コマンド結果をコピペしてエディタに張り付ける。

f:id:t-hom:20180707220444p:plain
先頭にvと付いたURLは問題なかったということ。
先頭にxと付いたURLは混在コンテンツなので要修正。
Mixed-Contentsと表示されているものはページ内で具体的にどれがhttp通信なのかを表示している。

余談だけど、EmEditor(エムエディタ)だと、リンククリックでそのままページを開けるので楽。
また一度開くと赤くマークされるので完了チェックリストとしても使える。

修正が終わったら、サイトマップの次のページのURLをchecker.pyに引き渡して実行する。
python checker.py https://thom.hateblo.jp/sitemap.xml?page=2

これの繰り返し。
ものすごく面倒くさかったけどまぁなんとか全ページSSL化完了した。

7/18追記

私は記事のMixed-Contentsの洗い出しまでをスクリプトでやったけれど、以下のブログ記事ではスクリプトによる記事の更新について書かれていて、更にスマートに作業できそう。
blog.jnito.com

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。