テクノロジー

pixivを常時HTTPS化するまでの道のり(前編)

catatsuy
2017.6.13
シェア
ツイート
ブックマーク

ピクシブ株式会社で開発基盤チームとして働いている @catatsuy です。主にpixivの技術的な改善をしていますが、広告チームも兼任しているので広告周りの開発もしています。

今回pixivの常時HTTPS化を担当したのでやったことを紹介します。

pixivをHTTPS化した理由

現在のインターネット全体の流れとして常時HTTPS化が進んでいます。エドワード・スノーデン - Wikipediaが暴露したNSAの事件発覚や 公衆無線LANの利用拡大により、通信経路上でユーザーの個人情報を保護することがインターネット全体として非常に重要になってきました。Googleが行っている調査によると、HTTPSページの閲覧時間はウェブ全体の利用時間の3分の2にも及びます。

それだけではありません。ブラウザに新しく追加されるAPIや機能(HTTP2/WebRTC/ServiceWorkerなど)はHTTPSで使用することが前提となっています。そのためHTTPのままではユーザーに提供できる機能が制限されてしまいます。 また、GoogleはHTTPSページを優先する方針を打ち出しているため、将来的にSEOに影響しかねない点も見逃せません。ブラウザから危険なサイトという表示になるのも時間の問題です。HTTPSでないサイトに対してユーザーが不信感を覚える日もそう遠くはないでしょう。

ピクシブ社内でも2013年にリリースされたBOOTHをはじめとした新規サービスは、リリース当初から常時HTTPSで提供していました。2012年リリースの pixivコミックは途中から常時HTTPSに移行しました。また、pixivコミックの姉妹サービスであるpixivノベルも、最初から常時HTTPSで提供しています。

このように社内でもすでに多くのサービスが常時HTTPSで提供されています。しかしメインサービスであるpixivではログインページなどセキュリティ的に重要な情報を扱うページのみHTTPSで、それ以外のページはすべてHTTPで提供してきました。 これまでいくつかの事情で常時HTTPS化に踏み切れていませんでしたが、それらの事情が払拭されたため常時HTTPS化に踏み切ることができました。

前編では常時HTTPS化に踏み切るに至った背景や、実際に行った作業などを紹介していきます。

HTTPS化に向けてやること

HTTPS化に向けて必要な変更は、ザックリと下記の4点が挙げられます。

  1. 開発環境でHTTPSを利用できるようにする
  2. ページで読み込んでいるすべてのリソースをHTTPSで配信できるようにする
    • 配信広告
    • 静的コンテンツ(CSS、スクリプト、画像など)
    • 画像コンテンツ
    • 自社配信広告
  3. アプリケーションが返すURLをHTTPSに順次切り替える
  4. アプリケーション自体をHTTPSで配信するようにする

HTTPS化というと『URLのhttpをhttpsに置換するだけでは?』と考える方もいるでしょう。アプリケーションのソースコード修正のみを考えればあながち間違いとは言えません。実際それでほぼ完了するサービスも多いでしょう。

しかしpixivのようなコードベースが巨大かつ多くのユーザーを抱えるサービスでは単純な置換のみでは対応できません。今回は具体的にどのような作業をし、どのような問題が起こったのか紹介していきます。

ちなみにpixivの常時HTTPS化は私と当時の新卒エンジニアの2人で担当しました。作業は2017年1月から開始し、touch.pixiv.netは2017年3月21日に完了、www.pixiv.netは2017年4月18日に完了しました。実に4ヶ月に及ぶ戦いでした。 中心となって作業を行ったのは2人でしたが、pixivの常時HTTPS化は会社全体を巻き込んだ大プロジェクトであるため、常時HTTPS化のために多くの社員の力を借りました。全員が常時HTTPS化の必要性を理解しポジティブに協力してくれたことが、大変ありがたかったです。

開発環境の整備

pixivの開発には共用の開発サーバーを利用しています。この環境では、開発者が独立したドメイン名を持った開発環境を、容易に構築できるようになっています。常時HTTPS化の作業よりも前にワイルドカード証明書を導入していたため、既に開発環境でもHTTPSを利用できるようになっていました。

HTTPSで配信できるようにする

