読者です 読者をやめる 読者になる 読者になる

かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

WordPress 4.7, 4.7.1 はAPIに致命的なバグがあって認証無しで誰でも記事を改ざんできちゃうっぽい!

WordPress security

WordPress 4.7, 4.7.1 のサイトは直ぐに4.7.2にアップデートするのです!

Twitterで大学や国会議員や公的機関のサイトが大量に改ざんされてるという情報を朝から目にした日でした。

どうやら改ざんされていたのはWordPressのサイトの様で、事の顛末は、
WordPressはアップデートの際には何を修正したかを公開していたのですが、今回はWordPress 4.7.2で修正をしたバグが致命的なものだったために直ぐにセキュリティに関わるアップデートの内容を公開せずに1週間後に情報を公開したようです。( WordPress 4.7.2のリリースが1月26日、バグの情報が公開されたのが2月1日 )
そして、それ以降もWordPressをアップデートせずに、4.7、4.7.1のバージョンのままだったサイトが軒並みこのバグを利用されて記事を改ざんされていったと言うのが今回の件のようです。

今回の話題になってるバグとは?

特定のAPIのURLにPOSTでデータを送るだけで、WordPressのログインも認証もなしに投稿内容を更新することができてしまうというバグ…そしてバグの内容が公開されていて、少しググれば簡単に攻撃スクリプトが解ってしまうというくらい簡単なもの。
これはWordPress 4.7 で導入された投稿の取得や新規追加、更新を行うことができるREST APIに含まれていたバグ。なので、4.7より古いバージョンのサイトはこの攻撃で改ざんされないっぽい。古いのはあまり良くないけど、結果的に今回は良かったみたいな…

ローカル環境で試してみました。

WordPressのバージョンは管理画面 >ダッシュボードで確認ができます。 f:id:kikiki-kiki:20170206143252p:plain
※ ここが、4.74.7.1 の人はすぐにアップデートしましょう!

バグの具体的な内容はWordPress公式のリリースノートの記事や、そこにある報告者のリンク先の記事内に書かれています。
攻撃したいWordPressのサイトのAPIのURLに、改ざんしたい記事の投稿IDを紐付けて、データにタイトルと本文を持たせてPOSTするだけ。

なので、こんなサイトに…
f:id:kikiki-kiki:20170206150323p:plain
次のような公式の記事とかを参考に作った攻撃コード ( 調べればすぐ解りますがキーとか隠しておきます )
f:id:kikiki-kiki:20170206150202p:plain
これをリクエストすると…

f:id:kikiki-kiki:20170206150331p:plain
はい。認証も何もなしに記事を書き換えることができました。
このAPIを利用して記事を改ざんするとWordPress管理画面から見れる投稿のリビジョンでは、ユーザー名が表示されないようです。
f:id:kikiki-kiki:20170206151734p:plain

ね?簡単でしょ!?

_人人人人人人人人人人人人人人人_  
> 簡単でしょ!?じゃねーよ!!!! <  
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄  

試してみた所、HTMLタグも入れ放題なんですよ。
そして、攻撃に必要になる「WordPressの投稿ID」なのですが、デフォルトとか多くのテーマだとHTMLタグにid名やclass名で投稿IDが出力されています。
HTMLに出力されていなくてもRSSを利用している場合RSSに出力されているURLはパーマネントリンク設定で変更されたURLではなく?p=1の形式になっており投稿IDが丸わかりなのです…

このバグ
f:id:kikiki-kiki:20170206142825p:plain

はてなブックマーク - WordPress 4.7.1 の権限昇格脆弱性について検証した | 徳丸浩の日記
👆 コトの重大性に溢れたコメントが並んでいます。マジやばくね?

解決方法

こちらの記事にあるように、下記の方法を取ればこの致命的なバグには対応することができそうです。

  1. WordPressを最新の4.7.2にアップデートする
  2. ただちに最新版へアップデートすることが困難な場合、REST APIを無効化するプラグインを使用する

