2015年5月7日木曜日

【修正されたバグ】サイトが非SSL、管理画面がSSL(/wp-admin/ 以下)の場合、メディア追加するとリンクがSSLに強制設定されてしまう

本件は、WordPress 4.2からのバグで、4.2.2で修正されています(5月7日)。
これに気づけず、フックを使ってあーでもない、こーでもないと修正してたんですが(末尾の付録参照)、勝手にリアルタイムで直ったので「アレレ??」って思ったんですよね。

今後も同じようなことが起こりそうなので、備忘録として残しておきます。

何が起こった?!


突然、独自ドメインに構築したWordPress上の「メディア」を使って追加した添付ファイルをダウンロードしようとすると、

---
この Web サイトのセキュリティ証明書には問題があります。
  (中略)
セキュリティ証明書の問題によって、詐欺や、お使いのコンピューターからサー
バーに送信される情報を盗み取る意図が示唆されている場合があります。
  (以下省略)
---

と「Internet ExplorerやChromeがいってきたけど、どういうこと?!」
って問い合わせが来たんですよね。

管理画面のみSSL暗号化(https:// アクセス)にしていて、SSL証明書に、オレオレ証明書(自己証明書)を使っている場合に起こる問題です。


つまり管理画面にアクセスできる人は限定的であり、警告がでても信用せよというか、自己証明書を認証してもらうようにPCに個別インストールしているケースは結構あると思います。

しかし、サイト閲覧者はそんなのしていないので、自己証明書を利用したhttps:// へのアクセスは、上記のような警告がでるようになったのです(最近のブラウザは特に警告が派手になりつつある)。

さらにWordPress 4.0からは、ログインのみSSL化して管理画面は非SSL「define('FORCE_SSL_LOGIN', true);」にすることが出来なくなりました
現在、FORCE_SSL_LOGINは、FORCE_SSL_ADMIN設定と同一になってます。

ですので、ログインのみSSLにしている人は、実際はログイン&管理画面がSSLになっちゃってるんですよね。

もう修正されちゃったのですが、この解決策はログインのみGoogle認証など外部認証を使って、あとは非SSL(http://)にしちゃうという短絡的なものもあります。ただお問い合わせデータなど個人情報が保存されていることを考えると、安易にそれはなぁと悩みました。

修正

に掲載されているリリースノートの「Summary」の一番最後
  • Fixes a bug where attachment URLs were incorrectly being forced to use https in some contexts
のバグです。深刻なセキュリティ問題もあるのでアップデートしておきましょう。

で、このバグ修正については
  • #32112(wp_get_attachment_url returns https when it should not)
で指摘されていて、これをみて解決されたのかなと思います。
この26コメント目に、
  • 添付ファイルのURLをSSL化するのは、サイトがSSL化しているときに限定すべきだ
といっていて、これが4.2.2に反映された(changeset#31614)ってことですね。


なんでこんなことになった!!

事の発端は、#15928(wp_get_attachment_url does not check for HTTPS)に遡ってますね。
  • サイトをSSL化(https://)したときに、記事への添付URLが http://のままじゃないか、それは困るよ〜
ってことだったようです(超意訳)。
具体的には、wp_get_attachement_url関数が、siteurl(設定のサイトURL)を参照するので、これってサイト自体がSSLの場合、記事や固定ページなどにメディアを追加したら(wp_get_attachement_urlで、添付ファイルのURLが処理される)http:// から始まるURLになるので、サイト内で https:// と http://が混在してしまって困るってことですね。

だから、siteurlを参照する際に、SSLチェック(is_ssl関数)をして、SSLでアクセスしているなら、https:// をつけてはどうなの?

ってことで、WordPress 4.2で取り込まれたのですが、
このコメント97番目において、
  • サイトがSSL対応していて、siteurlがSSLでない(http://から始まる)場合に、添付URLをSSL化するよ(https://)
ってなことになっちゃったのが問題なのかなぁ。

いやまぁ、オレオレ証明書をつかってなければ上記で問題ないのです。
でもまぁそうできない事情もあるわけで(特に金銭的な)...

付録:これに気づくまでやったフック設定

ステップ1)添付ファイルのURLを強制変更しちゃう(functions.php)


function nossl_attachment_url( $url ) {
    $regex = '/^https:\/\//u';
    if ( preg_match( $regex, $url) ) {
        $url = str_replace('https://', 'http://', $url);
    }
    return $url;
}
add_filter( 'wp_get_attachment_url', 'nossl_attachment_url' );

超簡易なのですが、添付ファイルのURLを処理する、wp_get_attachement_urlに対して https:// から始まるURLを見つけたら、http:// に置換する

っていう感じです。
これでメディア管理画面や追加時のURLが、https:// から http:// に強制変更されました。

正規表現になる「/^https:\/\//u」は、 /正規表現/ となり末尾のuはUTF-8での処理を意味します。^https:\/\/ の ^ は先頭、\は、/はバックスペース(\)でエスケープしています。この意味は、/正規表現/と先頭と末尾に/を括るため、正規表現内に/が出てくると、そのまま書くとプログラム的に 末尾の / を探せません。 /◯◯/△△/ っと正規表現内に/がはいっちゃうと、正規表現が◯◯でおわっちゃいますよね?  末尾じゃないよ〜って教えてあげるのがエスケープ処理ってことになります。/◯◯\/△△/ なら、プログラムは、◯◯/△△ を見てくれるってことになります。

これで新規追加分は問題なくなりました。
いままでのやつは手動で変えると手間がかかるので、

※以下は、未検証


function nossl_posted_url( $data ) {
    $regex = '/(?:https:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/wp-content/uploads/([-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/u';
    $data['post_content'] = preg_replace($regex, 'http://' . "\\1" . '/wp-content/uploads/' . "\\2" , $data['post_content']);
    return $data;
}
add_filter( 'wp_insert_post_data', 'nossl_posted_url' );

あたりをいれて、https://◯◯/wp-content/uploads/△△ がコンテンツ内にあると、自動的にhttp://◯◯/wp-content/uploads/△△で表示する。

って感じです。[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+ は、
-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#のいずれかの文字が1つ以上続く場合になります。

まぁでも正規表現的にまだ弱いなぁとか、もうちょい試そうと思っていたら、WordPress 4.2.2が自動アップデートされていて、あれadd_filterを無効にしても直ってる!!ってなっちゃって、終了でした。

バグ修正したと明記されている以上、根をつめてやるのには時間もなくて...

ってな感じで、でも結構長くなったな....

2015年5月7日 @kimipooh



0 件のコメント:

コメントを投稿

Google+ Badge