配信広告のHTTPS対応

pixivのHTTPS化で一番重要なのは広告タグのHTTPS化でした。実は数年前にもpixivの常時HTTPS化を検討したことはありましたが、当時はHTTPS非対応の広告配信事業者が多く、使用している広告配信事業者が仮に対応していたとしても、その接続先の事業者まで含めると多くの事業者が対応していないという状況があり、断念してきました。 今回の作業時にはほぼすべての事業者がHTTPSでの配信に対応していたため、常時HTTPS化に踏み切ることが出来ました。

弊社の広告は自社で運用している社内広告サーバーから配信しているものと、ソースコード内に直接貼っているものがあります。 社内広告サーバーから配信しているものは、社内の管理画面からHTTPSに対応した広告タグに差し替える必要があります。ソースコード内に直接貼られているものは、広告タグを直接変更してデプロイする必要があります。

またHTTPSでは、HTTPに比べオーバーヘッドがあるため、収益に影響が出る可能性があります。そこで広告の運用を行っているマーケティング部と連携しながら、収益への影響を監視しつつ、広告タグのHTTPSへの差し替えを進めました。

詳しくは後述しますが、一部のアドネットワーク経由でHTTPの広告が配信されたときに、常時HTTPS化によりJavaScriptが実行できずにインプレッション数が減ってしまう問題があります。 それにより一部のインプレッションを落としてしまう問題がありましたが、最終的に収益への大きな影響は見られませんでした。2017年現在では常時HTTPS化ができない理由として配信広告を挙げることは、もはやできないでしょう。

静的コンテンツ配信のHTTPS対応

pixivではHTTPサーバーとしてnginxを様々な用途で使用しています。画像・CSS・JSなどの静的コンテンツも、CDNを利用せずnginxでキャッシュし配信しています。 いずれもnginxでキャッシュを保持し、キャッシュがあるコンテンツについてはすべてキャッシュから配信し、オリジナルサーバーの負荷を下げる構成になっています。

nginxのキャッシュで気を付けるべき点はキャッシュの有無に使用するキーの設定です。httpとhttpsで同じコンテンツを返すサーバーをnginx上で設定しようと考えてみます。 nginxのドキュメントによるとproxy_cache_keyのデフォルトは$scheme$proxy_host$uri$is_args$args;です。$schemeが含まれているためキャッシュのキーにhttphttpsが含まれています。 これだとURLをhttpsに変更したときにキャッシュがないと判断されるため、このままではオリジナルサーバーにアクセスが集中することになります。 httphttpsで同じコンテンツを返すサーバーであれば、proxy_cache_key$schemeは含まない方が良いでしょう。

pixivのサーバーは以上の理由により、常時HTTPS化を行う以前からproxy_cache_key$schemeは含まれていませんでした。そのためURLをHTTPSに変更してもキャッシュが消える心配はありませんでした。 しかしHTTPS化によりユーザーのブラウザ上のキャッシュが使えなくなるため、変えた後しばらくの間、配信サーバーの通信・負荷が増えることは避けられません。 またユーザーのキャッシュを極力活用できるようにするために、完全にランダムでHTTPかHTTPSかを返すよりも、ファイル毎にHTTPSへのURL変更を進めていく方が好ましいでしょう。その方がサーバーの不要な負荷・通信量の削減にもなります。

静的コンテンツ配信サーバーのURLの変更は置換でどんどん行いましたが、pixivの一部のページで以下のような興味深いコードが複数あったので紹介します。

このコードは見覚えのある方が多いかもしれませんが、これはHTML5に対応していないIE8以下のブラウザのために、HTML5で追加されたタグに対応するためのコードです。 既にGoogle Codeは終了しているため有効ではないURLですが、IE8以下でしか実行されないために、動いてないことを気付かれずにそのままになっていました。 pixivでは既にIE8以下はサポートしていないので、これを機に該当するコードをすべて削除しました。 このケースは後編で紹介するCSPで発見できないmixed contentsになるコードなので印象的でした。

画像配信のHTTPS対応

pixivには投稿されたイラストの他に、背景画像・小説のカバー画像・プロフィール画像など実に様々な画像を投稿できます。それぞれが別のコードでURLを組み立てていたためすべてのコードに手を入れる必要がありました。