そして、可能な限りWordPressの自動更新をONにしておくのが良いのではないかと思いました。
しかし私の持っていたサイトの中には更新の通知が来ても実際には更新されなかったサイトもあったので自動更新機能を過信しすぎてもダメかもしれません。

改ざんされたサイトの対応

改ざんされた記事そのものはリビジョンから直ぐにもとに戻すことが可能です。
今回のAPIを利用した攻撃の場合、できても記事のタイトルと本文の更新のようなので記事内にスクリプトやiframe埋め込むことはできると思うのですが、サイトのテーマ自体にコードを追加したり、DBからデータを抜き取ったり、ログイン情報を取得したりとかは難しいのかな〜?と思っているのですが、これは私もハッキリとした事が言えないので、むしろ教えてほしい部分です!!

WordPressのような既に多くの人がコミットしているプロジェクトでもこんな重大な脆弱性が発生したりするんだなぁ〜って驚きました。
それより、WrodPressのサイトを持っている方は直ぐにチェックしてみることをオススメします。  
 
追記
REST APIのバグを利用しての改竄は観測している中ではISISを中傷する改竄が多かったのですが、中には「私はホワイトハッカーだ。君のサイトのWordPressアップデートした方が良いぞ。」と注意喚起のような記事を改ざんするハッカーも観られるようになってきました。
f:id:kikiki-kiki:20170206200127p:plain
まぁ いずれにせよ、改ざんされちゃってるわけですけどね。。。


[参考]

👇 徳丸 先生のありがた〜い本 👇

確定申告!

Book Blog

確定申告の季節です。
毎年、ナゼ毎月領収書を整理しておかなかったのだ!! と成長のない自分を責める季節でもあります。

私はフリーランスを初めてナンダカンダで10年くらいになっていました。
WEB・グラフィック制作やイベントの進行管理といった仕事の他に同人活動もしているの事もあり、業務内容が雑多で多岐にわたるので経費も雑多なものになるのですが、昔読んだ「フリーランスを代表して 申告と節税について教わってきました。」という本に書かれていた内容が青色申告になった今も役に立っています👇

2010年に読んで書いたレビューを貼っておきます。

会話形式の文章とイラストでとても読みやすく理解しやすかった。
腹黒本音モードのときは顔に影が入ったりするのが面白い。各章も短く簡潔で、最後にまとめの4コマ漫画が入るので読み疲れることなく最後まで読めた。
税が身近に感じられた一冊。
フリーランスを代表して 申告と節税について教わってきました。 感想 きたみ りゅうじ - 読書メーター

この本の著者はイラストレーターなので同人をしていて確定申告が必要な方はもちろん参考になる部分が多いと思います。その様な職種の方だけでなく、フリーのデザイナーやエンジニアも読んでおいて損は無いのではないかと思います。
どちらも資料がいっぱい必要なお仕事ですからね!! と、本をオススメするだけの記事でした。

Ruby Slim タグなどを含んだ変数をエスケープせずに出力したい。

Ruby Slim

Slim テンプレートでの変数の出力の方法は、こんな感じに=で出力することができます。

div
  p= @value

文章中や、属性中に変数展開させる場合は#{変数名}で出力します。

p
  a.btn src="edit/#{@id}" 編集

しかし、上記の方法ではHTMLタグや"などを含んだ文字列を出力しようとするとエスケープされたものが出力されてしまいます。自動的にエスケープしてくれるので便利なのですが、改行がある文章をそのまま出力したいなどといった場合には不都合があります。

EX:

@value = '<b>"タグ"を含んだテキスト。</b>'
p= @value
p 文章中に変数展開「#{@value}

↓ 出力されるHTML

<p>&lt;b&gt;&quot;タグ&quot;を含んだテキスト。&lt;/b&gt;</p>
<p>文章中に変数展開「&lt;b&gt;&quot;タグ&quot;を含んだテキスト。&lt;/b&gt;</p>