自社広告配信のHTTPS対応

自社で運用している広告配信サーバーはCPUが強くなかったため、HTTPSによる暗号化の負荷に耐えられませんでした。 加えて、広告配信サーバーはDebian7(wheezy)で構築されていました。既に2017/06中にDebian9(stretch)のリリースが予定されているため、Debian7のサポートは近いうちに止まってしまいます。 このままではセキュリティアップデートもできず、新しいサーバーの構築もできないという状況になります。 しかも移転予定の新しいサーバーでLinuxカーネルのバージョンが古いDebian7を使用すると、不具合が発生することが社内で確認されていました。 そこで今回のサーバー移転を機にDebian8(jessie)への移行を行いました。広告配信サーバーではGoとRubyが使われており、OSに依存した設定が少なかったことで比較的容易に移転することが出来ました。

サーバー移転時に重要なことはx86命令セットの拡張機能であるAES-NIに対応しているかどうか確認することです。 SSLの暗号化・復号化を行うOpenSSLはAES-NIに対応しているため、AES-NIに対応したCPUで動かすことで低いCPU負荷で高速にSSLの暗号化・復号化を行えるようになります。 最近のCPUであればまず対応していますが、BIOSの省電力設定で無効化されていることがあるので注意が必要です。 Linuxではcat /proc/cpuinfoをすると確認できます。本番投入する前に必ず確認しましょう。広告配信サーバーでは事前に問題無いことを確認してから投入を行いました。

HTTPSに順次切り替える

常時HTTPS化にあたって、画像・CSS・JSなど読み込むリソースは例外なくすべてHTTPSに変更する必要があります。配信広告以外をどう書き換えるべきか紹介します。

Mixed contentsについて

mixed contentsについて紹介します。詳しくは以下のURLを参照してください。

混合コンテンツとは | Web | Google Developers

簡単に解説すると、mixed contentsはHTTPSのサイト上でHTTPのリソースを読み込んだ時に発生します。折角ページをHTTPSにしても、HTTPのリソースを1つでも読み込んでしまうとセキュリティレベルが低下します。ブラウザ上の表示も変わりユーザーに不信感を与えてしまうため、できる限りなくすことが非常に重要です。

mixed contentsには2種類あります。Passive mixed contentとActive mixed contentです。

Passive mixed contentはHTTPSのページの中でHTTPの画像などを読み込んだ時に発生します。ブラウザにより表示は異なりますが、多くの場合このケースでは画像自体は読み込まれます。しかしHTTPSなら安全なサイトであるという表示になるはずですが、その表示がなくなって安全ではないサイトという表示になります。

passive mixed content

気を付けなければならないのは、pixivでは一部の画像にreferrer制限をかけています。HTTPSからHTTPへはreferrerが送られません。referrer制限がかかっているHTTPの画像をHTTPS上で読み込んだ場合、mixed contentsになり、かつ画像が表示されないという状況になります。イラストSNSとして致命的な状況にもなり得るので絶対に避けなければなりません。

Active mixed contentはHTTPSのページの中でHTTPのJavaScriptやCSSやiframeなどを読み込んだ時に発生します。 Active mixed contentの場合、コードは実行されません。ブラウザにより表示は異なりますが、赤い×などが表示され、ユーザーから見るとセキュリティ的に問題のあるサイトという表示になります。

active mixed content

HTTPSの配信広告タグを使用しているにも関わらず、アドネットワーク経由でHTTPの広告タグが読み込まれることがあります。その場合Active mixed contentになるため、コードは実行されず、インプレッション数がその分減ってしまいます。

少しややこしいですが、Passive mixed contentとActive mixed contentには細かい挙動の違いがあるのでHTTPS化をやる場合はしっかり覚えておきましょう。

HTTPSとフィーチャーフォン

mixed contentsを撲滅するために、どんどんソースコードを書き換えていきます。その前にpixivのフィーチャーフォン版について言及します。