エスケープせずに出力する方法

エスケープせずに変数を出力する場合は == で、
エスケープせずに文章中に変数展開をする場合は #{{変数名}} と二重にすれば記述すればOK。

EX:

@value = '<b>"タグ"を含んだテキスト。</b>'
p== @value
p 文章中に変数展開「#{{@value}}

↓ 出力されるHTML

<p><b>"タグ"を含んだテキスト。</b></p>
<p>文章中に変数展開「<b>"タグ"を含んだテキスト。</b></p>

まとめ

エスケープあり エスケープなし
変数出力 = ==
変数展開 #{変数名} #{{変数名}}

 
好んで使ってたSlimと記述方法が似てるpug (旧jade)ではエスケープしない場合は!=!{変数名}だったので、同じだろうと思ってハマってしまいました。
Rubyの学習が全然進んでないので、もくもく会とかに参加しよう…

後、記事と全然関係ないのだけどSublimeTextでRuby書いてると、シンタックスハイライトの処理なのかめちゃくちゃ入力と表示にラグ発生するのだけれど解決方法とかあるのだろうか…?


プログラミング言語 Ruby

プログラミング言語 Ruby

俺のAdobe Creative Cloudがある日突然、体験版になってた件。

Adobe Creative Cloud Tips

朝起きて、仕事をしようとPhotoshopを起動しようとしたら...
Photoshopの体験版を使用しますか? というアラートが表示されました。

Creative Cloudは契約済みで支払いも行っており、自分のアカウントでログインもされている状態でした。
f:id:kikiki-kiki:20170115115856p:plain
軒並み体験版になってる...

一度ログアウトして、再度ログインすれば解決

この状態で何度 アプリを再起動しようとしても、未契約状態扱いになり、体験版で使用するか聞かれるアラートが表示されてしまいます。
恐らく、1度目の失敗した状態がキャッシングされてしまっているのが原因ではないかと思います。
f:id:kikiki-kiki:20170115120147p:plain
一度、Creative Cloudのデスクトップアプリの設定アイコンををクリックし、「環境設定...」を選択し、ログアウト ボタンを押してログアウトします。
その後、再度Creative Cloudのデスクトップアプリをクリックしてログインしなおせば契約がされている状態に戻りました。

ネットワークが切れたとかの問題なのか、ちょっと原因が不明ですが契約しているのに未契約状態になっていたら、再ログインを試してみれば良さそうです。仕事始める前に疲れてしまったよ...

↓ これ欲しい。

神速Photoshop [Webデザイン編]

神速Photoshop [Webデザイン編]

神速Photoshop[グラフィックデザイン編] CS6/CC/CC 2015対応

神速Photoshop[グラフィックデザイン編] CS6/CC/CC 2015対応

神速Illustrator [グラフィックデザイン編] CC対応

神速Illustrator [グラフィックデザイン編] CC対応

WordPress 管理画面のベーシック認証が効かなくなった時のメモ

WordPress

WordPressを設置する時に少しでもセキュリティを高めるために管理画面やログイン画面にベーシック認証をかけています。
ファイル構成

/
|- .htaccess
|- /wp
|   |- .htaccess
|   |- .htpasswd
|   |- /wp-admin
|- index.php

WordPresswpディレクトリ内に置き、wpディレクトリ内の.htaccessでログイン画面(wp-login.php)にベーシック認証をかけていました。 今回なぜか/wp/wp-admin/でログイン画面にアクセスしようとするとexample.com/wp/wp-login.php?redirect_to=http%3A%2F%2Fexample.com%2Fwp%2Fwp-admin%2F&reauth=1にリダイレクトされエラーページ(404テンプレート)が表示されてしまう現象に遭遇しました。

ログイン画面のベーシック認証

/wp/.htaccess は次のような感じです。
簡易にwp-login.phpにベーシック認証をかけ、パーミッションを400にしてあるwp-config.phpも念のため直接アクセスを禁止する感じにしていました。

# wp-login.php にベーシック認証をかける
<files wp-login.php>
 AuthUserFile /webroot/wp/.htpasswd
 AuthGroupFile /dev/nul
 AuthName "Username and Password"
 AuthType Basic
 require valid-user
</files>

# wp-config.php への直接アクセスを禁止
<files wp-config.php>
 Order deny,allow
 deny from all
</files>

エラーページの指定 (ErrorDocument) が原因だった!

ベーシック認証が表示されず、ログイン画面に遷移しないでエラーページ(404テンプレート)が表示されていた問題は、/.htaccessに書いていたエラーページの指定 ErrorDocument が原因でした。
エラーコードが401の時の設定を ErrorDocument 401 404.html のように指定していしている。かつ ログイン画面にベーシック認証をかけていると、今回のようなリダイレクトパラメータが付いた画面になりログイン画面が表示されないという現象になってしまうようです。ログイン画面にベーシック認証を書けていない場合はErrorDocument 401 が指定されていても問題なく動作しました。
ErrorDocument 401 の指定を消すか、次のように書き換えればば問題は解決されました。

ErrorDocument 401 default

wp-login.phpだけでなく/wp-adminディレクトリ下にベーシック認証を書けている場合もErrorDocument 401default以外だと、同様にログイン画面が表示されなくなってしまいます。

 
まさか、ErrorDocument の指定に問題があるとは思いもしなかったので、問題の解決に結構時間がかかってしまいました。日本語で検索しても全然ヒットしなかったのでw
やはりWEB関連のトラブルの際は全て英語のキーワードで検索してみるのが近道ダナ(・x・) と実感したのでした。


[参考]

一歩先にいくWordPressのカスタマイズがわかる本

一歩先にいくWordPressのカスタマイズがわかる本

年の瀬に一気読みした漫画が凄く良かったので

Blog Book

新年 決意を新たに目標を立てるとか。
沢山 目標を立てても達成できないのでシンプルに、
今年の目標は「描く
コードも絵もたくさん描く。

個人的には決意を新たにするより、 環境を替えるか、付き合うコミュニティを替えるかの方が効果があると思っているのだけれど、年末に一気読みした漫画が凄くよくて、それに感化されてこの目標を立てることにしました。

かくかくしかじか