pixivはpixiv.gitというリポジトリで管理されています。pixiv.gitではpixiv-libと呼ばれる共通ライブラリを使用しています。画像のURL生成ロジックなどはそのpixiv-libが担当しています。 pixivは小説のみ、フィーチャーフォン版(m.pixiv.net)が存在しています。フィーチャーフォンでは端末に内蔵されているルート証明書が一般的なPCやスマートフォンよりも少なかったり、SHA256の証明書に対応していなかったりします。 既にセキュリティ的に脆弱であることが分かっているSHA-1の証明書を発行する手段はありませんし、pixivもSHA256の証明書にしか対応していません。 現在では新しいフィーチャーフォンを入手することも難しいため、今もフィーチャーフォンを使っているユーザーは非常に古い端末を使い続けている可能性があります。 そのためフィーチャーフォンで使用されている画像URLなどをHTTPSに書き換えると動作しなくなる端末があるでしょう。そのためpixiv-lib側で安易にすべてのURLをHTTPSに変更しないようにする必要がありました。

また以上の理由からフィーチャーフォン版をHTTPS化する予定はありません。

DBに保存されている画像URL変更

pixivのお知らせなどで画像を貼ることがよくあります。そういった社内でアップローダーとして使われてきたURLのHTTPS化を行う必要がありました。 これらのお知らせはデータベース上にURLがそのまま保存されていました。データベースのレコード数はそこまで多くなかったので、URLをHTTPSでも読み込めるように変更した上で、SQLのLIKE演算子を使用して抜け漏れがないか探しながら、MySQLのREPLACE文を打つことでURLの一斉置換を行いました。

また今後追加されるお知らせもHTTPSで配信されるように、管理画面上に表示されるURLをHTTPSに変更するなどの対応も行いました。

広告ロジックの修正

これまでpixivではセキュリティ的に重要なページのみがHTTPSで、それ以外はすべてHTTPで提供してきました。そのため昔からHTTPSが使用されているページ(ログイン・パスワード変更など)はセキュリティ的に重要なページのため、これまで外部のスクリプトは読み込まないポリシーでした。 そのことを利用してHTTPSならば広告を非表示にする、というロジックがpixivのコード内に存在していました。以前はそれで十分でしたが、これからHTTPS化を行うに辺り、広告が出るべきページで広告が出ないという問題が発生します。 そこでpixiv側の実装を見直し、ログインページなどセキュリティ的に重要なページは外部JS実行不可ページリスト、コンテストやpixivFANBOXなど広告を表示するべきでないページを広告非表示ページリストとしてそれぞれ保持し、HTTPSかどうかには依存しないロジックに変更しました。

他社のスクリプトの読み込み

pixivは配信広告以外にも多くの他社のスクリプトに依存しています。Google Analyticsを読み込んでいないWebサービスはほとんどないでしょう。TwitterやFacebookなどSNSのシェアボタンもあります。 それらの読み込んでいるスクリプトがすべてHTTPSに対応しているわけではありません。

pixivは中国のユーザーも多く抱えるサービスです。しかし中国のサービスはHTTPSに対応していないことが多く、シェアボタンもHTTPSに対応していないサービスがありました。 たまたまでしたが、SNSボタンのUIを統一するためにSNSのシェアボタンをリンクにする話が社内で進行していたため、その時にリンクにして外部のスクリプトの依存を外す対応をしました。

他にもHTTPSに対応していない動画サービスの埋め込みを利用している箇所があったため、リンクにしたり、どうしても埋め込みたい場合はHTTPSに対応しているYouTubeにアップロードし直すことで対応できました。

前編まとめ

今まで長々と書いてきましたが、ここまではすべてpixivをHTTPS化するための前準備にすぎません。後編で実際にpixivをどうHTTPS化したか、どういうトラブルが起こったのかを紹介していきます。

また2017年6月21日に弊社オフィスで大規模HTTPS導入Nightを開催いたします。このエントリーの内容に興味のある方におすすめです。

HTTPS化についてヤフー・クックパッド・ピクシブが語る! - 大規模HTTPS導入Night - connpass

福岡中継! HTTPS化についてヤフー・クックパッド・ピクシブが語る!大規模HTTPS導入Night - connpass

後編はこちら

https://inside.pixiv.blog/catatsuy/1872

シェア
ツイート
ブックマーク