作者の東村アキコ先生の自伝的漫画なのだけれど、美術系の学校に行っていたり、絵を描いたりしてる人だけでなく、
たぶん 「ついやらない理由を考えちゃう人」とか、「つい逃げちゃう人」とかにももグサグサ刺さる内容だと思います。(逃げ恥とか流行ってたけど。
その殆どに当てはまる僕は読みながら、「あ”あ”あ”あ”あ”あ”あ”あ”あ”」ってなりました。
胸が痛い...

全5巻なので、気になる方は是非!!
オススメです。

はてなブログ Markdown コード内にバッククオートを表示したい

Tips Markdown はてなブログ

` ← バッククオートをインラインコード内に表示する方法

表示したいバッククオートの後ろに半角スペースを付けると上手く表示できる。

`` `

👉 `

バッククオートを含んだ文字列をインラインコードに表示する方法

先頭にバッククオートを表示する場合

そのまま書けばOK

``foo`

👉 `foo

末尾にバッククートを表示する場合

2重のバッククオートで囲み表示したいバッククオートの後に半角スペースを含める

``bar` `` 
// 文字列の先頭にスペースを入れてもOK 
`` bar` ``

👉 bar` bar`

バッククオートで囲んだ文字列を表示する場合

2重のバッククオートで囲んだ中に表示するバッククオートで囲んだ文字列 + 半角スペース で表記する

```hoge` ``
// 前後にスペース入れたほうが見やすい
`` `hoge` ``

👉 `hoge` `hoge`

文字列中にバッククオートがある場合

code内に表示する文字列全体を2重のバッククオートで囲めばOK

``foo`bar` hoge `fuga`mofu``

👉 foo`bar` hoge `fuga`mofu

 

2つ以上の連続したバッククオートを表示したい場合

超 どこで使うねん感ある…
表示したい連続したバッククオートより多いバッククオートで囲めばOK
※ 表示するバッククオートが文字列中にある場合でも連続したバッククオートより多いバッククオートで囲まないとダメ

``` `` ```
``` ``foo ```
``` bar`` ```
```hoge``fuga```

👉 ``
👉 ``foo
👉 bar``
👉 hoge``fuga

 
結論としては、表示したいバッククオートより多い数で囲んで、バッククオ―トで終わる文字列だったら最後に半角スペースをつけるって感じに覚えておけばOKっぽい!


jadeがpugになって変わった所のメモ

pug (jade) node.js

HTMLのコーディングの際にjadeを愛用しています。
jadeがpugになってから、所々仕様が変わっていたのでメモ

Mixinの呼び出し方が変わった

mixin 関数名() ではなく+関数名()になった。

jade

mixin foo('引数')


pug

+foo('引数')

文字列中の変数展開の方法が変わった

jadeの時は"で囲まれた文字列の中に#{変数名}で文字列展開ができていましたが、
pugからは文字列展開をする場合は`で文字列を囲み${変数名}とするか、jadeでも使えていた+演算子で文字列と変数を連結するかになってました。
これはちょっとjadeのときの方が便利だった感じがします...

jade

a(href="#{link}")
p(class="foo#{bar}hoge")
p(class="foo" + bar + "hoge")


pug

a(href=`${link}`)
p(class=`foo${bar}hoge`)
p(class="foo" + bar + "hoge")

for, each の先頭の-が不要になった

逆に-を付けて - each とか - for としてしまうとpugではシンタックスエラーになってしまうようです。

jade

- each val in obj
  = val

- for val in arr
 = val


pug

each val in obj
  = val

for val in arr
 = val

詳しくは公式のリファレンスに載っています。
Migrating to Pug 2

 
CODEPENにjadeで書いてたものがpugに置き換わってて死んでたので気づきました。
これからはpugを使っていく事になると思うので気をつけようと思いました。


WordPress サイトのフロントページにしている固定ページを動的に取得したい

WordPress

WordPressで企業サイトなどを作っている時に固定ページをフロントページ(サイトトップ)に設定する事も多いと思います。
かなりレアケースな気もしますが、フロントページに設定しているページオブジェクトやページIDが必要になるテーマを作成する時のメモ。
f:id:kikiki-kiki:20161211123954p:plain

固定ページを決め打ちで変更しない場合

他のページでフロントページに紐づく情報が取りたい時に、フロントページが決まっていて変更がないのであれば、get_page_by_path()を使ってフロントページに指定されているページオブジェクトを取得することができます。
例えば、/homeでアクセスできる固定ページをフロントページにしている場合は下記で取得することができます。

<?php
$frontPageObj = get_page_by_path('home');

下記では取得できない。

<?php
$frontPage = get_page_by_path('/'); // => null
$frontPage = get_page_by_path( home_url() ); // => null

get_page_by_path()関数は /home_url() といったサイトのトップのURLを引数にしても、null になってしまいます。
なので、ページのスラッグを固定値で指定しなければならず、フロントページにする固定ページを変更すると、その都度get_page_by_path()関数に渡すスラッグを変更する必要があるので、フロントページが変更される可能性があると少し面倒です。

get_option()でフロントページのページIDを取得できる

get_option( 'page_on_front' ): returns the ID of the static page assigned to the front page
is_home() | Function | WordPress Developer Resources

get_option( 'page_on_front' )フロントページに設定してあるページのIDを取得することが出来るので、下記のコードでフロントページのページオブジェクトを取得することができます。

<?php
$pageID = get_option( 'page_on_front' );
$frontPage = get_post( $pageID );

この方法ならフロントページが変更になっても、変更したページを取得することが可能です。

get_option()で投稿ページに指定しているページIDも取得できる

引数をpage_for_postsにすれば、投稿ページ(home)に指定しているページIDも取得することができます。

<?php
$homeID = get_option( 'page_for_posts' );
$homePage = get_post( $homeID );

 
久しぶりにWordPress案件をしてたので、ページを取得する関数だったget_page()は廃止されて、投稿もページもget_post()で取得できるようになってたの今更を知りましたw


[参考]

小さなお店&会社の WordPress超入門 ―初めてでも安心! 思いどおりのホームページを作ろう!

小さなお店&会社の WordPress超入門 ―初めてでも安心! 思いどおりのホームページを作ろう!

Node.js nvmからnodebrewに乗り換えるぞい!

node.js nvm nodebrew Homebrew

Node.jsのバージョンをv6.9.2に上げるにあたって、npmでグローバルにインストールしたパッケージを移行できるコマンドがあるということだったので、Node.jsのバージョン管理をnvmからnodebrewに乗り換えるました。npmのパッケージ結構容量を取るので...

nvmをアンイントールする

$ npm cache clean
$ rm -rf $NVM_DIR ~/.npm ~/.bower

~/.bashrc~/.bash_profileに書かれているnvm関連のパスを削除

# 下記の記述を削除
source ~/.nvm/nvm.sh
npm_dir=${NVM_PATH}_modules
export NODE_PATH=$npm_dir

homebrewでインストールしたnodeを削除

かなり昔にhomebrewでインストールしたnodeが残っていたので、これもアンインストールしてしまいます。

npmを削除

$ npm cache clean
$ cd /usr/local/lib
$ sudo npm uninstall npm
$ rm -rf /usr/local/bin/npm

homebrewでインストールされているnode.jsを削除

$ sudo brew uninstall node

~/.bashrc~/.bash_profileに書かれているhomebrewのnpmのパスを削除

# 下記の記述を削除
export PATH="/usr/local/share/npm/bin:$PATH"

nodebrewをインストール

1. インストール

$ curl -L git.io/nodebrew | perl - setup

2. nodebrewのパスを追加
~/.bashrc~/.zshrcに下記を記述して保存する

export PATH=$HOME/.nodebrew/current/bin:$PATH

3. 追加したパスを反映

$ source ~/.bashrc

nodebrewでNode.jsをインストール

nodebrewの0.6.0をリリースしました。install-binaryというコマンドを追加しまして、コンパイル済みのバイナリからインストールできるようにしました。
nodebrewでバイナリからインストールできるようにした

install-binaryコマンドでコンパイル済みのnodeをダウンロードします。

$ nodebrew install-binary v6.9.2

※ 通常のinstallコマンドでインストールすると、ダウンロードしてからコンパイルするので少し時間がかかってしまいます。

$ nodebrew install v6.9.2

使用するNode.jsのバージョンとデフォルトのバージョンを指定

# 使用するバージョン
$ nodebrew use v6.9.2
# デフォルトで使用するバージョン
$ nodebrew alias default v6.9.2

インストールの確認

別途ターミナルを起動して、nodeのバージョンを確認

$ node -v
v6.9.2

指定したバージョンが表示されていればOK。
別のバージョンが表示される場合は、nodebrewのパスが通ってなかったり、他のnodeのパスなどが残っている可能性が高いので$ which nodeでnodeのパスを調べたり、~/.bashrc~/.bash_profileの記述を再チェックしてみると良いと思います。

globalにインストールしたnpmのパッケージの移行

nodebrewではmigrate-package <version>コマンドで<version>のglobalにインストールされたパッケージの移行ができる。

# Install global NPM packages contained in <version> to current version
$ nodebrew migrate-package <version>

<version>は移行元を指定する。

ex: v5.9.0 にインストールしたパッケージを現在のバージョンに移行する場合

$ nodebrew migrate-package v5.9.0

[参考]