<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ゆっくりと…</title>
	<atom:link href="http://tokkono.cute.coocan.jp/blog/slow/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://tokkono.cute.coocan.jp/blog/slow</link>
	<description>T.I.D. (Technologies Inspire Design)</description>
	<lastBuildDate>
	Sun, 07 Oct 2018 08:59:16 +0000	</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.1.4</generator>
	<item>
		<title>WordPressプラグイン脆弱性 &#8211; 攻撃ベクタの分析と対策</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/attack-analysis-against-vulnerable-plugins/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/attack-analysis-against-vulnerable-plugins/#comments</comments>
				<pubDate>Wed, 27 May 2015 00:04:29 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2313</guid>
				<description><![CDATA[「セキュリティ」のタグが付いたプラグイン は、公式サイトに1000個程もあり、その中から「1本」を選び出すのは至難の業でだと思います。 そもそも「セキュリティ対策」と一口に言ってもその範囲は広いわけで、健康管理に例えるな [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
<a href="https://wordpress.org/plugins/search.php?type=term&amp;q=security" title="WordPress › Search for security « WordPress Plugins">「セキュリティ」のタグが付いたプラグイン</a> は、公式サイトに1000個程もあり、その中から「1本」を選び出すのは至難の業でだと思います。
</p>
<p>
そもそも「セキュリティ対策」と一口に言ってもその範囲は広いわけで、健康管理に例えるなら「予防」や「診断」、「治療」とったカテゴリがあるワケで、さらに「予防」的なものには、
</p>
<ul>
<li>「定期的にバックアップをとっておきましょう」的な「定期検診」系</li>
<li>「常に最新版にアップデートしておきましょう」的な「うがい励行」系</li>
<li>「パーミッションやパスワードを強化しましょう」的な「体力増強」系</li>
<li>「2要素認証やファイアウォールを導入しましょう」的な「マスク着用」系</li>
</ul>
<p>
とまぁ色々あるワケです（ヘタクソな例えでスミマセン）。
</p>
<p>
一方、<a href="https://wpvulndb.com/" title="WPScan Vulnerability Database">WPScan の脆弱性データベース</a> には、プラグインやテーマが毎月10個ほど、続々と登録され続けています。
</p>
<p>
そこで私が最近こだわっているのが「未知の脆弱性という病巣を抱えたプラグインやテーマへの攻撃」を防御する「免疫力強化」系（！？）です。
</p>
<p>
ということで、<a href="https://wordpress.org/plugins/ip-geo-block/" title="WordPress › IP Geo Block « WordPress Plugins">IP Geo Block</a> の現状の防御力を調べ、今後の開発の方向性を見定めるために、<a href="https://wpvulndb.com/plugins" title="WordPress Plugin Vulnerabilities">プラグインの脆弱性データベース</a> から最新の50個を順に拾い、「攻撃ベクタ」という観点で分析を実施してみました（ものすごく骨の折れる作業でした <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ）。
</p>
<p>
自分でも予想外の結果だったので、ここに公開します！
</p>
<p><span id="more-2313"></span></p>
<h3 class="chapter">分析条件</h3>
<p>
DBの最新から順に無料で落とせるプラグインを拾い、公開されている「概念実証」（<a href="http://ja.wikipedia.org/wiki/%E6%A6%82%E5%BF%B5%E5%AE%9F%E8%A8%BC" title="Proof of Concept - Wikipedia">POC</a>）を元にそのパターンを次の様な定義の「攻撃ペクタ」で分類しました。
</p>
<dl style="margin-left: 1em;">
<dt style="clear: left; float: left; width:5em;">攻撃ベクタ</dt>
<dd style="margin-left:5em;">＝ 脆弱性の種類 × 攻撃経路</dd>
</dl>
<p>
「脆弱性の種類」は、<abbr title="Cross Site Scripting">XSS</abbr> や <abbr title="SQL Injection">SQLI</abbr>、<abbr title="Local File Inclusion">LFI</abbr>、<abbr title="Cross Site Request Forgeries">CSRF</abbr> などを表します。また「攻撃経路」は「WordPress に備え付けの入口」という狭義の意味として、以下の分類としました。
</p>
<dl style="margin-left: 1em; margin-bottom:1.71429rem;">
<dt style="clear: left; float: left; width:3em;">
		<abbr title="Ajax / Post">AX</abbr>
	</dt>
<dd style="margin-left:3em; margin-bottom:0">WordPress 標準の Ajax を経由した攻撃</dd>
<dt style="clear: left; float: left; width:3em;">
		<abbr title="Front End">FE</abbr>
	</dt>
<dd style="margin-left:3em; margin-bottom:0">一般公開ページの URI を経由した攻撃</dd>
<dt style="clear: left; float: left; width:3em;">
		<abbr title="Plugin Direct">PD</abbr>
	</dt>
<dd style="margin-left:3em; margin-bottom:0">プラグイン PHP ファイルへの直接攻撃</dd>
<dt style="clear: left; float: left; width:3em;">
		<abbr title="wp-admin">WA</abbr>
	</dt>
<dd style="margin-left:3em; margin-bottom:0"><code>wp-admin</code> 配下のファイルを経由した攻撃</dd>
</dl>
<p>
また特に今回の分析のミソは、「何種類の脆弱性をカバーできるか」ではなく、「脆弱性に関する実際の統計的分布に基づいた攻撃経路の分布が得られる事」にあると考えています。別な言い方をすれば、「脆弱性の種類」と「攻撃経路」のどちらに着目した方がより効果的な防御が出来るかを調べたかったのです。
</p>
<h3 class="chapter">分析結果</h3>
<p>
まずは50件に占める「攻撃経路」の割合を以下の図に示します。同時に IP Geo Block の前バージョンと最新バージョンのカバー範囲を重ねてみました。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/05/vulnerable-path-j.jpg" alt="脆弱性の経路とWP-ZEPの遮断成功率" style="max-width:280px" class="aligncenter size-full wp-image-2315" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/05/vulnerable-path-j.jpg 640w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/05/vulnerable-path-j-150x150.jpg 150w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/05/vulnerable-path-j-300x300.jpg 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/05/vulnerable-path-j-624x624.jpg 624w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<p>
IP Geo Block は、国コードだけでは防げない攻撃を遮断する「ゼロディ攻撃の防御（WP-ZEP）」を装備しているのがウリです（少なくとも私的には）。そこで WP-ZEP の防御力を推定するためのコード・リーディングや幾つかの再現テストも同時に実施しました。
</p>
<p>
次の表はその結果で、IP Geo Block 2.1.0 の防御成否を示しています。「GEO」は「国コード」による遮断の成否を、「ZEP」は WP-ZEP による遮断の成否をそれぞれ表していて、単純な防御率としては、前バージョンの 2.0.8 で26%、今回更新の <a href="http://tokkonopapa.github.io/WordPress-IP-Geo-Block/changelog/release-2.1.0.html" title="2.1.0 Release Note">2.1.0</a> では60%となりました。
</p>
<div class="table-responsive">
<div style="text-align:center">
    <cite><a href="https://wpvulndb.com/plugins" title="WordPress Plugin Vulnerabilities">出典：&copy; The WPScan Team</a></cite>
  </div>
<table id="my-table" class="table">
<thead>
<tr>
<th style="text-align:left">プラグインの脆弱性</th>
<th style="text-align:left" class="no-sort">バージョン</th>
<th style="text-align:left">種類</th>
<th style="text-align:left" id="attack-vec">経路</th>
<th style="text-align:left" id="geolocation">GEO</th>
<th style="text-align:left" id="wp-zep">ZEP</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7879" title="WP Business Intelligence Lite &lt;= 1.6.1 - SQL Injection">WP Business Intelligence Lite</a></td>
<td>&lt;= 1.6.1</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="http://packetstormsecurity.com/files/131228/">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7873" title="Ptengine &lt;= 1.0.1 - Reflected Cross-Site Scripting (XSS)">Ptengine</a></td>
<td>&lt;= 1.0.1</td>
<td><abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="Front End"><a href="https://wpvulndb.com/vulnerabilities/7873">FE</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7821" title="EZ Portfolio &lt;= 1.0.1 - Multiple Cross-Site Scripting (XSS) ">EZ Portfolio</a></td>
<td>&lt;= 1.0.1</td>
<td><abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="Ajax/Post for admin">AX</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7798" title="WonderPlugin Audio Player 2.0 Blind SQL Injection and XSS">WonderPlugin Audio Player</a></td>
<td>&lt;= 2.0</td>
<td><abbr title="SQL Injection">SQLI</abbr>, <abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://www.exploit-db.com/exploits/36086/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7866" title="Aspose Cloud eBook Generator - File Download">Aspose Cloud eBook Generator</a></td>
<td>&lt;= 1.0</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Plugin Direct for anonymous user"><a href="http://packetstormsecurity.com/files/131040/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7830" title="Wpshop - eCommerce &lt;= 1.3.9.5 - Arbitrary File Upload">WPshop &#8211; eCommerce</a></td>
<td>&lt;= 1.3.9.5</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="https://research.g0blin.co.uk/g0blin-00036/">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7813" title="WPBook &lt;= 2.7 - Cross-Site Request Forgery (CSRF)">WPBook</a></td>
<td>&lt;= 2.7</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr></td>
<td><abbr title="wp-admin">WA</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7817" title="WP-ViperGB 1.3.10 - XSS Weakness and CSRF">WP-ViperGB</a></td>
<td>&lt;= 1.3.10</td>
<td><abbr title="Cross Site Scripting">XSS</abbr>, <abbr title="Cross-Site Request Forgery">CSRF</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/129501">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7794" title="WordPress Survey &#038; Poll &lt;= 1.1.7 - Blind SQL Injection">WordPress Survey &#038; Poll</a></td>
<td>&lt;= 1.1.7</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="http://packetstormsecurity.com/files/130381/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7814" title="WP Media Cleaner &lt;= 2.2.6 - Cross-Site Scripting (XSS)">WP Media Cleaner</a></td>
<td>&lt;= 2.2.6</td>
<td><abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/130576/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7888" title="WP Easy Slideshow &lt;= 1.0.3 - Multiple Cross-Site Request Forgery (CSRF)">WP Easy Slideshow</a></td>
<td>&lt;= 1.0.3</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr></td>
<td><abbr title="wp-admin"><a href="https://www.exploit-db.com/exploits/36612/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7896" title="N-Media Website Contact Form with File Upload &lt;= 1.3.4 - Arbitrary File Upload">N-Media Website Contact Form</a></td>
<td>&lt;= 1.3.4</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr></td>
<td><abbr title="Ajax/Post for privilege and no-privilege user"><a href="http://packetstormsecurity.com/files/131413/">AX+</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7901" title="Tune Library &lt;= 1.5.4 - SQL Injection">Tune Library</a></td>
<td>&lt;= 1.5.4</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Front End"><a href="http://packetstormsecurity.com/files/131558/">FE</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7791" title="Redirection Page &lt;= 1.2 - CSRF/XSS">Redirection Page</a></td>
<td>&lt;= 1.2</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/130314/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7884" title="PHP Event Calendar &lt;= 1.5 - Arbitrary File Upload">PHP Event Calendar</a></td>
<td>&lt;= 1.5</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr></td>
<td><abbr title="Plugin Direct for admin"><a href="http://packetstormsecurity.com/files/131277/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7937" title="My Wish List - Multiple Parameter XSS">My Wish List</a></td>
<td>&lt;= 1.4.1</td>
<td><abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="Front End">FE</abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7792" title="Mobile Domain &lt;= 1.5.2 - CSRF/XSS">Mobile Domain</a></td>
<td>&lt;= 1.5.2</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/130316/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7935" title="MailChimp Subscribe Form &lt;= 1.1 - Email Field Remote PHP Code Execution">MailChimp Subscribe Form</a></td>
<td>&lt;= 1.1</td>
<td><abbr title="Remote Code Execution">RCE</abbr></td>
<td><abbr title="Plugin Direct for admin"><a href="http://plugins.svn.wordpress.org/mailchimp-subscribe-sm/tags/1.1/data.php">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7816" title="IP Blacklist Cloud &lt;= 3.4 - SQL Injection">IP Blacklist Cloud</a></td>
<td>&lt;= 3.4</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="wp-admin">WA</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7844" title="IP Blacklist Cloud &lt;= 3.42 - Arbitrary File Disclosure">IP Blacklist Cloud</a></td>
<td>&lt;= 3.42</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Front End"><a href="https://research.g0blin.co.uk/g0blin-00037/">FE</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7864" title="InBoundio Marketing Plugin &lt;= 2.0.3 - Shell Upload">InBoundio Marketing</a></td>
<td>&lt;= 2.0.3</td>
<td><abbr title="Remote File Upload">RFU</abbr></td>
<td><abbr title="Plugin Direct for admin"><a href="http://packetstormsecurity.com/files/130957/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7796" title="Image Metadata Cruncher - Multiple XSS">Image Metadata Cruncher</a></td>
<td>&lt;= 1.8</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://www.securityfocus.com/archive/1/archive/1/534718/100/0/threaded">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7812" title="CrossSlide jQuery Plugin &lt;= 2.0.5 - Stored XSS &amp; CSRF">CrossSlide jQuery</a></td>
<td>&lt;= 2.0.5</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/130313/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7876" title="Aspose PDF Exporter - Arbitrary File Download">Aspose PDF Exporter</a></td>
<td>&lt; 2.0</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Plugin Direct for anonymous user"><a href="http://packetstormsecurity.com/files/131161/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7877" title="Aspose Importer and Exporter 1.0 - Arbitrary File Download">Aspose Importer &amp; Exporter</a></td>
<td>&lt;= 1.0</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Plugin Direct for anonymous user"><a href="http://packetstormsecurity.com/files/131162/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7869" title="Aspose DOC Exporter 1.0 - Arbitrary File Download">Aspose DOC Exporter</a></td>
<td>&lt;= 1.0</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Plugin Direct for anonymous user"><a href="http://packetstormsecurity.com/files/131167/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7778" title="WP Ultimate CSV Importer &lt;= 3.6.74 - Database Table Export">WP Ultimate CSV Importer</a></td>
<td>&lt;= 3.6.74</td>
<td><abbr title="Authentication Bypass">AB</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="https://research.g0blin.co.uk/g0blin-00025/">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7949" title="WP Ultimate CSV Importer &lt;= 3.7.1 - Directory Traversal">WP Ultimate CSV Importer</a></td>
<td>&lt;= 3.7.1</td>
<td><abbr title="Directory Traversal">DT</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="http://www.pritect.net/blog/wp-ultimate-csv-importer-3-7-1-critical-vulnerability">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7898" title="WP Mobile Edition &lt;= 2.7 - Remote File Disclosure">WP Mobile Edition</a></td>
<td>&lt;= 2.2.7</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Plugin Direct for anonymous user"><a href="https://www.exploit-db.com/exploits/36733/">PD</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7809" title="WP All Import &lt;= 3.2.3 - RCE">WP All Import</a></td>
<td>&lt;= 3.2.3</td>
<td><abbr title="Remote Code Execution">RCE</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="http://packetstormsecurity.com/files/130596/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7852" title="WP All Import &lt;= 3.2.4 - Multiple Vulnerabilities">WP All Import</a></td>
<td>&lt;= 3.2.4</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="Ajax/Post for admin">AX</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7781" title="UpdraftPlus &lt;= 1.9.50 - Privilege Escalation">UpdraftPlus</a></td>
<td>&lt;= 1.9.50</td>
<td><abbr title="Privilege Escalation">PE</abbr></td>
<td><abbr title="Ajax/Post for login user">AX</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7850" title="Ultimate Member &lt;= 1.0.78 - Multiple Vulnerabilities">Ultimate Member</a></td>
<td>&lt;= 1.0.78</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="http://www.pritect.net/blog/ultimate-member-plugin-1-0-78-critical-security-vulnerability">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7939" title="Ultimate Product Catalogue Plugin &lt;= 3.1.1 - Unauthenticated File Upload">Ultimate Product Catalogue</a></td>
<td>&lt;= 3.1.1</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://wpvulndb.com/vulnerabilities/7939">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7946" title="Ultimate Product Catalogue Plugin &lt;= 3.1.2 - Unauthenticated SQL Injection">Ultimate Product Catalogue</a></td>
<td>&lt;= 3.1.2</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://www.exploit-db.com/exploits/36823/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7948" title="Ultimate Product Catalogue Plugin &lt;= 3.1.2 - Unauthenticated SQL Injection">Ultimate Product Catalogue</a></td>
<td>&lt;= 3.1.2</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Front End"><a href="https://www.exploit-db.com/exploits/36824/">FE</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7775" title="TinyMCE Advanced 4.1 - Setting Reset CSRF">TinyMCE Advanced</a></td>
<td>&lt;= 4.1</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://vexatioustendencies.com/wordpress-plugin-vulnerability-dump-part-2/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7811" title="Huge-IT Slider - SQL Injection ">Huge-IT Slider</a></td>
<td>&lt;= 2.6.8</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://www.htbridge.com/advisory/HTB23250">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7882" title="Simple Ads Manager &lt;= 2.5.94 - Arbitrary File Upload &#038; SQL Injection">Simple Ads Manager</a></td>
<td>&lt;= 2.5.94</td>
<td><abbr title="Arbitrary File Upload">AFU</abbr>, <abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Plugin Direct including wp-load.php"><a href="http://packetstormsecurity.com/files/131282/">PD*</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7922" title="Related Posts for WordPress &lt;= 1.8.1 - Cross-Site Scripting (XSS)">Related Posts for WordPress</a></td>
<td>&lt;= 1.8.1</td>
<td><abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="Front End">FE</abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7858" title="Ajax Search Lite &lt;= 3.1 - Authenticated RCE">Ajax Search Lite</a></td>
<td>&lt;= 3.1</td>
<td><abbr title="Remote Code Execution">RCE</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="http://research.evex.pw/?vuln=9">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7773" title="Blubrry PowerPress &lt;= 6.0 - Cross-Site Scripting (XSS)">Blubrry PowerPress</a></td>
<td>&lt;= 6.0</td>
<td><abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="https://www.netsparker.com/cve-2015-1385-xss-vulnerability-in-blubrry-powerpress/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7870" title="PlusCaptcha Plugin - CSRF">PlusCaptcha</a></td>
<td>&lt;= 2.0.14</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr></td>
<td><abbr title="wp-admin">WA</abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7924" title="P3 (Plugin Performance Profiler) &lt;= 1.5.3.8 - Cross-Site Scripting (XSS)">Plugin Performance Profiler</a></td>
<td>&lt;= 1.5.3.8</td>
<td><abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin">WA</abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7928" title="NEX-Forms - Ultimate Form builder &lt;= 3.0 - SQL Injection">NEX-Forms</a></td>
<td>&lt;= 3.0</td>
<td><abbr title="SQL Injection">SQLI</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://www.exploit-db.com/exploits/36800/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7848" title="MiwoFTP - File &#038; Folder Manager &lt;= 1.0.4 - Arbitrary File Disclosure">MiwoFTP</a></td>
<td>&lt;= 1.0.4</td>
<td><abbr title="Local File Inclusion">LFI</abbr></td>
<td><abbr title="Front End"><a href="https://research.g0blin.co.uk/g0blin-00038/">FE</a></abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7905" title="MiwoFTP - File &#038; Folder Manager &lt;= 1.0.5 - Multiple Vulnerabilities">MiwoFTP</a></td>
<td>&lt;= 1.0.5</td>
<td><abbr title="Cross-Site Request Forgery">CSRF</abbr>, <abbr title="Cross-Site Scripting">XSS</abbr></td>
<td><abbr title="wp-admin"><a href="http://packetstormsecurity.com/files/131436/">WA</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7839" title="MainWP Child &lt;= 2.0.9.1 - Authentication Bypass">MainWP Child</a></td>
<td>&lt;= 2.0.9.1</td>
<td><abbr title="Authentication Bypass">AB</abbr></td>
<td><abbr title="Front End">FE</abbr></td>
<td><span class="label label-danger">NG</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7936" title="Mashshare &lt;= 2.3.0 - Information Disclosure">Mashshare</a></td>
<td>&lt;= 2.3.0</td>
<td><abbr title="Authentication Bypass">AB</abbr></td>
<td><abbr title="Ajax/Post for admin"><a href="https://research.g0blin.co.uk/g0blin-00045/">AX</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-success">OK</span></td>
</tr>
<tr>
<td><a href="https://wpvulndb.com/vulnerabilities/7871" title="WordPress Leads 1.6.1-1.6.2 - Persistent XSS">WordPress Leads</a></td>
<td>&lt;= 1.6.2</td>
<td><abbr title="Cross Site Scripting">XSS</abbr></td>
<td><abbr title="Ajax/Post for privilege and no-privilege user"><a href="https://research.g0blin.co.uk/g0blin-00042/">AX+</a></abbr></td>
<td><span class="label label-success">OK</span></td>
<td><span class="label label-danger">NG</span></td>
</tr>
<tr class="no-sort">
<td style="text-align:right; padding-right: 0.5em;" class="text-right" colspan="4"><span class="label label-success">OK</span> の総数</td>
<td style="padding-left:0.5em">33</td>
<td style="padding-left:0.5em">30</td>
</tr>
</tbody>
</table>
</div>
<p>
表を眺めるみると、何となく「攻撃経路」に着目した方が良いのでは？ という感じがしています（いい加減な、結果ありきの分析でゴメンナサイ）。
</p>
<h3 class="chapter">今後の対応</h3>
<p>
上の表を <a href="javascript:void(0);" onclick="sortby('attack-vec');" title="「経路」で並べ替える">「経路」で並べ替えて</a> みて下さい。<span class="label label-danger">NG</span> が残っているのは、ほとんどが「一般公開ページの URI を経由した攻撃（FE）」と「プラグイン PHP ファイルへの直接攻撃（PD）」であることが分かります。これらが厄介なのは、管理者権限を持たない一般訪問者向けの機能を含んでいるという点です。
</p>
<p>
実は IP Geo Block 2.1.0 は、今回の分析を元に「PD*」（<code>wp-load.php</code> を読み込んでいる、プラグイン PHP ファイルへの直接攻撃）に対処できるよう、対策をしています。その結果、WordPress のコンテキストとは全く関係なく単独で実行が出来てしまう「PD」が残ったというワケです。
</p>
<p>
私にとって驚きだったのは、一般公開ページ向けのサービスに WordPress とは独立な脆弱性が予想以上にあったという事実です。このリスクを下げるには、一般公開ページ向けにも何らかの対策を施すべきということが、定量的にも分かっちゃった次第です。
</p>
<h3 class="chapter">まとめ</h3>
<p>
正直、前バージョンの IP Geo Block については、思ったより防御率が悪くてガッカリ、というか「誇大広告」ぎみで、利用して下さっている方々にちょっと申し訳ない気持ちになりました。同時に「他のセキュリティ・プラグインはどうなんだろう？」という興味も湧いてきたので、そのうち「ゼロディ攻撃に対する防御力」という観点で比較検証してみたいと思います。
</p>
<p>
次のステップは「PD*」を遮断する事です。これにより遮断率を80%にする事ができます（が、副作用も増えます）。原理的なところはほぼ出来ているのですが、リライトの設定とか新たな脆弱性を作り込まないための検証とか、結構時間がかかると思います。
</p>
<p>
また IP Geo Block は「一般公開ページは誰でもアクセスできる様にしておきたい」という気持ちで作ってきました。今後はこの選択もユーザーに任せるべき？ と思っています。ただ「検索botは遮断しない」とかの「抜け穴」を作らなくちゃならないので、気が進まないのですが &hellip;
</p>
<p>
まぁ、今後もチマチマと改善は加えていくので、使ってくれれば励みになります <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/attack-analysis-against-vulnerable-plugins/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
							</item>
		<item>
		<title>wp-adminへのゼロデイ攻撃を防ぐ機能を追加 &#8211; IP Geo Block更新告知</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/wp-admin-zero-day-exploit-prevention/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/wp-admin-zero-day-exploit-prevention/#respond</comments>
				<pubDate>Sun, 22 Mar 2015 09:49:45 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2295</guid>
				<description><![CDATA[2014年12月、NTTコミュニケーションズが「Zero day Attack Protection（仮称）」を開発、今年4月からのサービス開始を発表しましたが、我が WordPress プラグイン IP Geo Blo [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
2014年12月、NTTコミュニケーションズが「<a href="http://www.ntt.com/release/monthNEWS/detail/20141218.html" title="ニュース  2014年12月18日：日本独自のゼロデイ攻撃対策セキュリティサービス「Zero day Attack Protection」(仮称)を開発・提供 | NTT Com 企業情報">Zero day Attack Protection（仮称）</a>」を開発、今年4月からのサービス開始を発表しましたが、我が WordPress プラグイン <a href="https://wordpress.org/plugins/ip-geo-block/" title="WordPress &#8250; IP Geo Block &laquo; WordPress Plugins">IP Geo Block</a> も独自の仕組みにより一部の <a href="http://ja.wikipedia.org/wiki/%E3%82%BC%E3%83%AD%E3%83%87%E3%82%A4%E6%94%BB%E6%92%83" title="ゼロデイ攻撃 - Wikipedia">ゼロデイ攻撃</a> を防御する機能を追加しましたので、その告知とバグ出しの協力願いをしたいと思います <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p><span id="more-2295"></span></p>
<h3 class="chapter">背景</h3>
<p>
拙作の「<a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/misunderstanding-of-creating-wp-plugins/">プラグイン作者必読！実例に学ぶ脆弱なWordPressプラグインの作り方、又はwp-adminを守る理由</a>」では、脆弱性を持つプラグインの多くで「重要な処理」を行う際、「権限と nonce の検証」が欠落していることを明らかにしました。またその後も <a href="https://wpvulndb.com/" title="WPScan Vulnerability Database">同様の例</a> が後を絶ちません。
</p>
<p>
本来なら WordPress 自体が本質的にセキュアな仕組みで出来ていて、この手の脆弱性を作り込む余地がないのが理想でしょう。一方で、もしそんな作りになっていたら、現在私たちが手にしている自由は無かったのかもしれない、とも思います。
</p>
<p>
それならということで、補助的に「権限の検証」と「nonce の検証」を埋め込むことで、これらが欠落して起きる <a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA"><abbr title="Cross Site Request forgeries">CSRF</abbr></a> や <a href="http://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3"><abbr title="SQL Injection">SQLi</abbr></a> といった攻撃や <abbr title="Local File inclusion"><a href="http://hakipedia.com/index.php/Local_File_Inclusion">LFI</a></abbr> などの脆弱性からサイトを守る機能を追加してみました。
</p>
<p>
理想的には、この機能はプラグインに依存せず「ゼロデイ攻撃の防御」が可能です。
</p>
<p>
が、現実にはそれほど素晴らしいものではなく、防御できるのは一部になります。まずはその辺りの事情から説明させて下さい。
</p>
<h3 class="chapter">プラグインで「何か重要なことをする」3つの方法</h3>
<p>
プラグインが <a href="http://wpdocs.sourceforge.jp/Adding_Administration_Menus" title="管理メニューの追加 - WordPress Codex 日本語版">管理メニュー</a> にその入口を追加すると、その URL は、登録した種類に応じて例えば次の様になっているハズです。
</p>
<ul>
<li><code>wp-admin/admin.php?<span style="color:red">page=my-plugin</span></code></li>
<li><code>wp-admin/tools.php?<span style="color:red">page=my-plugin</span></code></li>
<li><code>wp-admin/option-general.php?<span style="color:red">page=my-plugin</span></code></li>
<li>&#8230;</li>
</ul>
<p>
さて、それぞれのページで「ボタンを押した時に何か重要な処理をする」には、（コア系の処理を除けば）最もベーシックな方法として次の3つがあります。
</p>
<div id="attachment_2303" style="width: 1610px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2303" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/my-plugin.png" alt="「重要な処理」を実行する3つの方法を実装したサンプル" width="1600" height="960" class="size-full wp-image-2303" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/my-plugin.png 1600w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/my-plugin-300x180.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/my-plugin-1024x614.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/my-plugin-624x374.png 624w" sizes="(max-width: 1600px) 100vw, 1600px" /><p id="caption-attachment-2303" class="wp-caption-text">「重要な処理」を実行する3つの方法を実装したサンプル</p></div>
<h4 class="chapter"><code>wp-admin/admin.php?action=do-my-action</code></h4>
<p>
<a href="http://wordpress.stackexchange.com/questions/10500/how-do-i-best-handle-custom-plugin-page-actions" title="wp admin - How do i best handle custom plugin page actions? - WordPress Development Stack Exchange">Akismet でも使われている方法</a> で、ユニークなアクション名 <code>do-my-action</code> を軸に「重要な処理」を実行するコードを組み立てます。
</p>
<p>
まずは、フォームによるボタンの作成です。
</p>
<p>[php]<br />
&lt;form method=&#8221;post&#8221; action=&#8221;&lt;?php echo admin_url( &#8216;admin.php&#8217; ); ?&gt;&#8221;&gt;<br />
    &lt;?php wp_nonce_field( &#8216;do-my-action&#8217;, &#8216;_wpnonce&#8217; ); ?&gt;<br />
    &lt;input type=&#8221;hidden&#8221; name=&#8221;action&#8221; value=&#8221;&lt;?php echo &#8216;do-my-action&#8217;; ?&gt;&#8221; /&gt;<br />
    &lt;input type=&#8221;submit&#8221; value=&#8221;重要な処理&#8221; class=&#8221;button button-primary&#8221; /&gt;<br />
&lt;/form&gt;<br />
[/php]</p>
<p>
あるいは、a タグで飛ばすなら次の様にします。
</p>
<p>[php]<br />
&lt;?php<br />
$link = add_query_arg(<br />
    array(<br />
        &#8216;action&#8217; => &#8216;do-my-action&#8217;,<br />
        &#8216;_wpnonce&#8217; => wp_create_nonce( &#8216;do-my-action&#8217; ),<br />
    ),<br />
    admin_url( &#8216;admin.php&#8217; )<br />
);<br />
?&gt;<br />
&lt;a class=&#8221;button-secondary&#8221; href=&#8221;&lt;?php echo esc_url( $link ); ?&gt;&#8221;&gt;重要な処理&lt;/a&gt;<br />
[/php]</p>
<p>
またリクエストされたアクション <code>do-my-action</code> をフックするには、以下を定義しておかなければなりません。
</p>
<p>[php]<br />
add_action( &#8216;admin_action_&#8217; . &#8216;do-my-action&#8217;, &#8216;my_action&#8217; );<br />
function my_action() {<br />
    // 権限と nonce の検証<br />
    if ( ! current_user_can( &#8216;manage_options&#8217; ) ||<br />
         ! check_admin_referer( &#8216;do-my-action&#8217;, &#8216;_wpnonce&#8217; ) ) {<br />
        return; // ログイン画面に戻される<br />
    }</p>
<p>    // ここで重要な処理<br />
    &#8230;</p>
<p>    // 結果の表示：Ajax の場合<br />
    if ( defined( &#8216;DOING_AJAX&#8217; ) &#038;&#038; DOING_AJAX ) {<br />
        wp_send_json( $result );<br />
    }</p>
<p>    // 結果の表示：ページを遷移する場合<br />
    else {<br />
        if ( isset( $_REQUEST[&#8216;_wp_http_referer&#8217;] ) ) {<br />
            // wp_nonce_field() が埋め込んだリファラに遷移<br />
            $redirect_to = $_REQUEST[&#8216;_wp_http_referer&#8217;];<br />
        }<br />
        else if ( isset( $_SERVER[&#8216;HTTP_REFERER&#8217;] ) ) {<br />
            // ブラウザが出力したリファラに遷移<br />
            $redirect_to = $_SERVER[&#8216;HTTP_REFERER&#8217;];<br />
        }<br />
        else {<br />
            // 予め設定したページに遷移<br />
            $redirect_to = admin_url( &#8216;admin.php?page=&#8217; . &#8216;my-plugin&#8217; );<br />
        }</p>
<p>        wp_safe_redirect( $redirect_to );<br />
        exit;<br />
    }<br />
}<br />
[/php]</p>
<p>
余計な経路は介さずに関数 <code>my_action()</code> を起動、「重要な処理」に集中し、「結果の表示」は他に任せるという <q>潔さ</q> が、この方法のミソでしょう。
</p>
<h4 class="chapter"><code>wp-admin/admin-ajax.php?action=do-my-action</code></h4>
<p>
詳細は <a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/secured-ajax-with-wp-nonce/" title="初歩からわかるWordPressのnonceでAjaxをセキュアに実装する方法 | ゆっくりと…">他の記事</a> に譲りますが、前述の <code>my_action()</code> に Ajax 用のフックを引っ掛けます。
</p>
<p>[php]<br />
add_action( &#8216;wp_ajax_&#8217; . &#8216;do-my-action&#8217;, &#8216;my_action&#8217; ); // ログインユーザー用<br />
add_action( &#8216;wp_ajax_nopriv_&#8217; . &#8216;do-my-action&#8217;, &#8216;my_action&#8217; ); // 非ログインユーザー用<br />
[/php]</p>
<p>
おっと、ここでは「重要な処理」に「非ログインユーザー用（no privilege）」は必要ありませんネ。
</p>
<h4 class="chapter"><code>wp-admin/admin-post.php?action=do-my-action</code></h4>
<p>
<code>admin-post.php</code> は、純粋な POST リクエストに対する入口です。Ajax と同様に「ログインユーザー」と「非ログインユーザー」を振り分ける事が出来ます。
</p>
<p>[php]<br />
add_action( &#8216;admin_post_&#8217; . &#8216;do-my-action&#8217;, &#8216;my_action&#8217; );<br />
add_action( &#8216;admin_post_nopriv_&#8217; . &#8216;do-my-action&#8217;, &#8216;my_action&#8217; );<br />
[/php]</p>
<h3 class="chapter">ゼロデイ攻撃を防御する仕組みと限界</h3>
<p>
脆弱なプラグインに代わって「権限と nonce の検証」を行うには、遷移前のページに nonce を埋め込み、「重要な処理」の前に検証を実行しなければなりません。
</p>
<p>
このため前述の3つの基本形に対し、リンク、フォーム、jQuery による Ajax リクエストの各々に nonce を埋め込み、リクエストを受けたところで検証をする仕組み入れています。
</p>
<p>
一方、プラグインが「重要な処理」のリクエストを受け付ける方法は、前述の3つ以外にも無数に存在します。例えば <code>admin.php?page=my-plugin&amp;<span style="color:red">job=do-my-job</code></code> で、表示の前に処理を振り分けても OK ですし、（酷いのになると、プラグインはイベント駆動で開発されるべきという <q>お約束</q> を無視して）WordPress を経由しないケースも見受けられます。
</p>
<p>
同様に、PHP が他の PHP に直接リクエストする場合（サーバーサイド）や、ブラウザから flash や JavaScript のロケーション・オブジェクトを介してリクエストする場合（クライアントサイド）などがあり得ます。このような場合は nonce の埋め込みが出来ず、逆にこの仕組みが邪魔になってしまいます。
</p>
<p>
そこで、「この仕組みをバイパスする処理」について、および「この仕組みでも防げない脆弱性」について、以下に説明します。
</p>
<h4 class="chapter">コア系で使われるリクエスト</h4>
<p>
メディア・ライブラリでは、<a href="http://www.plupload.com/" title="Plupload: Multi-runtime File-Uploader">Plupload</a> が flash や silverlight 経由でアップロードを行なうため、これらのアクション名を特定し、バイパスしています。
</p>
<h4 class="chapter">他のflash系を使うプラグインなど</h4>
<p>
jQuery 以外で Ajax を行うプラグイン向けに、バイパスすべきアクションを追加するフィルター・フックを用意しました。
</p>
<p>[php]<br />
add_filter( &#8216;ip-geo-block-admin-actions&#8217;, &#8216;my_admin_actions&#8217; );<br />
function my_admin_actions( $admin_actions ) {<br />
    $actions = array(<br />
        &#8216;do-some-plugin-action&#8217;, // バイパスするアクション名<br />
    );<br />
    return $admin_actions + $actions;<br />
}<br />
[/php]</p>
<h4 class="chapter">権限昇格（<abbr title="Privilege Escalation">PE</abbr>）は防げない</h4>
<p>
WordPress ではバックエンドでの処理に際し、<a href="http://wpdocs.sourceforge.jp/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E6%A8%A9%E9%99%90" title="ユーザーの種類と権限 - WordPress Codex 日本語版">ユーザーの種類と権限</a> を細かく制限する事が出来ますが、権限の十分条件はプラグインやテーマに依存し、PHP ソースでも解析しない限り外側からは特定する事が出来ません。
</p>
<p>
そこで本プラグインでは、「ログイン」を最低限の権限としています。
</p>
<p>
よって、異なる権限間で発生し得る nonce の漏洩や権限の回避といった、「権限昇格」の脆弱性に対する攻撃は防ぐ事が出来ません。
</p>
<h3 class="chapter">効果の検証</h3>
<p>
最近発表された脆弱性の事例から、防御が成功する場合と失敗する場合を1例ずつ紹介したいと思います。
</p>
<h4 class="chapter">防御が成功する場合</h4>
<p>
2015年1月、<a href="https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/" title="WordPress &#8250; All In One WP Security &amp; Firewall &laquo; WordPress Plugins">All In One WP Security &#038; Firewall</a> の CSRF 脆弱性が <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-0895" title="CVE - CVE-2015-0895">CVE に上がりました</a>（<a href="http://jvn.jp/en/jp/JVN87204433/index.html" title="JVN#87204433: All In One WP Security &amp; Firewall vulnerable to cross-site request forgery">JVN へは2015年3月</a>）。
</p>
<p>
「悪意あるリンクを踏むと、特定の 404 イベント・ログが削除される」という、深刻度の低い脆弱性です <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p>
残念ながら（？）<a href="https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/developers/" title="WordPress &#8250; All In One WP Security &amp; Firewall &laquo; WordPress Plugins">公式の SVN リポジトリ</a> からは既に該当のバージョンは削除されていますので、ミラーサイトの <a href="https://github.com/wp-plugins/all-in-one-wp-security-and-firewall" title="wp-plugins/all-in-one-wp-security-and-firewall - GitHub">Github</a> からクローンを落としての再現です。
</p>
<p>
「悪意あるリンク」は、図の通りです。
</p>
<div id="attachment_2296" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2296" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/404Logs.png" alt="404 Event Logs" width="1200" height="520" class="size-full wp-image-2296" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/404Logs.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/404Logs-300x130.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/404Logs-1024x444.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/404Logs-624x270.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2296" class="wp-caption-text">404 Event Logs</p></div>
<p>
これを WordPress 以外のページに貼付けてクリックすると、All in one Security の管理画面に飛んで、ログが削除されます。
</p>
<div id="attachment_2302" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2302" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/aios-CSRF.png" alt="All In One WP SecurityのCSRF" width="1200" height="830" class="size-full wp-image-2302" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/aios-CSRF.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/aios-CSRF-300x208.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/aios-CSRF-1024x708.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/aios-CSRF-624x432.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2302" class="wp-caption-text">All In One WP SecurityのCSRF</p></div>
<p>
一方、IP Geo Block の「ゼロデイ攻撃を防御」を有効にすれば、以下の様にブロックすることが出来ます。
</p>
<div id="attachment_2298" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2298" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/blocked-CSRF.png" alt="ブロックされたリクエスト" width="1200" height="390" class="size-full wp-image-2298" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/blocked-CSRF.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/blocked-CSRF-300x98.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/blocked-CSRF-1024x333.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/blocked-CSRF-624x203.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2298" class="wp-caption-text">ブロックされたリクエスト</p></div>
<h4 class="chapter">防御が失敗する場合</h4>
<p>
2015年3月11日には、<a href="https://wordpress.org/plugins/wordpress-seo/" title="WordPress &#8250; WordPress SEO by Yoast &laquo; WordPress Plugins">WordPress SEO by Yoast</a> の <a href="https://wpvulndb.com/vulnerabilities/7841" title="WordPress SEO by Yoast &lt;= 1.7.3.3 - Blind SQL Injection">1.7.3.3 以下で任意の SQL が実行できる</a> という、深刻度の高い脆弱性が公開されました。
</p>
<p>
この脆弱性の根本原因は nonce の検証漏れによる <abbr title="Cross Site Request Forgeries">CSRF</abbr> なので、本プラグインにとって最も「オイシイ」ケースですが、残念ながら防御対象であるリクエストの「3つの方法」に当てはまらず、防御できません。
</p>
<p>
何処まで基本形を拡張できるかは、今後の課題ですネ。
</p>
<h3 class="chapter">IP Geo Block の設定</h3>
<p>
「設定」画面の「検証の設定」で、「管理領域」および「管理領域のajax/post」に「ゼロデイ攻撃の防御」を選んで下さい。
</p>
<div id="attachment_2299" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2299" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/IPGB-settings.png" alt="IP Geo Blockの設定" width="1200" height="640" class="size-full wp-image-2299" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/IPGB-settings.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/IPGB-settings-300x160.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/IPGB-settings-1024x546.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/03/IPGB-settings-624x333.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2299" class="wp-caption-text">IP Geo Blockの設定</p></div>
<h3 class="chapter">オマケの機能</h3>
<p>
折角組み込んだ nonce が第三者に漏れては元も子もありません。これが起きるケースの1つに、「URL に埋め込まれた nonce がリファラを介して外部に漏れる」が想定できます。
</p>
<p>
そこでログイン中に外部リンクを踏んだ場合、ブラウザがリファラをリセットしてから飛ぶ仕掛け「リファラ・サイレンサー」を入れてあります。ネットスケープ時代からブラウザが独自に取り入れている機能なため、大抵のブラウザで働くと思いますョ <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h3 class="chapter">バグ出し協力のお願い</h3>
<p>
さてさて、今回追加した機能がウマく働くかどうかは、ひとえに「nonce が埋め込めるかどうか」にかかっています。が、ウマくいかない場合も多々あるかと思います。
</p>
<p>
そこで「試してもイイよ」というパイオニア精神が旺盛な方、トラブル発見の際は、ぜひ <a href="https://wordpress.org/support/plugin/ip-geo-block" title="WordPress &#8250; Support &raquo; IP Geo Block">サポート・フォーラム</a> とか、コメント欄とかに書き込みをお願いします <code>m_(..)_m</code></p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/wp-admin-zero-day-exploit-prevention/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Web Automobile Firewallという考え方</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/web-automobile-firewall/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/web-automobile-firewall/#respond</comments>
				<pubDate>Fri, 20 Feb 2015 15:46:44 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[Webテクノロジ]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2291</guid>
				<description><![CDATA[今回は、めずらしく妄想系のハナシを書きたいと思います。 昨今、自動車業界が「自動運転」で騒がしい事はご存知だと思います。ブームの発端は Google X のプロジェクト なワケですが、中でも「セキュリティ」が盛り上がりを [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
今回は、めずらしく妄想系のハナシを書きたいと思います。
</p>
<p>
昨今、自動車業界が「自動運転」で騒がしい事はご存知だと思います。ブームの発端は <a href="http://ja.wikipedia.org/wiki/Google_%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC%E3%83%AC%E3%82%B9%E3%82%AB%E3%83%BC" title="Google ドライバーレスカー - Wikipedia">Google X のプロジェクト</a> なワケですが、中でも「セキュリティ」が盛り上がりを見せています。<br />
</a>
</p>
<p>
つい先日も <a href="http://www.securitymagazine.com/articles/86080-bmw-fixes-security-flaw-to-stop-hackers" title="BMW Fixes Security Flaw to Stop Hackers | 2015-02-02 | Security Magazine">BMW がセキュリティ上の欠陥を見つけた</a> とか、<a href="http://jalopnik.com/darpa-hacks-gms-onstar-to-remote-control-a-chevrolet-i-1684593523" title="DARPA Hacks GM&#39;s OnStar To Remote Control A Chevrolet Impala">DARPAのハッカーが、衛星通信サービスの脆弱性をついて GM のコンピュータ・ソフトウェアを書き換え、ホーンを勝手に鳴らすのはご愛嬌としても、ブレーキを利かなく出来る</a> という問題が騒がれました。期せずして、自動車業界にはセキュリティの専門家がいないということを露呈しちゃったワケです。
</p>
<p><span id="more-2291"></span></p>
<h3 class="chapter">背景</h3>
<p>
今を遡る事、??年前、マルチメディア・パソコンなるものがもてはやされた後、インターネットを使ったビジネスが流行ると言われていました。
</p>
<p>
しかし現実的には、なかなかウマいビジネス・モデルが出てきませんでした。当時、「ナゼ？」と考えていて思い当たったのが、インターネット上で安心してお金のやり取りをするには、盗まれないようにする仕組みが必要だと言う事です。
</p>
<p>
時は流れて現在、<abbr title="Internet Of Things">IoT</abbr> というキーワードがもてはやされていますが、やはり自動運転時代のビジネスが花開くためには、「セキュリティだ！」という、漠然とした思いに駆られ、去年からセキュリティの勉強を始めていたワケです。
</p>
<p>
何を隠そう、その具体的成果が <a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/misunderstanding-of-creating-wp-plugins/" title="プラグイン作者必読！実例に学ぶ脆弱なWordPressプラグインの作り方、又はwp-adminを守る理由 | ゆっくりと…">前回のエントリー</a> です。
</p>
<h3>自動車会社によるセキュリティ・エンジニアの争奪合戦が始まるゾ</h3>
<p>
今はまだ、<a href="http://next.rikunabi.com/rnc/docs/cp_s00700.jsp?__m=1424443941684-999239569657504644" title="自動車・輸送機器【メーカー】・自動運転などの求人・転職情報｜【リクナビNEXT】で転職！">セキュリティを要件とした自動車業界からの人材募集</a> は目立っていませんが、そのうちセキュリティ・エンジニアの大争奪合戦が始まるんじゃないかというのが、今の私の見解です。
</p>
<p>
大手自動車メーカーの給料って、40代で1000万ぐらいじゃないかと思っているのですが（根拠なし）、これから年収1000万から2000万ぐらい（これも根拠なし）を目指したいヒトは、自動車業界をターゲットにしたセキュリティの専門家を目指すのがイイんじゃないかと思う今日この頃です。
</p>
<p>
妄想系が過ぎますかネ？</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/web-automobile-firewall/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>プラグイン作者必読！実例に学ぶ脆弱なWordPressプラグインの作り方、又はwp-adminを守る理由</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/misunderstanding-of-creating-wp-plugins/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/misunderstanding-of-creating-wp-plugins/#respond</comments>
				<pubDate>Wed, 11 Feb 2015 10:25:53 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2284</guid>
				<description><![CDATA[セキュリティ・コンサルティング Sucuri の 2014年11月の記事 によると、WordPress プラグインの3大脆弱性は、SQL インジェクション（SQLi）、クロス・サイト・スクリプティング（XSS）、ファイル [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
セキュリティ・コンサルティング <a href="https://sucuri.net/" title="Sucuri Security — Website Protection, Malware Removal, and Blacklist Prevention">Sucuri</a> の <a href="http://blog.sucuri.net/2014/11/most-common-attacks-affecting-todays-websites.html" title="Website Security - Most Common Attacks 2014  | Sucuri Blog">2014年11月の記事</a> によると、WordPress プラグインの3大脆弱性は、SQL インジェクション（SQLi）、クロス・サイト・スクリプティング（XSS）、ファイル・インクルージョン（FI）とのことです。
</p>
<p>
<a href="https://wpvulndb.com/statistics" title="WordPress Vulnerability Statistics">冒頭のグラフ</a> は最新の分析結果で、この事実を裏付けています。プラグイン開発の <a href="http://codex.wordpress.org/Writing_a_Plugin" title="Writing a Plugin &laquo; WordPress Codex">チュートリアル</a> や <a href="https://developer.wordpress.org/plugins/" title="WordPress &#8250; Plugin Handbook | WordPress Developer Resources">手引き</a> には、脆弱性を作り込まないためのポイントが上手にまとめられているのに、なぜ無くならないのでしょうか？
</p>
<p>
「ヒトが作るものだから、バグがあって当然」と言ってしまえばそれまでですが、 <a href="http://blog.sucuri.net/category/vulnerability-disclosure" title="Vulnerability Disclosure | Sucuri Blog">Sucuri のブログ</a> を読み漁っていると、こと脆弱性に関する限り、 WordPress に特有の「思い込み」や「見過ごし」といった、ヒトの心理的・認知的な盲点が原因の多くを占めているんじゃないかと思えてきます。
</p>
<p>
だから単に PHP のセキュリティ How To ではなく、<a href="https://wordpress.org/plugins/ip-geo-block/" title="WordPress &#8250; IP Geo Block &laquo; WordPress Plugins">私が公開している唯一のプラグイン</a> の機能設計と脆弱性を作り込まない実装のために勉強したたこと − 実際に攻撃を試し脆弱性を追跡して見えてきたこと − を中心にまとめてみたいと思います。ただし具体的な攻撃方法は、元記事以上に詳しくは触れません、あしからず <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p><span id="more-2284"></span></p>
<h3 class="chapter">SQL インジェクション</h3>
<p>
端的には、 <a href="https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet#Introduction" title="SQL Injection Prevention Cheat Sheet - OWASP">OWASP の SQL インジェクション チートシート</a> に示されている「防御の3原則＋2」が基本なんだと思います。
</p>
<h4 class="chapter">OWASP の SQL インジェクション チートシート</h4>
<h5>優先すべき防御策：</h5>
<ul>
<li>オプション #1： <a href="http://php.net/manual/ja/pdo.prepared-statements.php" title="PHP: プリペアドステートメントおよびストアドプロシージャ - Manual">プリペアド・ステートメント</a> を使う（パラメータ化されたクエリ）</li>
<li>オプション #2： ストアード・プロシージャ―を使う</li>
<li>オプション #3： ユーザーからの入力は全てエスケープする</li>
</ul>
<h5>追加の防御策：</h5>
<ul>
<li>追加で強化すべき： 最小限の権限で実行する</li>
<li>追加で検討すべき： 入力はホワイトリスト方式で検証する</li>
</ul>
<p>
これらの防御原則に対し WordPress では、 <code>$wpdb->prepare()</code> や <code>esc_sql()</code>、あるいは <a href="http://codex.wordpress.org/Roles_and_Capabilities" title="Roles and Capabilities &laquo; WordPress Codex">役割りと権限</a> を検証する <a href="http://codex.wordpress.org/Function_Reference/current_user_can" title="Function Reference/current user can &laquo; WordPress Codex"><code>current_user_can()</code></a> などを準備することで、開発物をセキュアにするプログラミング環境を提供しています。
</p>
<p>
故に、これらの原則に従って対応する関数を正しく使っていれば、 SQLi は起きないハズなんですが&hellip;
</p>
<p>
次の例は「思い込み」に起因すると思われる SQLi の例です。
</p>
<h4 class="chapter"><a href="http://blog.sucuri.net/2014/08/database-takeover-in-custom-contact-forms.html" title="WordPress Security Vuln in Custom Contact Forms Plugin | Sucuri Blog">Custom Contact Forms に見る「思い込み」の盲点</a></h4>
<p>
次のコードは、① 設定を SQL ダンプしダウンロードする、② バックアップしておいた SQL をインポートする、という管理者向け機能のコードの一部です。
</p>
<p>[php]<br />
if (!is_admin()) {<br />
    &#8230;<br />
    $custom_contact_front = new CustomContactFormsFront();<br />
} else {<br />
    &#8230;<br />
    $custom_contact_admin = new CustomContactFormsAdmin();<br />
    &#8230;<br />
    add_action(&#8216;init&#8217;, &#8216;adminInit&#8217;);<br />
}</p>
<p>/* 設定のエクスポート、インポート（管理者向け）*/<br />
function adminInit() {<br />
    $this->downloadExportFile();<br />
    $this->downloadCSVExportFile();<br />
    $this->runImport();<br />
}<br />
[/php]</p>
<p>
上記コードには、最低でも5つの問題点が考えられます。
</p>
<ol>
<li>「管理者」かどうかの検証を <code>is_admin()</code> に頼っている</li>
<li>予め想定された経路が前提で、別経路でアクセスされた場合を想定していない</li>
<li>生の SQL 文を出力する仕様のため、DB のプレフィックスが暴露される</li>
<li>SQL のエクスポート、インポートに際し、権限を検証、限定していない</li>
<li>インポートでは、任意の SQL 文が実行できる</li>
</ol>
<p>
結果、誰でも DB の書き換えが可能という深刻な脆弱性が生じてしまいました。
</p>
<div id="attachment_2286" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2286" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/Custom-Contact-Forms.png" alt="ダウンロードされた生のSQL文" width="1200" height="685" class="size-full wp-image-2286" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/Custom-Contact-Forms.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/Custom-Contact-Forms-300x171.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/Custom-Contact-Forms-1024x585.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/Custom-Contact-Forms-624x356.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2286" class="wp-caption-text">ダウンロードされた生のSQL文</p></div>
<p>
1. について言えば、ここでの <code>is_admin()</code> の使い方は必ずしも間違いじゃないと思います。ただし 2. においては、「正規にログインした管理者がダッシュボードからアクセスする」という「予め想定された経路」以外にも、 <code>admin-ajax.php</code> や <code>admin-post.php</code> を直接叩くという経路があり得ます。これらには <code>admin</code> の名が付いてはいますが、管理者以外でも機能する仕様となっており、おまけに <code>is_admin()</code> を <code>true</code> にします。
</p>
<p>
よって、ある条件で <code>admin-ajax.php</code> にアクセスすると SQL ダンプが始まってしまうという、「想定外の経路」が存在する構造になっていたのです。
</p>
<p>
Sucuri が作者に連絡するも応答がなかったため、WordPress のセキュリティ・チームが急遽、対策版をリリースしました。その内容は、単に <q><code>init</code></q> へのフックを削除し、 <code>adminInit()</code> の実行を阻止するというものでした。
</p>
<p>
仮に SQLi の防御原則に則った実装をするなら、以下の様にすべきだったでしょう。
</p>
<ul>
<li>nonce（後述）を検証して特定ページからの要求である事を確認し、</li>
<li><code>current_user_can('manage_options')</code> で権限を検証し、</li>
<li>データベースへの入出力はすべてパラメータ化、</li>
<li>さらに入出力時には、値の検証と無害化をした上で、</li>
<li>適切に組み立てられエスケープされた安全な SQL 文を実行する。</li>
</ul>
<p>
この原則が見逃されてしまった要因には、 <code>is_admin()</code> への誤った「思い込み」が盲点となった事が挙げられるのではないでしょうか。<a href="https://wordpress.org/support/topic/checking-if-the-user-is-admin" title="WordPress &#8250; Support &raquo; Checking if the User is Admin">フォーラムでのディスカッション</a> が、そのことを如実に物語っているように思います。
</p>
<p>
全く同じ「思い込み」の元凶に <code>admin_init</code> フックがあり、 <code>admin-ajax.php</code> などにアクセスするとトリガーがかかるようになっています。テーマ <a href="https://wordpress.org/themes/platform" title="WordPress &#8250; Platform &laquo; Free WordPress Themes">Platform</a> の <a href="http://blog.sucuri.net/2015/01/security-advisory-vulnerabilities-in-pagelinesplatform-theme-for-wordpress.html" title="Security Advisory &#8211; Vulnerabilities in Pagelines/Platform theme for WordPress | Sucuri Blog">任意の PHP コードが注入できてしまう脆弱性</a> や、プラグイン <a href="https://wordpress.org/plugins/wysija-newsletters/" title="WordPress &#8250; MailPoet Newsletters &laquo; WordPress Plugins">MailPoet</a> の <a href="http://blog.sucuri.net/2014/07/remote-file-upload-vulnerability-on-mailpoet-wysija-newsletters.html" title="WordPress Security Vuln in MailPoet Plugin | Sucuri Blog">任意のファイルがアップロードできてしまう脆弱性</a> が同種の例として報告されちゃってます。
</p>
<p>
「<code>admin</code> の名が付いたファイルやフックには気を付けろ！」ってことですネ。
</p>
<h5>2015年2月18日 追記</h5>
<p>
<a href="http://codex.wordpress.org/Plugin_API/Action_Reference/admin_init" title="Plugin API/Action Reference/admin init &laquo; WordPress Codex"><code>admin_init</code> の公式ドキュメント</a> には、管理画面へのアクセスを管理者に限定するコードが載っていますが、一般ユーザーによる公開ページの Ajax も許容するコードになっているので、コピペする時は注意しましょう <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h3 class="chapter">XSS</h3>
<p>
XSS の詳しい話は <a href="http://www.ipa.go.jp/security/vuln/websecurity.html" title="安全なウェブサイトの作り方：IPA 独立行政法人 情報処理推進機構">専門家</a> に譲りますが、ほとんどの場合、外からやって来るデータ（DB から読み出したものを含む）の検証漏れか、出力前のエスケープ漏れでしょう（「<a href="http://www.ipa.go.jp/files/000017316.pdf" title="安全なウェブサイトの作り方">安全なウェブサイトの作り方</a>」によると、前者は「保険的対策」、後者は「根本的対策」とされています）。
</p>
<p>
まずは、「これじゃあ漏れも仕方ない」的な例を紹介します。
</p>
<h4 class="chapter"><a href="https://wpvulndb.com/vulnerabilities/7773" title="Blubrry PowerPress &lt;= 6.0 - Cross-Site Scripting (XSS)">Blubrry PowerPress に見る「見過ごし」の例</a></h4>
<p>
下の表を見れば分かりますが、 <a href="https://wordpress.org/plugins/powerpress/" title="WordPress &#8250; Blubrry PowerPress Podcasting plugin &laquo; WordPress Plugins">Blubrry PowerPress</a> では、最初から XSS が未対策だったワケじゃありません。
</p>
<div class="table-responsive">
<table>
<thead>
<tr>
<th rowspan="2" style="vertical-align:bottom">対策</th>
<th colspan="2" style="text-align:center">PHP</th>
<th rowspan="2" style="text-align:center; vertical-align:bottom"><code>htmlspecialchars</code></th>
<th rowspan="2" style="text-align:center; vertical-align:bottom"><code>esc_html</code></th>
<th rowspan="2" style="text-align:center; vertical-align:bottom"><code>esc_attr</code></th>
</tr>
<tr>
<th style="text-align:center">ファイル数</th>
<th style="text-align:center">行数</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">前</td>
<td style="text-align:center">42</td>
<td style="text-align:center">36280</td>
<td style="text-align:center">274</td>
<td style="text-align:center">82</td>
<td style="text-align:center">153</td>
</tr>
<tr>
<td style="text-align:center">後</td>
<td style="text-align:center">33</td>
<td style="text-align:center">22807</td>
<td style="text-align:center">160</td>
<td style="text-align:center">53</td>
<td style="text-align:center">131</td>
</tr>
</tbody>
</table>
</div>
<p>
対策前後のコードの一例を以下に示しますが&hellip; 何と言うか&hellip; 一言で表せば、追跡するのがとても厄介なコードです（すいません、想像してください <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f610.png" alt="😐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ）。そして至る所にパッチが当てられ、その対策の慌てっぷりがヒシヒシと伝わってきます <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p>[php]<br />
/* before */<br />
&lt;input type=&quot;hidden&quot; &#8230; value=&quot;&lt;?php echo empty($_POST[&#8216;tab&#8217;]) ? 0 : $_POST[&#8216;tab&#8217;]; ?&gt;&quot; /&gt;<br />
/* after  */<br />
&lt;input type=&quot;hidden&quot; &#8230; value=&quot;&lt;?php echo empty($_POST[&#8216;tab&#8217;]) ? 0 : intval($_POST[&#8216;tab&#8217;]) ); ?&gt;&quot; /&gt;</p>
<p>/* before */<br />
powerpress_page_message_add_error( &#8230;, $_POST[&#8216;feed_slug&#8217;]) );<br />
/* after  */<br />
powerpress_page_message_add_error( &#8230;, esc_html($_POST[&#8216;feed_slug&#8217;]) ) );</p>
<p>/* before */<br />
echo &#8216;&lt;rawvoice:metamark type=&quot;&#8217;. $MetaMark[&#8216;type&#8217;] .&#8217;&quot;&#8217;;<br />
/* after  */<br />
echo &#8216;&lt;rawvoice:metamark type=&quot;&#8217;. esc_attr($MetaMark[&#8216;type&#8217;]) .&#8217;&quot;&#8217;;</p>
<p>/* before */<br />
&#8216;&lt;em&gt;&#8217;. htmlspecialchars($post_title) .'&lt;/em&gt;&#8217;,<br />
&#8216;&lt;em&gt;&#8217;. $feed_slug .'&lt;/em&gt;&#8217; );<br />
/* after  */<br />
&#8216;&lt;em&gt;&#8217;. htmlspecialchars($post_title) .'&lt;/em&gt;&#8217;,<br />
&#8216;&lt;em&gt;&#8217;. htmlspecialchars($feed_slug) .'&lt;/em&gt;&#8217; );<br />
[/php]</p>
<p>
こういったヤッツケ仕事的パッチワークの問題点は、「対策漏れ」がないかの検証が難しいこと、そして <code>htmlspecialchars()</code> と <code>esc_html()</code> の混在など、統一性のない対策方針が果たして正しいのか判断がつかない事ではないでしょうか？
</p>
<p>
私には、混在（要は、省略されたパラメータの扱い）が直ちに問題となる例題は示せませんし、実際、大丈夫なのかもしれません。しかし WordPress という系の中では、コアチームが熟成させてきた関数群を使うべきだと思っています（例えば <code>esc_html()</code> の内部では <a href="http://blog.ohgaki.net/correct-htmlentities-htmlspecialchars-usage" title="htmlspecialchars/htmlentitiesの正しい使い方 | yohgaki&#039;s blog">厳密性の高い <code>htmlspecialchars()</code> の使い方</a> がされている）。
</p>
<p>
追記：徳丸さんの <a href="http://blog.tokumaru.org/2014/12/phpphp.html" title="&#12302;例えば&#12289;PHPを避ける&#12303;以降PHPはどれだけ安全になったか | 徳丸浩の日記">&#12302;例えば&#12289;PHPを避ける&#12303;以降PHPはどれだけ安全になったか | 徳丸浩の日記</a> に <code></code> の第３パラメータについて詳しく解説されていました。
</p>
<h4 class="chapter">入力の検証と出力のエスケープ、およびモデルとビューの分離</h4>
<p>
「見過ごし」を防ぐ上で大事なことは、「モデル」における「入力の検証」と、「ビュー」における「出力のエスケープ」と言った具合に、見通しのよい設計と実装をする事だと思います（注：ここでは MVC の話をしているつもりはありません）
</p>
<p>
ちょっと厳しい言い方ですが、先のコードはこれら2つが混沌としているため、「対策漏れ」が起きて当然と言われても仕方ありません。
</p>
<p>
Codex の <a href="http://codex.wordpress.org/Validating_Sanitizing_and_Escaping_User_Data" title="Validating Sanitizing and Escaping User Data &laquo; WordPress Codex">Validating Sanitizing and Escaping User Data</a> と <a href="http://codex.wordpress.org/Data_Validation" title="Data Validation &laquo; WordPress Codex">Data Validation</a>（<a href="http://wpdocs.sourceforge.jp/Data_Validation" title="データ検証 - WordPress Codex 日本語版">日本語版</a>）には、XSS や SQLi、 <abbr title="ディレクトリ・トラバーサル">DT</abbr> など、様々な攻撃を阻止するための入出力に関する検証と無害化の関数群がリストアップされています。
</p>
<p>
ただし一部、日本で語られている考え方やネーミングと、多少の違いと混乱があるので要注意です。例えば、不要なタグやコードを削除する「入力の検証（クリーニング）」の関数群が <code>sanitize_*()</code> というネーミングになっていたり、「出力のサニタイジング」にエスケープ処理を施す関数群 <code>esc_*()</code> と <code>sanitize_text_field()</code> が混在していたり、といった具合です。
</p>
<p>
いずれにしても、見通しの良い設計と共に、これらの関数群をコードの文脈に合わせて適切に使うことが肝要でしょう。
</p>
<p>
最後に蛇足ですが、<a href="http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/602.html" title="IPA ISEC　セキュア・プログラミング講座：Webアプリケーション編　第7章 エコーバック対策：スクリプト注入: #2 攻撃の解説">IPA セキュア・プログラミング講座</a> にある「スクリプトが動作する箇所」の図と WordPress の <code>esc_*()</code> 関数との対応を取ってみました。
</p>
<p>
図を描いてみて分かったのですが、 <code>expression</code> 攻撃を阻止する関数は無さそうなので、外から入力されたデータを <code>style</code> 属性に注入するのは避けた方が良さそうですネ。
</p>
<div id="attachment_2287" style="width: 1210px" class="wp-caption aligncenter"><a href="http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/602.html" title="IPA ISEC　セキュア・プログラミング講座：Webアプリケーション編　第7章 エコーバック対策：スクリプト注入: #2 攻撃の解説"><img aria-describedby="caption-attachment-2287" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/wp-esc-function.png" alt="スクリプトが動作する箇所と対応するWordPress関数" width="1200" height="860" class="size-full wp-image-2287" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/wp-esc-function.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/wp-esc-function-300x215.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/wp-esc-function-1024x734.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/wp-esc-function-624x447.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /></a><p id="caption-attachment-2287" class="wp-caption-text">スクリプトが動作する箇所と対応するWordPress関数</p></div>
<h4 class="chapter"><a href="http://blog.sucuri.net/2014/12/critical-vulnerability-in-joomla-hd-flv-player-plugin.html" title="Critical vulnerability affecting HD FLV Player - Sucuri Disclosure | Sucuri Blog">HD FLV Player に見る「見過ごし」の例</a></h4>
<p>
<a href="https://wordpress.org/plugins/wp-flash-player/" title="WordPress &#8250; FLASH PLAYER PLUGIN &laquo; WordPress Plugins">FLASH PLAYER PLUGIN</a> の古いバージョンと PHP バージョン 5.3.4 以前との組み合わせには、任意のファイルがダウンロードできるという脆弱性が存在します。
</p>
<p>
<a href="http://blog.sucuri.net/2014/12/critical-vulnerability-in-joomla-hd-flv-player-plugin.html" title="Critical vulnerability affecting HD FLV Player - Sucuri Disclosure | Sucuri Blog">Sucuri の報告</a> には、以下の様な <code>download.php</code> のコードが掲載されています。
</p>
<p>[php]<br />
$finename = $_GET[&#8216;f&#8217;];<br />
header(&#8216;Content-disposition: attachment; filename=&#8217; . basename($filename));<br />
readfile($filename);<br />
[/php]</p>
<p>
実際にはこれほど単純ではなく、 <code>$finename</code> に対して、絶対パスの追加と拡張子の検証が行われています。しかし、ディレクトリ・トラバーサルの検証（<a href="http://codex.wordpress.org/Function_Reference/validate_file" title="Function Reference/validate file &laquo; WordPress Codex"><code>validate_file()</code></a> で可能です）や <a href="http://gihyo.jp/dev/serial/01/legacy-php/0005" title="第5回　ファイル名にNULLを含む場合に無効化するパッチ：レガシーPHPのセキュリティ対策，大丈夫ですか？｜gihyo.jp … 技術評論社">NULL バイト攻撃</a> の検証が見過ごされたため、一撃で破られるシングル・フェイルとなってしまいました。
</p>
<p>
また <code>download.php</code> が WordPress とは無関係に単独で実行出来るようになっていたという点も問題でしょう。<code>wp-load.php</code> を読み込んだり、 <code>admin-ajax.php</code> や <code>admin-post.php</code> 経由で <a href="http://ja.wikipedia.org/wiki/%E3%83%8E%E3%83%B3%E3%82%B9" title="ノンス - Wikipedia">nonce</a> や権限を検証するなど、 WordPress の仕組みを使うべきだったのではないか、と思います。
</p>
<p>
先の <code>htmlspecialchars()</code> にも言える事ですが、僅かな処理時間の増加をケチったんだとすると、その結果、脆弱性を作り込んでしまっては、本末転倒と言えるのではないでしょうか？
</p>
<h4>2015年5月23日 追記</h4>
<p>
PHP 5.3.4 以前には、ファイル・システム系の関数が <q><a href="https://bugs.php.net/bug.php?id=39863" title="PHP :: Request #39863 :: file_exists() silently truncates after a null byte">NULL バイトの攻撃に弱いという問題</a></q> がありましたが、5.3.4 で <a href="http://php.net/releases/5_3_4.php" title="PHP: PHP 5.3.4 Release Announcement">チェックが強化</a> されました。
</p>
<p>
手元の環境で調べてみた結果は以下の通りです。
</p>
<div class="table-responsive">
<table>
<thead>
<tr>
<th rowspan=2 style="text-transform:none; vertical-align:bottom">Ver.</th>
<th colspan=2 style="text-transform:none; text-align:center"><code>$file = "/etc/passwd¥0.php";</code></th>
</tr>
<tr>
<th style="text-transform:none"><code>is_file( $file )</code></th>
<th style="text-transform:none"><code>is_readable( $file )</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>5.2.14</td>
<td><code>true</code></td>
<td><code>true</code></td>
</tr>
<tr>
<td>5.4.4</td>
<td><code>false</code></td>
<td><code>false</code></td>
</tr>
</tbody>
</table>
</div>
<p>
当然このまま <code>include( $file )</code> とかすると、パスワードがバッと表示されちゃいます。WordPress は PHP 5.2.4（推奨は 5.4 以上）から使える事になっているので、拡張子を調べるだけじゃダメで、 <code>str_replace( "¥0", "", $file )</code> などによる NULL バイトの無効化が必須というワケです。
</p>
<p>
この辺りは <a href="http://www.asahi-net.or.jp/~wv7y-kmr/memo/php_security.html">PHP と Web アプリケーションのセキュリティについてのメモ</a> がとても参考になるので、一読を激しく推奨します。
</p>
<h3 class="chapter">権限昇格（<abbr title="Privilege Escalation">PE</abbr>）</h3>
<p>
WordPress における nonce を一言で表せば、「今、このページにアクセスしているユーザーだけが知りえる秘密の情報」です。詳しくは拙作の <q><a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/most-common-mistakes-in-wordpress-plugins-coding/">WordPressプラグインのコーディングでありがちな10の間違いと設計時に考慮すべきこと</a></q> や <q><a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/secured-ajax-with-wp-nonce/">初歩からわかるWordPressのnonceでAjaxをセキュアに実装する方法</a></q> を参照してください。
</p>
<p>
でもその nonce だって漏れるんです。漏れると、単なるユーザーが管理者の権限にまで昇格しちゃうんです。次は、そんな脆弱性の紹介です。
</p>
<h4 class="chapter"><a href="http://blog.sucuri.net/2015/02/advisory-dangerous-nonce-leak-in-updraftplus.html" title="Advisory &#8211; Dangerous &quot;nonce&quot; leak in UpdraftPlus | Sucuri Blog">UpdraftPlus に見る「思い込み」の盲点</a></h4>
<p>
登録ユーザーのダッシュボード上で <code>wp-admin/?action=hogehoge</code> にアクセスすると <code>hogehoge_handler()</code> にフックされるようにしたとします。
</p>
<p>[php]<br />
add_action( &#8216;admin_action_hogehoge&#8217;, &#8216;hogehoge_handler&#8217; );<br />
[/php]</p>
<p>
このハンドラは <code>wp-content/plugin/hogehoge/admin.php</code> で定義され、「何か」する目的で、ブラウザに次の様な出力をするものとします。
</p>
<p>[php]<br />
function hogehoge_handler() {<br />
    &#8230;<br />
    ?&gt;<br />
    &#8230;<br />
    &lt;input type=&#8221;hidden&#8221; name=&#8221;_wpnonce&#8221; value=&#8221;&lt;?php echo wp_create_nonce(&#8216;hogehoge-secret-nonce&#8217;);?&gt;&#8221;&gt;<br />
    &#8230;<br />
    &lt;?php<br />
}<br />
[/php]</p>
<p>
この登録ユーザー向け秘密情報のタネである <code>'hogehoge-secret-nonce'</code> が、管理者向けのタネと共通で使われていたりすると、ちょっと心配な事になります。いわゆる「秘密情報の漏洩」ですネ。
</p>
<p>
さらに別の管理者向けハンドラでは、 <code><a href="http://codex.wordpress.org/Function_Reference/check_admin_referer" title="Function Reference/check admin referer &laquo; WordPress Codex">check_admin_referer</a>('hogehoge-secret-nonce')</code> による nonce の検証を行っただけで管理者権限の検証が漏れたりすると、いわゆる「権限昇格」が起きてしまうのです。
</p>
<p>
<a href="https://wordpress.org/plugins/updraftplus/" title="WordPress &#8250; UpdraftPlus Backup and Restoration &laquo; WordPress Plugins">UpdraftPlus</a> が正にこのパターンにハマってしまいました。また同様の脆弱性は、あの有名な <a href="https://wordpress.org/plugins/wptouch/" title="WordPress &#8250; WPtouch Mobile Plugin &laquo; WordPress Plugins">WPtouch</a> でも <a href="http://blog.sucuri.net/2014/07/disclosure-insecure-nonce-generation-in-wptouch.html" title="WordPress Security Vuln in WPTouch Plugin | Sucuri Blog">報告されています</a>。
</p>
<p>
これらも一種の「思い込み」と言えるでしょう。
</p>
<h3 class="chapter"><abbr title="Cross Site Request Forgeries">CSRF</abbr></h3>
<p>
<a href="http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA" title="クロスサイトリクエストフォージェリ - Wikipedia">CSRF</a> が起きる原因は単純です。
</p>
<p>
例えば管理画面で「変更を保存」のボタンを押すと、内部で保存処理をして新しい画面に遷移しますが、遷移前の画面に nonce が埋め込まれていなかったり、保存処理の前に nonce がチェックされていなかったりすると、即 CSRF となります。
</p>
<p>
この場合、保存処理の所で管理者の権限を検証するだけでは CSRF は防げません。管理者が自らのクッキーを持ったまま悪意のあるリンクを踏んで起きる脆弱性だからです。
</p>
<p>
「管理者かどうかチェックしているから大丈夫」という「思い込み」があったのでしょうか、 <a href="https://wpvulndb.com/search?text=&#038;vuln_type=3" title="Search">Sucuri のデータベース</a> からは、有名どころの <a href="https://wordpress.org/plugins/w3-total-cache/" title="WordPress &#8250; W3 Total Cache &laquo; WordPress Plugins">W3 Total Cache</a> を始め、この脆弱性を持ったプラグインが数多く検索されます。
</p>
<p>
オプションの保存処理であれば、 nonce の生成・検証と管理者権限の検証の両方を確実に行ってくれる <a href="http://wpdocs.sourceforge.jp/Settings_API" title="Settings API - WordPress Codex 日本語版">Settings API</a> を積極的に使うのが吉でしょう。
</p>
<h5>2018年2月18日 追記</h5>
<p>
<q><a href="http://hetarena.com/archives/2039" title="WordPress での CSRF 対策 | ヘタレな趣味の道">WordPress での CSRF 対策 &#8211; nonce ってナンスか？</a></q> がとても分かり易かったので、一読推奨です <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h3 class="chapter">ファイル・インクルージョン（<abbr title="File Inclusion">FI</abbr>）</h3>
<p>
<a href="http://hakipedia.com/index.php/File_Inclusion" title="File Inclusion - Hakipedia">FI</a> は、ファイルシステム系の関数に検証が十分でない入力を与える事で起きる脆弱性です。2014年9月には、 <code>file_get_contents()</code> を介して <a href="https://wpvulndb.com/vulnerabilities/7540" title="WordPress Slider Revolution Vulnerability">任意のファイルがダウンロードできてしまう</a> という <a href="http://revolution.themepunch.com/" title="Slider Revolution Responsive WordPress Plugin">Slider Revolution</a> の <a href="http://hakipedia.com/index.php/Local_File_Inclusion" title="Local File Inclusion - Hakipedia">LFI</a> が報告されました。
</p>
<h4 class="chapter"><a href="http://blog.sucuri.net/2014/09/slider-revolution-plugin-critical-vulnerability-being-exploited.html" title="WordPress Security Vuln in Slider Revolution Plugin | Sucuri Blog">Slider Revolution に見る「思い込み」の盲点</a></h4>
<p>
管理者向けのある機能に対し、<code>admin-ajax.php</code> を経由した次の様な攻撃で、任意のファイルが漏洩します（本サイトにも未だに時々やってきます）。
</p>
<p>[html]<br />
http://victim.com/wp-admin/admin-ajax.php?action=revslider_show_image&#038;img=../wp-config.php<br />
[/html]</p>
<div id="attachment_2288" style="width: 1210px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2288" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/slider-revolution.png" alt="Slider Revolutionの脆弱性により漏洩したwp-config.php" width="1200" height="586" class="size-full wp-image-2288" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/slider-revolution.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/slider-revolution-300x147.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/slider-revolution-1024x500.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/02/slider-revolution-624x305.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /><p id="caption-attachment-2288" class="wp-caption-text">Slider Revolutionの脆弱性により漏洩したwp-config.php</p></div>
<p>
Slider Revolution では、管理者用クラスの中で <code>admin-ajax.php</code> に対するアクション・ハンドラが登録されます。しかし同ハンドラでは、以下の様な検証が全く行われないまま <code>file_get_content()</code> を呼び出していました。
</p>
<ul>
<li>お約束の nonce を検証していない</li>
<li>実行しようとしているユーザーの権限を検証、制限していない</li>
<li>ディレクトリー・トラバーサルの検証やパスの限定など、入力の検証と無害化をしていない</li>
</ul>
<p>
問題の構造は冒頭の SQLi と同じですネ。 <code>admin-ajax.php</code> のネーミングに由来する「管理者向け」という「思い込み」が原因です<span style="color:red"> *</span>。想定が「管理者」だとしても、何らかの脆弱性で権限昇格だってあり得るんだから、他の検証を省略できるってことにはならないのです！
</p>
<p>
<span style="color:red">*</span> 断定根拠： 有料販売もしているプラグインですョ、上記の様な基本的な検証が全く実装されていないなんて、あり得ないじゃないですか！
</p>
<h3 class="chapter">まとめ</h3>
<p>
今回分析した案件の多くが、<code>admin</code> の名前が付く関数やアクションフックに対する「思い込み」によるものと推察（一部は断定）しました。また数の多い XSS では、「見過ごし」が起き難い設計が重要との認識を新たにしました。
</p>
<p>
心構えとしては、常に攻撃側／非攻撃側という2つの側面から、コードの1行1行に「盲点がないか」を問いかけるってことでしょうか。
</p>
<p>
とどのつまり、性善説じゃダメで、次のような性悪説を元に開発に臨むというのが個人的な結論です。
</p>
<ul>
<li>入力は汚染されている</li>
<li>DB は改ざんされている</li>
<li>秘密の情報は漏洩する</li>
<li>管理者権限は回避、奪取される</li>
<li>攻撃は想定外の経路から来る</li>
<li>実際に今、ページにアクセスしているワケではない</li>
</ul>
<p>
攻撃者はさらにプラットフォーム（OS やら PHP、時には WordPress コア）自体に内在する脆弱性とを組み合わせてきます。
</p>
<p>
これらを全て防ぐのって大変なことですが、こと WordPress という <a href="https://kotobank.jp/word/%E3%82%A8%E3%82%B3%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-185508" title="エコシステム(えこしすてむ)とは - コトバンク">エコシステム</a> に関して言えば、防御に必要な仕組みはコア開発の方々が揃えてくれているので、後は「使いこなし」ってことで、この記事を〆たいと思います。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/misunderstanding-of-creating-wp-plugins/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>プラグインなしから発想するWordPressセキュリティ &#8211; IP Geo Blockの更新告知</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/baseline-of-wordpress-security/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/baseline-of-wordpress-security/#respond</comments>
				<pubDate>Wed, 28 Jan 2015 22:32:31 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[BBS spam]]></category>
		<category><![CDATA[pingback]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[trackback]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2276</guid>
				<description><![CDATA[昨年末、一晩で15000余りの パスワード辞書によるクラッキング を受けました。その時のログを分析してみて改めて思ったのは、「これだけランダムで長けりゃ大丈夫」的なパスワードも、「漏れたら終わり」って事です。 「ランダム [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
昨年末、一晩で15000余りの <a href="http://ja.wikipedia.org/wiki/%E8%BE%9E%E6%9B%B8%E6%94%BB%E6%92%83" title="辞書攻撃 - Wikipedia">パスワード辞書によるクラッキング</a> を受けました。その時のログを分析してみて改めて思ったのは、「これだけランダムで長けりゃ大丈夫」的なパスワードも、「漏れたら終わり」って事です。
</p>
<p>
「ランダムで長いパスワード」をアカウント毎に頻繁に変えるのは面倒なワケで、長い間変えずに使い続けと、漏洩時のリスクが極めて高くなるってことだと思います。
</p>
<p>
おっと、何も <q><a href="http://tumblr.tokumaru.org/post/38756508780/about-changing-passwords-regularly" title="パスワードの定期的変更に関する徳丸の意見まとめ - 徳丸浩のtumblr">パスワードの定期変更は必要か</a></q> の議論へ乱入しようというワケじゃありません。
</p>
<p>
IPアドレスのジオロケーション情報を元に海外からの投稿を弾くスパム対策プラグイン <a href="https://github.com/tokkonopapa/WordPress-IP-Geo-Block" title="tokkonopapa/WordPress-IP-Geo-Block">IP Geo Block</a> に、<code>wp-login.php</code> や <code>wp-admin/admin.php</code>、<code>xmlrpc.php</code> へのアクセスを遮断するセキュリティ機能、さらにはログを記録する機能を追加したので、その告知が本記事の主題です <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p><span id="more-2276"></span></p>
<h3 class="chapter">IP Geo Blockの制作コンセプト</h3>
<blockquote><p>
WordPress がセキュリティ的に最も強固なのは、「テーマはデフォルト、プラグインは使用せず」という素の状態である
</p></blockquote>
<p>
何か目新しいことを言っているつもりはありません。サーバー設定、<a href="https://ja.forums.wordpress.org/topic/1880" title="WordPress &#8250; フォーラム &raquo; wp-config.phpのパーミッションは何にしておくのがベストでしょうか？">パーミション設定</a>、強いパスワードなど、<a href="https://ja.forums.wordpress.org/topic/408" title="WordPress &#8250; フォーラム &raquo; インストール後　安全のために必要なこと">基本的な条件を整えた後</a> は、プラグインまみれの WordPress より、クリーン・インストール直後の WordPress の方が、脆弱性を抱える可能性が低いってことです。
</p>
<p>
ハッカーやクラッカーに、「なぜハッキングやクラッキングをするのか」と問えば、「そこに脆弱性があるから」と答えるかは分かりませんが（それぞれ目的が違いますからネ）、テーマを弄り、有象無象のプラグインを使い出す結果、脆弱性を抱え込むことになります。
</p>
<p>
そこでセキュリティ・プラグインの出番となるワケですが、単機能で物足りなかったり、<a href="https://wordpress.org/plugins/better-wp-security/" title="WordPress › iThemes Security (formerly Better WP Security) « WordPress Plugins">iThemes Security</a> や <a href="https://wordpress.org/plugins/bulletproof-security/" title="WordPress &#8250; BulletProof Security &laquo; WordPress Plugins">BulletProof Security</a>、<a href="https://wordpress.org/plugins/wordfence/" title="WordPress › Wordfence Security « WordPress Plugins">Wordfence Security</a> などの <q>フルスペック</q> なプラグインでは、多機能過ぎて設定が難しかったり重たかったりと、私的には「単機能以上、重量級未満」の <q>ちょうどいいサイズ</q> のプラグインがあってもイイんじゃないかと思ってました。
</p>
<p>
速度比較については後述しますが、例えば Wordfence Security では明らかにページの応答速度が悪化します（しかも128Mのメモリを要求する！）。
</p>
<p>
ということで、今回も自分が <q>ちょうどいい</q> と思う機能をだけを実装しました:D。
</p>
<h4 class="chapter">出来る限りシンプルかつ軽量に</h4>
<p>
ウチの様な共有サーバーでも問題なく使えるよう、<a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-block-wordpress-plugin/" title="海外からの投稿を弾くスパム対策用WordPressプラグインをリリースします | ゆっくりと…">従来の遮断機能</a> に加え、WordPress が標準で備えている幾つかの典型的な「入口」を遮断対象に追加しました。実際、コア部分は、コメントを含め60行弱の PHP を追加した程度です。
</p>
<p>
またシンプルな故、例えばIPアドレスの国別遮断機能がプレミアム版のみで提供される Wordfence Security と組み合わせるのも、有効だと思います。
</p>
<h4 class="chapter">ログ機能は手厚く</h4>
<p>
私が借りている LaCoocan では、月別の統計的アクセスレポートはあるものの、個別のアクセスログを見ることができません。そのため、いつ何処にどんな攻撃を受けたかを特定する手がかりが少なく、攻撃の事前対策や事後処理が困難です。
</p>
<p>
有名なプラグインに <a href="https://wordpress.org/plugins/crazy-bone/" title="WordPress &#8250; Crazy Bone &laquo; WordPress Plugins">狂骨</a> がありますが、ログする対象を <code>xmlrpc.php</code> や <code>admin-ajax.php</code> にも拡大した感じと思ってもらえれば良いと思います。
</p>
<h4 class="chapter">オプションは極力少なく、拡張性は高く</h4>
<p>
誰かが使うかもしれない機能をオプションに組み込んで無闇にコードを肥大化させるより、各所にアクション・フックを設けて拡張性を残すことを選びました。またユースケース別サンプルコードを <a href="https://github.com/tokkonopapa/WordPress-IP-Geo-Block/blob/master/ip-geo-block/samples.php" title="WordPress-IP-Geo-Block/samples.php at master - tokkonopapa/WordPress-IP-Geo-Block - GitHub">sample.php</a> に載せ、同梱しています。
</p>
<h3 class="chapter">機能の概要</h3>
<h4 class="chapter">ログ機能</h4>
<p>
より詳しい情報が得られるよう、<code>$_POST</code> データのキーを指定すると、その中身を展開して記録する機能を持たせました。
</p>
<div id="attachment_2277" style="width: 1210px" class="wp-caption aligncenter"><a href="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login.png" class="highslide" onclick="return hs.expand(this)"><img aria-describedby="caption-attachment-2277" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login.png" alt="$_POSTデータのキーを展開して記録" width="1200" height="840" class="size-full wp-image-2277" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login-300x210.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login-1024x717.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-login-624x437.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /></a><p id="caption-attachment-2277" class="wp-caption-text">$_POSTデータのキーを展開して記録</p></div>
<p>
ログは、カテゴリ毎に DB 上のリング・バッファ（最大100個で固定）に記録されます。また攻撃の事後に解析できるよう、選択的にバックアップ・ファイルを残すためのアクション・フックも設けました。
</p>
<p>[php]<br />
/**<br />
 * パスワードが破られたか否かを後で確認できるようバックアップする<br />
 *<br />
 * @param  string $hook &#8216;comment&#8217;, &#8216;xmlrpc&#8217;, &#8216;login&#8217;, &#8216;admin&#8217; のいずれか<br />
 * @return string $path 非公開領域への絶対パス、または null（バックアップなし）<br />
 */<br />
function my_backup_dir( $hook ) {<br />
    if ( &#8216;login&#8217; === $hook )<br />
        return &#8216;/absolute/path/to/&#8217;;<br />
    else<br />
        return null;<br />
}<br />
add_filter( &#8216;ip-geo-block-backup-dir&#8217;, &#8216;my_backup_dir&#8217; );<br />
[/php]</p>
<p>
バックアップは CSV フォーマットのテキストファイルとして月別に記録されます。<code>public_html</code> などの公開領域以外で書き込み可能な場所を指定して下さい。
</p>
<h4 class="chapter">遮断機能</h4>
<p>
本プラグインでは、WordPress で最も基本的かつ重要な以下の4カテゴリ、7つの投稿・攻撃パターンを遮断対象としています。
</p>
<h5 class="chapter"><code>wp-comments-post.php</code></h5>
<p>
2014年11月21日、WordPress コアに存在した <abbr title="Cross Site Scripting">XSS</abbr>、<abbr title="Cross Site Request Forgeries">CSRF</abbr>、<abbr title="Server Side Request Forgery">SSRF</abbr> 脆弱性を修正する <a href="https://ja.wordpress.org/2014/11/21/wordpress-4-0-1-security-release/" title="WordPress &#8250; 日本語 &laquo; WordPress 4.0.1 セキュリティリリース">4.0.1 セキュリティ・アップデート版がリリース</a> されました。
</p>
<p>
この中には、ダッシュボード上で管理者が承認待ちのコメントを確認すると、管理者権限を攻撃者が取得できてしまうという、<a href="http://jvndb.jvn.jp/ja/cwe/CWE-79.html" title="CWE-79">格納型（蓄積型あるいは持続的）XSS</a> の修正が含まれています（<a href="http://blog.sucuri.net/2014/11/protecting-against-unknown-software-vulnerabilities.html" title="Website Security - Protecting The Unknown - Software Vulnerabilities | Sucuri Blog">出典1</a>、<a href="http://www.computerworld.com/article/2850883/critical-xss-flaws-patched-in-wordpress-and-popular-plug-in.html" title="Critical XSS flaws patched in WordPress and popular plug-in | Computerworld">出典2</a>）。
</p>
<p>
コメントの投稿とトラックバックはここで受けますが、余計なものは内部に取り込まないのが一番ということでしょう。
</p>
<h5 class="chapter"><code>xmlrpc.php</code></h5>
<p>
実はコレがとってもヤバいんです。その名の通り XML による <q><a href="http://ja.wikipedia.org/wiki/RPC" title="RPC - Wikipedia">遠隔命令を実行する手続き</a></q> の入口なんですが、単にピンバック・スパムの温床になるだけじゃなく、<a href="http://blog.sucuri.net/2014/03/more-than-162000-wordpress-sites-used-for-distributed-denial-of-service-attack.html" title="More Than 162,000 WordPress Sites Used for Distributed Denial of Service Attack | Sucuri Blog">ピンバックを悪用した DDoS 攻撃の踏み台</a> <span style="vertical-align:super; color:red; font-size:small">*1</span> に使われたり、<code>wp-login.php</code> と同様にクラッキングの対象になったり、また古くは <a href="http://www.acunetix.com/blog/web-security-zone/wordpress-pingback-vulnerability/" title="WordPress Pingback Vulnerability Found in WordPress 3.5">ポートスキャン</a> が出来たりなど、いっそ閉じておくのが当然のようなシロモノです。
</p>
<p>
<span style="color:red">*1</span>： WordPress 3.9.2 でピンバックによる <abbr title="Distributed Denial of Service">DDoS</abbr> 攻撃関連の <a href="https://wordpress.org/news/2014/08/wordpress-3-9-2/" title="WordPress &#8250; WordPress 3.9.2 Security Release">セキュリティ・アップデート</a> が、また <a href="http://akismet.com/" title="Comment spam prevention for your blog - Akismet">Akismet</a> でも <a href="http://blog.akismet.com/2014/03/18/akismet-plugin-2-6/" title="Akismet WordPress plugin 2.6.0 | Moderation Queue">関連するアップデート</a>（<a href="http://ja.naoko.cc/2014/03/19/akismet-update-address-pinback-ddos-risks/" title="ピンバック悪用の踏み台攻撃防止に対応した Akismet 2.6 がリリース | ja.naoko.cc">日本語記事</a>）がリリースされています。
</p>
<p>
一方で私も使ってますが、<a href="https://apps.wordpress.org/" title="WordPress.org Mobile Apps">WordPress.org 公式のモバイルアプリ</a> や <a href="http://jetpack.me/" title="Jetpack for WordPress">Jetpack</a> の一部機能には XML-RPC が必要で、公式サイトの FAQ では、<a href="https://apps.wordpress.org/support/#faq-ios-12" title="Support | WordPress.org Mobile Apps">XML-RPC が禁止されているサーバー用回避プラグイン</a> が紹介されているぐらいです。
</p>
<p>
本プラグインでは XML-RPC の利便性を残すため、海外からのアクセスを弾くのは勿論、クラッキングと見なせるアクセスに対しては、<code>wp-login.php</code> と同様、国内外を問わず認証の試行回数を制限する機能を実装しました。
</p>
<h5 class="chapter"><code>wp-login.php</code></h5>
<p>
パスワードのクラッキングは国内から受ける場合もあり得ます。そこで「国内外を問わず、認証失敗が一定回数（現状は5回で固定）を超えた場合、そのIPアドレスからの認証要求を一時的に禁止」します（禁止期間はIPアドレスのキャッシュ保持期間と連動で、デフォルトは60分です）。
</p>
<p>
同様の機能は <a href="https://wordpress.org/plugins/login-lockdown/" title="WordPress &#8250; Login LockDown &laquo; WordPress Plugins">Login LockDown</a> が有名です。こちらはIPアドレスだけではなく、ユーザー・アカウント単位でも認証の試行回数が管理されていて、brute-force と reverse-brute-force の両攻撃を効果的に防げるよう工夫されています。
</p>
<p>
試行回数の管理方法は、IPアドレス単位／アカウント単位ともに一長一短ありますが、「串の数はそう多くはない」ので、IPアドレス単位で十分だと判断しました。
</p>
<h5 class="chapter"><code>wp-admin/[admin.php | admin-ajax.php]</code></h5>
<p>
このカテゴリは、直接的攻撃に対するというより、サイトに何らかの脆弱性が存在した場合の間接的防御という位置づけです。例えば、XSS 脆弱性が原因のセッション・ハイジャックや、権限のチェックが十分でない脆弱なプラグインを経由したファイルの不正アップロードや盗用といった攻撃が想定できるでしょう。
</p>
<p>
最近の例では、<a href="http://security.szurek.pl/paid-memberships-pro-17142-path-traversal.html" title="Paid Memberships Pro 1.7.14.2 Path Traversal - security.szurek.pl">Paid Memberships Pro の脆弱性</a> による任意ファイルの漏洩や、<a href="http://blog.sucuri.net/2014/09/slider-revolution-plugin-critical-vulnerability-being-exploited.html" title="WordPress Security Vuln in Slider Revolution Plugin | Sucuri Blog">Slider Revolution の脆弱性</a> による <code>wp-config.php</code> のダウンロードとバックドアのアップロードがこれに当たります。
</p>
<div id="attachment_2280" style="width: 1210px" class="wp-caption aligncenter"><a href="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev.png" class="highslide" onclick="return hs.expand(this)"><img aria-describedby="caption-attachment-2280" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev.png" alt="RevSliderの脆弱性を突いた攻撃" width="1200" height="436" class="size-full wp-image-2280" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev-300x109.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev-1024x372.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-rev-624x227.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /></a><p id="caption-attachment-2280" class="wp-caption-text">RevSliderの脆弱性を突いた攻撃</p></div>
<div id="attachment_2279" style="width: 1210px" class="wp-caption aligncenter"><a href="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay.png" class="highslide" onclick="return hs.expand(this)"><img aria-describedby="caption-attachment-2279" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay.png" alt="Paid Memberships Proの脆弱性を突いた攻撃" width="1200" height="768" class="size-full wp-image-2279" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay-300x192.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay-1024x655.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/log-admin-pay-624x399.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /></a><p id="caption-attachment-2279" class="wp-caption-text">Paid Memberships Proの脆弱性を突いた攻撃</p></div>
<p>
これらを防ぐには <code>.htaccess</code> によるIPアドレスの制限が最も効果的ですが、本プラグインならIPアドレスに依らず、次の拡張用コードで防ぐことが出来ます。
</p>
<p>[php]<br />
/**<br />
 * admin-ajax.php 経由の不正なアクセスを遮断する<br />
 *<br />
 * @global array $_GET, $_POST リクエストされた値<br />
 * @param  array $validate<br />
 * @return array $validate[&#8216;result&#8217;] 不正な場合に &#8216;blocked&#8217;（遮断）を設定<br />
 */<br />
function my_protectives( $validate ) {<br />
    if ( defined( &#8216;DOING_AJAX&#8217; ) &amp;&amp; DOING_AJAX ) {<br />
        // 保護するファイル名のリスト<br />
        $protectives = array(<br />
            &#8216;wp-config.php&#8217;,<br />
            &#8216;.htaccess&#8217;,<br />
            &#8216;passwd&#8217;,<br />
        );</p>
<p>        $req = array();<br />
        $req += array_values( $_GET ) + array_values( $_POST );<br />
        $req = strtolower( urldecode( implode( &#8216; &#8216;, $req ) ) );</p>
<p>        foreach ( $protectives as $item ) {<br />
            // リクエスト中にファイル名を発見したら遮断<br />
            if ( strpos( $req, $item ) !== FALSE ) {<br />
                $validate[&#8216;result&#8217;] = &#8216;blocked&#8217;;<br />
                break;<br />
            }<br />
        }<br />
    }</p>
<p>    return $validate; // 引き続き国コードを検証するため &#8216;passed&#8217; は設定しない<br />
}<br />
add_filter( &#8216;ip-geo-block-admin&#8217;, &#8216;my_protectives&#8217; );<br />
[/php]</p>
<p>
余談ですが、Codex の <q><a href="http://wpdocs.sourceforge.jp/Hardening_WordPress#wp-config.php_.E3.82.92.E5.AE.89.E5.85.A8.E3.81.AB.E3.81.99.E3.82.8B" title="WordPress の安全性を高める - WordPress Codex 日本語版">wp-config.php を安全にする</a></q> にある <code>.htaccess</code> の設定は、<q>HTTP でアクセス</q> した時に <code>403 Permission Denied</code> を返すか、中身が空の <code>200 OK</code> を返すか（何も出力しない PHP が実行されるだけ）の違いにしかならず、先の様に内部に脆弱性がある場合の漏洩は防げませんので、念のため <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p>[text]<br />
# 内部からの漏洩は防げない<br />
&lt;files wp-config.php&gt;<br />
order allow,deny<br />
deny from all<br />
&lt;/files&gt;<br />
[/text]</p>
<p>
また、<a href="https://wordpress.org/plugins/wordfence/" title="WordPress &#8250; Wordfence Security &laquo; WordPress Plugins">Wordfence Security</a> には <a href="http://revolution.themepunch.com/" title="Slider Revolution Responsive WordPress Plugin">Slider Revolution</a> 専用 <abbr title="Web Application Firewall">WAF</abbr> が入っていて（先の拡張用コードの <code>$protectives</code> に <code>revslider_show_image</code> が指定されている感じ）、脆弱性を突いたアクセスをすると次の様な画面が表示されます。
</p>
<div id="attachment_2278" style="width: 1210px" class="wp-caption aligncenter"><a href="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev.png" class="highslide" onclick="return hs.expand(this)"><img aria-describedby="caption-attachment-2278" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev.png" alt="Slider Revolution の脆弱性を突いた攻撃を遮断する Wordfence Security の WAF" width="1200" height="450" class="size-full wp-image-2278" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev.png 1200w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev-300x113.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev-1024x384.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2015/01/hack-rev-624x234.png 624w" sizes="(max-width: 1200px) 100vw, 1200px" /></a><p id="caption-attachment-2278" class="wp-caption-text">Slider Revolution の脆弱性を突いた攻撃を遮断する Wordfence Security の WAF</p></div>
<p>
一方、<a href="https://wordpress.org/plugins/better-wp-security/" title="WordPress › iThemes Security (formerly Better WP Security) « WordPress Plugins">iThemes Security</a>（4.6.2）は、設定をアレコレ弄ってみましたが遮断できず、また <a href="https://wordpress.org/plugins/bulletproof-security/" title="WordPress &#8250; BulletProof Security &laquo; WordPress Plugins">BulletProof Security</a>（.51.4）は、<code>.htaccess</code> によってローカルから Admin 領域へのアクセスが禁止されるため、確認できませんでした <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h4 class="chapter">出来ない事</h4>
<p>
セキュリティ対策では、「何が出来るか」と共に「何が出来ないか」の想定が大事です。当然ですが、本プラグインは、フルスペック・プラグインが謳い文句にしている以下の様な機能は持っていません。
</p>
<ol>
<li>認証の強化
<ul style="list-style-type:none">
<li>パスワード強度のチェック、認証プロセスの強化（二段階認証など）</li>
</ul>
</li>
<li>不要なサービスの削除
<ul style="list-style-type:none">
<li>admin変更、アカウント名隠蔽 <span style="vertical-align:super; color:red; font-size:small">*2</span>、XML-RPC 無効化などの機能</li>
</ul>
</li>
<li>脆弱性や脅威のスキャン、特定攻撃パターンの検出、遮断
<ul style="list-style-type:none">
<li><abbr title="Cross Site Scripting">XSS</abbr> 脆弱性 <span style="vertical-align:super; color:red; font-size:small">*3</span>、<abbr title="Cross Site Request Forgeries">CSRF</abbr> 脆弱性、ファイルや DB の改ざん、ファイルの不正なアップロード（マルウェア、バックドア、ドットファイルなど）やダウンロード、SQL インジェクション等々を検出する機能、あるいは特定の攻撃パターンを遮断する WAF 機能</li>
</ul>
</li>
<li>攻撃を検知した時の警告
<ul style="list-style-type:none">
<li>管理者メール送信、管理画面への警告表示、アカウント・ロックなど</li>
</ul>
</li>
<li>攻撃に対する事前準備や事後処理
<ul style="list-style-type:none">
<li>DB のバックアップやリストア、被害拡大を防ぐサイト閉鎖機能など</li>
</ul>
</li>
</ol>
<p>
全て対応しようとすれば遅くなるのも仕方がない気がしますが、特にプラグインを数多く抱えていると（数じゃなく質の問題ですけどネ）、本プラグインのように「典型的な入口」を抑えるだけではダメで、3. 以降を重視せざるを得ないでしょう。
</p>
<p>
<span style="color:red">*2</span>： 個人的には、<a href="https://technet.microsoft.com/ja-jp/magazine/2008.06.obscurity.aspx" title="セキュリティ: 大論争 : 隠すことによるセキュリティ"><q>隠すセキュリティ対策</q></a> はあまり重視していません。
</p>
<p>
<span style="color:red">*3</span>： スキャンや <abbr title="Web Application Firewall">WAF</abbr> により、間接的に検出するんじゃないかと思いますが&hellip;。
</p>
<h3 class="chapter">応答時間の計測</h3>
<p>
どれだけ遅くなるかを見るために、ローカルに仕立てた WordPress で、ブルートフォース攻撃を想定したログイン・パスワードのクラックに対する処理能力を計測しました。
</p>
<h4 class="chapter">計測方法</h4>
<p>
<a href="http://blog.nintechnet.com/wordpress-brute-force-attack-detection-plugins-comparison/" title="WordPress: Brute-force attack detection plugins comparison">WordPress brute-force attack detection plugins comparison</a> を参考に、<a href="http://qiita.com/flexfirm/items/ac5a2f53cfa933a37192" title="Apache Benchでサクッと性能テスト - Qiita">ApacheBench コマンド</a> を使って計測しています。
</p>
<p>[text]<br />
# ab -t 60 -c 5 -p &#8216;postdata.txt&#8217; -T &#8216;application/x-www-form-urlencoded&#8217; -C &#8216;wordpress_test_cookie=WP+Cookie+check&#8217; http://localhost/wordpress/wp-login.php<br />
[/text]</p>
<p>
<code>postdata.txt</code> には、ログイン・フォームから送信される内容を入れておきます。
</p>
<p>[text]<br />
log=admin&#038;pwd=bruteforce&#038;wp-submit=Log+In&#038;redirect_to=http%3A%2F%2Flocalhost%2Fwordpress%2Fwp-admin%2F&#038;testcookie=1<br />
[/text]</p>
<h4 class="chapter">計測結果</h4>
<p>
① セキュリティ・プラグインを有効にしていない場合、② IP Geo Block だけを有効にした場合、③（重量級プラグインの代表として）Wordfence Security だけを有効にした場合の3つについて計測しました。各プラグインの設定は、それぞれデフォルトのままです。
</p>
<p>
計測の環境と結果は以下の通りです。
</p>
<ul>
<li>プラットフォーム：MacBook Pro Retina, 13-inch, Late 2013</li>
<li>プロセッサ：2.8 GHz Intel Core i7</li>
<li>メモリ：16 GB 1600 MHz DDR3</li>
<li>OS：OS X 10.9.5</li>
<li>サーバー：Apache/2.2.22</li>
<li>PHP：5.4.30</li>
<li>WordPress：4.1-ja</li>
</ul>
<table>
<thead>
<tr>
<th>プラグイン</th>
<th>リクエスト／秒（平均）[#/sec]</th>
</tr>
</thead>
<tbody>
<tr>
<td>① なし</td>
<td style="text-align:right">11.28</td>
</tr>
<tr>
<td>② IP Geo Block (2.0.0)</td>
<td style="text-align:right">11.76</td>
</tr>
<tr>
<td>③ Wordfence Security (5.3.4)</td>
<td style="text-align:right">5.12</td>
</tr>
</tbody>
</table>
<p>
「プラグインなし」より「IP Geo Block」の方が若干向上していますが、これは WordPress の一連の処理のうち、比較的早い段階で弾いているからです。
</p>
<p>
一方 Wordfence Security では2倍ほどのコストがかかっています。キャッシュ・プラグインの併用など、何らかの高速化手段が必要でしょう（Wordfence Security は、それ自身がキャッシュ機能を持っています）。
</p>
<h3 class="chapter">今後は&hellip;</h3>
<p>
特に構想はありませんが、サンプルコードの一部を本体に取り込んでもいいかな？と思っています。
</p>
<p>
「単機能以上、重量級未満」にどれだけのニーズがあるか分かりませんが、ニッチはニッチらしく行きたいと思いますし、要望、バグ報告など大歓迎です <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/baseline-of-wordpress-security/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>jQueryとAngularJSにおけるAjaxの微妙な違い</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/programming/ajax-trivial-difference-jquery-angularjs/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/programming/ajax-trivial-difference-jquery-angularjs/#respond</comments>
				<pubDate>Sat, 10 Jan 2015 14:42:23 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[AnuglarJS]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2273</guid>
				<description><![CDATA[AngularJS の勉強、始めました。 最初はそのプログラミングに関する独特のお約束事項にイラッとしましたが、キモであろう DI を「疎な関係のクラスを（実行時に）結びつけるのに必要な仕組み」と割り切り、DI &#82 [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
<a href="https://angularjs.org/" title="AngularJS — Superheroic JavaScript MVW Framework">AngularJS</a> の勉強、始めました。
</p>
<p>
最初はそのプログラミングに関する独特のお約束事項にイラッとしましたが、キモであろう <abbr title="Dependency Injection">DI</abbr> を「疎な関係のクラスを（実行時に）結びつけるのに必要な仕組み」と割り切り、<q><a href="http://qiita.com/hshimo/items/1136087e1c6e5c5b0d9f" title="DI - 猿でも分かる! Dependency Injection: 依存性の注入 - Qiita">DI &#8211; 猿でも分かる! Dependency Injection: 依存性の注入</a></q> で引用されている <a href="http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20050216/156274/?ST=develop&#038;P=2" title="（2/3）記者の眼 - Java開発を変える最新の設計思想「Dependency Injection（DI）」とは：ITpro">ITpro 記事</a> の <a href="http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20050216/156274/zu1.html?ST=develop" title="DIによる依存性の解消">クラス図</a> をコードから想像できるようになったところで、それなりに面白くなってきました。
</p>
<p>
何より「jQuery が要らなくなる！」のがとっても快感なんです <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> （つらい時もあるけど…）。
</p>
<p>
さて今回は、<a href="http://jquery.com/" title="jQuery">jQuery</a> まみれのページを <a href="https://angularjs.org/" title="AngularJS — Superheroic JavaScript MVW Framework">AngularJS</a> で書き換えた時に気付いた Ajax の動作 − 非同期通信の戻り値をいつどこで DOM に反映するか − に関する話題を書いてみます。
</p>
<p><span id="more-2273"></span></p>
<h3>jQueryの場合</h3>
<p>
検索のクエリを渡すと Github のリポジトリを返す関数を例にとってみます。
</p>
<p>[javascript]<br />
function get_repos(queries) {<br />
    var url = &#8216;&#8230;&#8217;;<br />
    queries = encodeURIComponent(queries.replace(/\s+/g, &#8216; &#8216;));</p>
<p>    $.ajax({<br />
        url : url + queries,<br />
        type: &#8216;GET&#8217;<br />
    })</p>
<p>    .done(function (data, textStatus, jqXHR) {<br />
        // 読み込み結果の処理<br />
        ;<br />
    })</p>
<p>    .fail(function (jqXHR, textStatus, errorThrown) {<br />
        // エラー処理<br />
        ;<br />
    });<br />
}<br />
[/javascript]</p>
<p>
私がよくやりがちなのが、「読み込み結果の処理」の所で DOM をゴニョゴニョとやる事です。当然「Github リポジトリ検索」をビューから切り離せなくなり、サービスとして独立させる事が出来ません。
</p>
<p>
ではどうするか？ <a href="http://qiita.com/sukobuto/items/0ee5026776e1bab10fb4" title="jQuery - async:false とは何か。或いは、非同期処理を諦めるのはまだ早い! - Qiita">async:false とは何か。或いは、非同期処理を諦めるのはまだ早い!</a> に紹介されているようにオブザーバー・パターンを使うのも手ですが、ここでは簡単に次のようコールバックを使うことにします。
</p>
<p>[javascript]<br />
function get_repos(queries, callback) {<br />
    &#8230;// コールバック関数を指定 ↑</p>
<p>    .done(function (data, textStatus, jqXHR) {<br />
        var res = &#8230;; // 読み込み結果の処理<br />
        callback(res);<br />
    })</p>
<p>    .fail(function (jqXHR, textStatus, errorThrown) {<br />
        // エラー処理<br />
        ;<br />
    });<br />
}<br />
[/javascript]</p>
<p>
これに対する呼び出し側は例えば次の通りです（XSS 対策は文脈に合わせてネ）。
</p>
<p>[javascript]<br />
$(&#8216;#submit&#8217;).on(&#8216;click&#8217;, function () {<br />
    get_repos($(&#8216;#queries&#8217;).val(), function (res) {<br />
        $(&#8216;#repos&#8217;).html($.parseHTML(res));<br />
    });<br />
});<br />
[/javascript]</p>
<div id="jsfiddle-nqbrs1La"></div>
<p>
「読み込み結果の処理」は目的とするデータの抽出に専念し、DOM 操作を呼び出し側に集約するワケですネ。
</p>
<p>
（余談ですが、<del><code>$(document.createDocumentFragment())</code> より <code>$('&lt;ul&gt;')</code> の方が <a href="http://jsperf.com/document-createfragment-vs-jquery-element/7" title="document.createFragment vs jQuery element - jsPerf">微妙に速そう</a> です。</del> <a href="http://jsperf.com/document-createfragment-vs-jquery-element/8" title="document.createFragment vs jQuery element - jsPerf">最後に一発 <code>$.html()</code></a> が良さげでした。）
</p>
<h3>AngularJSの場合</h3>
<p>
サービス部分は <a href="https://docs.angularjs.org/api/ng/service/$http" title="AngularJS: API: $http"><code>$http</code></a> サービスを使えば、ほぼ jQuery と同様に出来ます（他にも <code>get_users()</code> とかを追加していく想定です）。
</p>
<p>[javascript]<br />
angular.module(&#8216;myServices&#8217;, [])<br />
.service(&#8216;github&#8217;, [&#8216;$http&#8217;, function ($http) {<br />
    this.get_repos = function (queries, callback) {<br />
        var url = &#8216;&#8230;&#8217;;<br />
        queries = encodeURIComponent(queries.replace(/\s+/g, &#8216; &#8216;));</p>
<p>        $http({<br />
            url: url + queries,<br />
            method: &#8216;GET&#8217;<br />
        })</p>
<p>        .success(function (data, status, headers, config) {<br />
            var res = &#8230;; // 読み込み結果の処理<br />
            callback(res);<br />
        })</p>
<p>        .error(function (data, status, headers, config) {<br />
            // エラー処理<br />
            ;<br />
        });<br />
    };<br />
}]);<br />
[/javascript]</p>
<p>
ちなみにコントローラー部分は次のようになります。
</p>
<p>[javascript]<br />
angular.module(&#8220;myApp&#8221;, [&#8216;myServices&#8217;])<br />
.controller(&#8216;myCtrl&#8217;, [&#8216;$scope&#8217;, &#8216;github&#8217;, function ($scope, github) {<br />
    $scope.submit = function () {<br />
        github.get_repos($scope.queries, function (res) {<br />
            $scope.repos = res.items;<br />
        });<br />
    };<br />
}]);<br />
[/javascript]</p>
<div id="jsfiddle-vxme1qdf"></div>
<h3>AngularJS、もう1つのパターン</h3>
<p>
Angular には、<code>$http</code> 関数の成功／失敗を処理する関数 <code>success()</code>、<code>error()</code> 以外に、もう1つ <code>then()</code> という関数があります（というか、こちらの方が古くてプリミティブ、たぶん）。両者の違いは次の通りです。
</p>
<table border=1>
<thead>
<tr>
<th>コールバック関数</th>
<th>コールバック関数への引数</th>
<th>コールバック関数の戻り値</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>then()</code></td>
<td>以下のプロパティを持つレスポンス・オブジェクトが引数に与えられる</p>
<ul>
<li><code>data</code>: レスポンスのボディ部分</li>
<li><code>status</code>: レスポンスの HTTP ステータス・コード</li>
<li><code>headers</code>: ヘッダーを取得する関数</li>
<li><code>config</code>: リクエスト時の設定を格納したオブジェクト</li>
<li><code>statusText</code>: レスポンスの HTTP ステータス・テキスト</li>
</ul>
</td>
<td><code>then()</code> を介し<sup style="color:red"><code>*</code></sup>、呼び出し側に値を戻す事が出来る</td>
</tr>
<tr>
<td><code>success()</code>、<code>error()</code></td>
<td>以下のオブジェクトが引数に与えられる</p>
<ul>
<li><code>data</code>: レスポンスのボディ部分</li>
<li><code>status</code>: レスポンスの HTTP ステータス・コード</li>
<li><code>headers</code>: ヘッダーを取得する関数</li>
<li><code>config</code>: リクエスト時の設定を格納したオブジェクト</li>
</ul>
</td>
<td>呼び出し側に値を戻す事が出来ない</td>
</tr>
</tbody>
</table>
<p>
<sup style="color:red"><code>*</code></sup> 印を成立させるには、次のように <code>get_repos()</code> から <code>then()</code> を介して <code>$http</code> の戻り値である <a href="https://docs.angularjs.org/api/ng/service/$q#the-promise-api">Promise オブジェクト</a> を返してやるのがミソです。
</p>
<p>[javascript]<br />
.service(&#8216;github&#8217;, [&#8216;$http&#8217;, function ($http) {<br />
    this.get_repos = function (queries) {<br />
        &#8230;<br />
        // ↓ この return がミソ<br />
        return $http({<br />
            url: url + queries,<br />
            method: &#8216;GET&#8217;<br />
        })</p>
<p>        .then(<br />
            function (response) {<br />
                return response.data;<br />
            },<br />
            function (response) {<br />
                alert(response.data.message);<br />
                return {items: []};<br />
            }<br />
        );<br />
    };<br />
}]);<br />
[/javascript]</p>
<p>
こうすると、サービス関数 <code>get_repos()</code> にコールバック関数を引き渡す必要がなくなり、呼び出し側は then() を介して目的のデータを受け取れるようになります。そればかりか、受け取るデータを変えながら次のチェーンにつなげられるというオマケ付きです。
</p>
<div id="jsfiddle-qrj2mhdo"></div>
<h3>どちらが好み？</h3>
<p>
jQuery の <code>then()</code> や AngularJS の <code>success()</code>、<code>error()</code> では <code>jqXHR</code> オブジェクトや展開されたレスポンス・オブジェクトがそのまま引数に渡されるだけで、同じ事は出来ません。
</p>
<p>
出来る事に違いはないので、どちらを使うかは好みで良いと思いますし、チェーンする機会もあまりないでしょう。しかしどのパターンにおいても <code>deferred</code> や <code>promise</code> は常にチェーンできるようにしておいた方が良いと思います。まぁ、覚えておいても損しないってことでネ！
</p>
<p>
※ 今回の場合、<a href="http://jsfiddle.net/tokkonoPapa/w42pnLtf/" title="Basic sample of AngularJS No.2 (factory version) - JSFiddle"><code>factory</code> を使っても書ける</a> し、<del>単純さが変わらないのならそうする</del> より単純な方を選ぶべきなのかもしれませんが、練習用として <a href="https://github.com/dickeyxxx/angular-boilerplate" title="dickeyxxx/angular-boilerplate - GitHub">dickeyxxx/angular-boilerplate</a> を参考にしました。
</p>
<h3>2015年1月13日 追記</h3>
<p>
正確性を期すためとは思いますが、 promise オブジェクトの元である <a href="https://docs.angularjs.org/api/ng/service/$q" title="AngularJS: API: $q"><code>$q</code></a> の <a href="http://js.studio-kingdom.com/angularjs/ng_service/$q" title="$q | AngularJS 1.2 日本語リファレンス | js STUDIO">日本語訳</a> が微妙にわかりずらい（失礼ッ、もちろん翻訳の労には感謝の意と敬意を表します）ので、私なりの注釈をつけた意訳を載せておきます。また promise の概念については、2011年の拙作「<a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/programming/jquery-deferred-for-responsive-applications-basic/">jQueryのDeferredとPromiseで応答性の良いアプリを－基本編</a>」を参考にしてください。
</p>
<h4>The Promise API</h4>
<p>
deferred のインスタンスが作成されると、新しい promise のインスタンスが作成され、（注：deferred オブジェクトのプロパティとして） <code>deferred.promise</code> で参照できるようになります。
</p>
<p>
promise オブジェクトの目的は、延期されていたタスク（deferred task）が実行を完了した時、関係者がその結果にアクセス出来るようにすることにあります。
</p>
<h5>メソッド</h5>
<p>
<code>then(successCallback, errorCallback, notifyCallback)</code> &#8211; promise が解決されたか（resolved）あるいは否決されたか（rejected）に関わらず、 <code>then</code> は結果が得られるとすぐに成功または失敗のコールバックを非同期に呼び出します。その際コールバックには、ただ1つの引数: 解決の結果または否決の理由 が渡されます（注：各コールバックに結果を引き渡せるということです）。
</p>
<p>
加えて promise が解決または否決されるまで、その進行を示すために notify コールバックが0回以上呼び出されます。
</p>
<p>
このメソッドは <code>successCallback</code> または <code>errorCallback</code> の戻り値を介して、解決または否決された（状態の）新しい promise を返します（注：結果を引き渡しながらチェーンできるということです）。また <code>notifyCallback</code> メソッドの戻り値を介しても通知されます（注：<code>notifyCallback</code> が呼び出された時もチェーンされるということです）。ただし <code>notifyCallback</code> メソッドからは promise を解決または否決（の状態に）することはできません。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/programming/ajax-trivial-difference-jquery-angularjs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>MaxMindジオロケーションDBの自動更新を装備、IP Geo Blockの更新告知</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-location-with-maxmind/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-location-with-maxmind/#respond</comments>
				<pubDate>Sun, 12 Oct 2014 13:45:07 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[BBS spam]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2259</guid>
				<description><![CDATA[このところ海外からのスパムを弾く拙作の WordPress プラグイン IP Geo Block の機能アップにかなりの時間を割いています。 最初のバージョンで IP アドレスから国が引ける API をネット越しに叩き、 [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
このところ海外からのスパムを弾く拙作の WordPress プラグイン <q><a href="https://wordpress.org/plugins/ip-geo-block/" title="WordPress &#8250; IP Geo Block &laquo; WordPress Plugins">IP Geo Block</a></q> の機能アップにかなりの時間を割いています。
</p>
<p>
最初のバージョンで <a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-block-wordpress-plugin/" title="海外からの投稿を弾くスパム対策用WordPressプラグインをリリースします | ゆっくりと…">IP アドレスから国が引ける API をネット越しに叩き</a>、次いでサーバー負荷の低減を狙って <a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/update-ip-geo-block-1-1/" title="スパムの連続投稿によく効くキャッシュを装備したIP Geo Blockの更新告知 | ゆっくりと…">キャッシュを実装した</a> ワケですが、ここ最近、<a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/ip-geolocation-restful-apis/" title="IPアドレスの地理的位置情報が引ける無料RESTful API集 | ゆっくりと…">無料 RESTful API</a> のサービス中止が相次いだため、急ぎ安定した <a href="http://www.maxmind.com/" title="MaxMind - IP Geolocation and Online Fraud Prevention">MaxMind</a> の <a href="http://dev.maxmind.com/geoip/legacy/geolite/" title="GeoLite Legacy Downloadable Databases &laquo; Maxmind Developer Site">無料 GeoLite データベース</a> を使えるようにする必要があった次第です。
</p>
<p>
プログラミングは嫌いな方ではないですが、スパムやら bot 対策は何も新しいものを生みません。一所懸命に作り込んでも空しさが拭えないので、せめてココで告知させて下さい <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h4>2014年10月13日 追記</h4>
<p>
今回のバージョンアップではオプションテーブルの更新が必要なのですが、自動更新では更新処理が働きません。対応策が見つかるまではお手数ですが、更新後に一旦<br />
「停止」し、再度「有効化」していただくよう、お願いします m_(..)_m。
</p>
<p><span id="more-2259"></span></p>
<h3 class="chapter">MaxMind GeoLite データベースに関する仕様</h3>
<p>
MaxMind の GeoLite データベースは、月に1度、月初に更新されます。これに合わせ、プラグインのインストール後は WordPress のクローンで定期的にダウンロードする仕様としました。また MaxMind のサーバーは、<code>Last-Modified</code> ヘッダをちゃんと返すので、最終更新の1ヶ月＋α後に <code>If-Modified-Since</code> リクエストヘッダを付けて落としに行きます。
</p>
<p>
「＋α」の部分はアクセスを集中させないための乱数で、1〜6日まで幅を持たせています。また <code>304 Not Modified</code> が返ってきた場合は、24時間後に再リクエストを試みます。
</p>
<p>
あまり高頻度にリクエストすると <code>403 Forbidden</code> が返ってきたりするので、この辺りは緩やかな仕様としています。
</p>
<p>
またデータベースは IPv4 用と IPv6 用があり、両方とも落とします。実は IPv6 用で IPv4 も引けるのですが、容量が IPv4 用より大きく検索時間がかかるので、使い分けるようにしています。
</p>
<p>
もう少し細かな話をすると、ダウンロードには <a href="http://dogmap.jp/2011/04/26/wp_remote_get/" title="wp_remote_get のススメ | dogmap.jp"><code>wp_remote_get()</code></a> を使っています。このため gzip 全データをメモリ中に読み込んでからファイルに書き出す事になりますが、容量的には 1.3MB 程度なのでメモリ不足になる事はないでしょう。
</p>
<p>
実は <a href="http://codex.wordpress.org/Function_Reference/download_url" title="Function Reference/download url &laquo; WordPress Codex"><code>download_url()</code></a> という関数を使えば、巨大なファイルも <code>stream</code> として落とせるのですが、先の <code>If-Modified-Since</code> が効かなくなるので使っていません。
</p>
<p>
この辺りは、HEAD メソッドでヘッダー情報だけ取得するようにすれば良いだけなので、いずれ省メモリ化を計りたいと思います。
</p>
<h5>技術情報</h5>
<ul>
<li><a href="http://dev.maxmind.com/geoip/" title="GeoIP Products &laquo; Maxmind Developer Site">GeoIP Products</a></li>
<li><a href="https://github.com/maxmind/geoip-api-php" title="maxmind/geoip-api-php - GitHub">maxmind/geoip-api-php</a></li>
<li><a href="http://dev.maxmind.com/geoip/legacy/geolite/" title="GeoLite Legacy Downloadable Databases &laquo; Maxmind Developer Site">GeoLite Legacy Downloadable Databases</a></li>
</ul>
<h3 class="chapter">その他の更新項目</h3>
<h4 class="chapter">IP2LocationのIPv6用データベースのサポート</h4>
<p>
<a href="http://www.ip2location.com/" title="IP Address Geolocation to Identify Website Visitor's Geographical Location">IP2Location</a> の無料データベース <a href="http://lite.ip2location.com/" title="Free IP Geolocation Database">IP2Location LITE</a> が、10月1日のリリースから IPv6 をサポートするようになりました。
</p>
<blockquote>
<p>We are glad to announce that IP2Location is supporting IPv6 database in all products from this release.</p>
<p style="text-align: right">10月のニュースレターより</p>
</blockquote>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/10/ip2location-download.png" alt="IP2Locationデータベースのダウンロード" width="1024" height="1755" class="aligncenter size-full wp-image-2260" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/10/ip2location-download.png 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/10/ip2location-download-175x300.png 175w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/10/ip2location-download-597x1024.png 597w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/10/ip2location-download-624x1069.png 624w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<p>
これらのファイルを <code>database.bin</code> にリネームし、<code>wp-content/ip2location/</code> に置けば利用可能です（<a href="http://lite.ip2location.com/login" title="IP2Location LITE Sign Up">登録</a> と <a href="http://lite.ip2location.com/terms-of-use" title="IP2Location LITE Terms of Use">帰属リンク</a> が必要）。ファイルサイズが大きくなるほど検索時間もかかるので、出来る限りコンパクトな形式を選択するのが吉です。
</p>
<h5>技術情報</h5>
<ul>
<li><a href="http://www.ip2location.com/developers#free_open_source" title="Developers | IP2Location.com">Free/Open Source</a></li>
<li><a href="https://www.ip2location.com/free/plugins" title="Free Plugins | IP2Location.com">Free Extensions/Plugins</a></li>
<li><a href="http://lite.ip2location.com/" title="Free IP Geolocation Database">IP2Location Lite</a></li>
</ul>
<h4 class="chapter">RESTful APIの更新</h4>
<p>
API の幾つかが、サービス停止あるいはキーを要求するようになったので、削除しました。ストックはまだ幾つかあるのですが、MaxMind の自動ダウンロードにより、ほぼメンテナンス・フリーとなったため、今後は緩やかに削減の方向になると思います。
</p>
<h4 class="chapter">判定処理の効率化</h4>
<p>
前バージョンでは、コメントのチェックも想定し、<code>preprocess_comment</code> アクション・フィルタをフックしていましたが、<code>pre_comment_on_post</code> に変更しました。これにより <code>wp-comments-post.php</code> へのアクセス直後に判定でき、サーバー負荷が軽減されます。
</p>
<h3 class="chapter">今後は？</h3>
<p>
セキュリティ用プラグインとして本格的な <a href="https://wordpress.org/plugins/wordfence/" title="WordPress &#8250; Wordfence Security &laquo; WordPress Plugins">Wordfence Security</a> の <a href="http://www.wordfence.com/#pricing-table" title="Wordfence - WordPress Security Plugin">プレミアム版</a> には、スパムや <code>wp-login.php</code> への <a href="http://ja.wikipedia.org/wiki/%E7%B7%8F%E5%BD%93%E3%81%9F%E3%82%8A%E6%94%BB%E6%92%83" title="総当たり攻撃 - Wikipedia">Brute Force 攻撃</a> を防御するための Country Blocking という機能がありますが、有料です。
</p>
<p>
これが無料で提供できれば少しは価値があるかな？と思っています。ただセキュリティ用となると、海外からのアクセスを弾くだけでは成り立ちません。あまりコードを肥大化させる事なく実現できる道を探っていきたいと思います。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-location-with-maxmind/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>スパムの連続投稿によく効くキャッシュを装備したIP Geo Blockの更新告知</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/update-ip-geo-block-1-1/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/update-ip-geo-block-1-1/#respond</comments>
				<pubDate>Sun, 31 Aug 2014 06:54:42 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[BBS spam]]></category>
		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2249</guid>
				<description><![CDATA[ここ数日間、本サイトではスパムの連投が流行っています 😡 。 こいつらに貴重なサーバー資源を食われるのは1ミリたりとも許せないワケで、かつては日本以外の IP アドレスを .htaccess に手作業で書き込んでいました [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
ここ数日間、本サイトではスパムの連投が流行っています <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f621.png" alt="😡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p>
こいつらに貴重なサーバー資源を食われるのは1ミリたりとも許せないワケで、かつては日本以外の IP アドレスを <code>.htaccess</code> に手作業で書き込んでいましたが、あまりにも量が多く、馬鹿げているので止めました。
</p>
<p>
そんなワケで作ったのが、海外からの投稿を <a href="http://akismet.com/" title="Comment spam prevention for your blog - Akismet">Akismet</a> の起動前に弾く <a href="http://wordpress.org/plugins/ip-geo-block/" title="WordPress &#8250; IP Geo Block &laquo; WordPress Plugins">IP Geo Block</a> というプラグインなんですが、スパムは激減するものの、IP アドレスの検索に少々時間がかかるのが気になる点でした。
</p>
<p>
で、この度、一度検索した IP アドレスをキャッシュに保持する機構を付けたところ、思いの外、効果があったので、バージョン 1.1.0 として告知したいと思います <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<p><span id="more-2249"></span></p>
<h3 class="chapter">バージョン 1.1.0 での変化点</h3>
<p>
主に次の3つです。
</p>
<ol>
<li>一度検索した IP アドレスと国コードを一定期間キャッシュする機能を追加。</li>
<li>サービス提供元で生じた障害を分析し易くするため、エラー処理を改善。</li>
<li>ユーザーエージェント文字列をプラグイン独自のものに変更。</li>
</ol>
<h4 class="chapter">キャッシュ機構の追加</h4>
<p>
本プラグインは、<q><a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/ip-geolocation-restful-apis/">IPアドレスの地理的位置情報が引ける無料RESTful API集</a></q> でピックアップした API を呼び出すか、<a href="http://wordpress.org/plugins/ip2location-tags/" title="WordPress &#8250; IP2Location Tags &laquo; WordPress Plugins">IP2Location Tags</a> など <a href="http://www.ip2location.com/" title="IP Address Geolocation to Identify Website Visitor's Geographical Location">IP2Location</a> が提供するプラグインのインストールで利用可能となるデータベースを用いて、IP アドレスの国コードを検索するのが仕様です。
</p>
<p>
前者は、API から返答が返ってくるまでの数百ミリ秒から数秒の間、コネクションが張られっぱなしになりますし、後者は、WordPress にインストールされたデータベース・ファイルの検索に50ミリ秒前後のCPU処理を必要としていました。
</p>
<p>
一方、今回のキャッシュ化により、2度目以降の検索は数ミリ秒で完了するようになりました。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-cache.png" alt="IP Geo Block 投稿の統計" width="800" height="1156" class="aligncenter size-full wp-image-2251" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-cache.png 800w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-cache-207x300.png 207w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-cache-708x1024.png 708w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-cache-624x901.png 624w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>
スパムの投稿パターンにも依りますが、今のところデフォルトの設定で90%以上のヒット率をキープしています。
</p>
<p>
キャッシュの実装には <a href="http://www.warna.info/archives/1681/" title="WordPressのTransients APIを用いて表示の高速化を図る | Simple Colors">Transient API</a> を利用していて、デフォルトでは最大10個の IP アドレスを3600秒間保持するようにしています。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-settings.png" alt="IP Geo Block キャッシュの設定" width="800" height="170" class="aligncenter size-full wp-image-2252" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-settings.png 800w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-settings-300x63.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-settings-624x132.png 624w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>
本プラグインの設定画面で上のようにならない場合、一旦本プラグインを「停止」し、再度「有効化」して下さい。自動的に設定値を更新します。
</p>
<h4 class="chapter">エラーメッセージ処理の改善</h4>
<p>
API 提供元の都合により、サービスに障害が起きたり停止したりすることがあります。例えば smart-ip.net はサイト自体が停止してしまったため、前バージョンの 1.0.3 で外しています。
</p>
<p>
このような状況を分析し易くするため、サービスが返すエラーメッセージや HTTP レベルで起きるエラーを検索タブで確認できるようにしました。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-error.png" alt="IP Geo Block IPアドレスの位置情報を検索" width="800" height="600" class="aligncenter size-full wp-image-2253" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-error.png 800w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-error-300x225.png 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/08/ip-geo-block-error-624x468.png 624w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>
まぁ、ユーザーの皆さんにはあまり関係のない機能ですネ。
</p>
<h4 class="chapter">ユーザーエージェント文字列の変更</h4>
<p>
WordPress 標準の <a href="http://developer.wordpress.org/reference/functions/wp_remote_get/" title="WordPress &#8250; wp_remote_get() | Function | WordPress Developer Resources"><code>wp_remote_get()</code></a> を使うと、ユーザーエージェント文字列は、例えば次のようになります。
</p>
<p>[text]<br />
WordPress/3.9.2; http://tokkono.cute.coocan.jp/blog/slow<br />
[/text]</p>
<p>
これを次のように変えました。
</p>
<p>[text]<br />
WordPress/3.9.2; ip-geo-block 1.1.0<br />
[/text]</p>
<p>
ただそれだけのことです。
</p>
<h3 class="chapter">IP2Locationのデータベースについて</h3>
<p>
<q><a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/ip-geo-block-wordpress-plugin/">海外からの投稿を弾くスパム対策用WordPressプラグインをリリースします</a></q> にも書きましたが、本プラグインは <a href="http://www.ip2location.com/free/plugins" title="Free Plugins | IP2Location.com">IP2Location の無料プラグイン</a> をインストールするか、それぞれを <code>ip2location</code> にリネームし <code>wp-content</code> にアップロードすることで、そのデータベースが利用可能になります（配置後、本プラグインを一旦「停止」、再度「有効化して下さい）。
</p>
<p>
必要なのは、データベース本体の <code>database.bin</code> と <code>ip2location.class.php</code> というクラス・ライブラリのファイルです。
</p>
<p>
またデータベースを <a href="http://lite.ip2location.com/" title="Free IP Geolocation Database">オープンソースの無料データベース</a> に差し替えれば、さらに幸せになれます。メールアドレスの登録と <a href="http://www.ip2location.com/" title="IP Address Geolocation to Identify Website Visitor's Geographical Location">IP2Location.com</a> への <a href="http://lite.ip2location.com/terms-of-use" title="IP2Location LITE Terms of Use">帰属リンク張りが必要</a> ですが、<del>IPv6 もカバーされているので、</del>* 他の サービス API を呼び出す頻度がグッと減ります。
</p>
<p>
* IPv6 の無料データベースは、<a href="http://www.ip2location.com/free/ipv6" title="Free IPv6 Database | IP2Location.com">こちら</a> でした。
</p>
<p>
私は <a href="http://tokkono.cute.coocan.jp/blog/slow/index.php/about/">About</a> ページにリンクを貼った上で <a href="http://lite.ip2location.com/database-ip-country-region-city-latitude-longitude" title="Free IP2Location LITE IP-COUNTRY-REGION-CITY-LATITUDE-LONGITUDE">DB5.LITE</a> を利用していますが、月に一度、データベース更新の案内が届くぐらいで、特に面倒なく使えています。
</p>
<h3 class="chapter">今後の構想</h3>
<p>
今回のキャッシュ化により、例えば WordPress の管理領域にアクセスしに来た IP アドレスを記録して弾く仕様を追加すれば、セキュリティ向上にもつながるかな？ などと夢想しています。
</p>
<p>
もっとも、優れた <a href="http://wordpress.org/plugins/search.php?q=security" title="WordPress &#8250; Search for security &laquo; WordPress Plugins">セキュリティ用プラグイン</a> はたくさんありますし、より根本的な対策をすべきですけどネ。
</p>
<p>
まぁ、今後も細々とメンテはしていきますので、良かったら使ってやって下さい <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/update-ip-geo-block-1-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>レスポンシブデザインの進化はWebの常識を変えるか？</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/future-of-responsive-design/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/future-of-responsive-design/#comments</comments>
				<pubDate>Sun, 08 Jun 2014 21:48:18 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[Webテクノロジ]]></category>
		<category><![CDATA[site optimization]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2231</guid>
				<description><![CDATA[ある記事 によれば、レスポンシブ Web デザインを採用するサイトの 72% が、デスクトップとモバイルに同じリソースが使われているそうです。またそれらリソースの 60% 以上が画像 という統計や、モバイル用に画像を最適 [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
<a href="http://www.guypo.com/uncategorized/real-world-rwd-performance-take-2/" title="Guy&#039;s Pod  &raquo; Blog Archive &raquo; Real World RWD Performance &#8211; Take 2">ある記事</a> によれば、レスポンシブ Web デザインを採用するサイトの 72% が、デスクトップとモバイルに同じリソースが使われているそうです。またそれらリソースの <a href="http://httparchive.org/interesting.php#bytesperpage" title="HTTP Archive  - Interesting Stats">60% 以上が画像</a> という統計や、モバイル用に画像を最適化すれば、<a href="http://timkadlec.com/2013/06/why-we-need-responsive-images/" title="Why we need responsive images - TimKadlec.com">データ量を 72.2% 削減できる</a> という調査結果もあります。
</p>
<p>
ということで、レスポンシブ画像のことを調べていていましたが、その技術進化というか、紆余曲折も含めて色々とある様です。
</p>
<p>
最新技術を素早く取り入れることはもちろん大事ですが、特に過渡期においては、変化に強いサイトを作るためにも技術の先行きを見極めることが重要です。そこでタイトルのような視点で、これまでの経緯をつらつらと辿ってみました。
</p>
<p>
自分としてのテーマは、「じゃあ、今、どうするか？」だったのですが&#8230;。読んで下さる方の何かに役立つかどうかは甚だ心もとない記事です。
</p>
<p>
ちなみに今回記事で取り上げた話題については、<q><a href="http://contentloaded.com/responsive/" title="レスポンシブ画像のデモ">レスポンシブ画像のデモ</a></q> に、もう少し掘り下げて展示しています。そちらもぜひ覗いてみて下さい！
</p>
<p><span id="more-2231"></span></p>
<h3 class="chapter">レスポンシブ画像をめぐる要求の変化</h3>
<p>
レスポンシブ画像とは従来、ビューポートや画面解像度（時には印刷時の解像度）などに適した画像を表示することを指し、</p>
<ul>
<li>ビューポートや回線速度に適した画像を提供し、モバイル環境での通信量低減を図る</li>
<li>Retina などピクセル密度の高い表示デバイスには、解像度の高い画像を提供する</li>
</ul>
<p>などが主な関心事項でした。
</p>
<p>
一方 <a href="http://www.w3.org/community/respimg/" title="Responsive Images Community Group">W3C コミュニティ・グループ</a> の1つである <a href="http://responsiveimages.org/"><abbr title="Responsive Images Community Group">RICG</abbr></a> が考える理想的なレスポンシブ画像とは「ユーザーのコンテキストに適した画像」です。彼らはその <a href="http://usecases.responsiveimages.org/" title="Use Cases and Requirements for Standardizing Responsive Images">ユースケース</a> として、上記に加え次のような要求があると考えています。</p>
<ul>
<li>省電力モードでは低品質の画像を選択し、通信時の消費電力を抑える</li>
<li>端末のサイズに合わせ、ユーザーに対する訴求に最適な画像を提供する</li>
</ul>
<p>
特に後者は  <q>Art Direction</q>（<a href="http://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%BC%E3%83%88%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%82%BF%E3%83%BC" title="アートディレクター - Wikipedia">広告、宣伝、グラフィックデザインなどにおいて、主に視覚的表現手段を計画し、総括、監督すること</a>）と呼ばれ、例えばモバイル用には単なる縮小画像ではなく、<q>ユーザーに訴求したいエリアを切り出し拡大して見せる</q> ことを要求します。
</p>
<div id="attachment_2233" style="width: 1290px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-2233" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/BarackObama.jpg" alt="Barack Obama at Chrysler, Toledo, OH" width="1280" height="667" class="size-full wp-image-2233" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/BarackObama.jpg 1280w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/BarackObama-300x156.jpg 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/BarackObama-1024x533.jpg 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/BarackObama-624x325.jpg 624w" sizes="(max-width: 1280px) 100vw, 1280px" /><p id="caption-attachment-2233" class="wp-caption-text"><a href="http://blog.cloudfour.com/a-framework-for-discussing-responsive-images-solutions/" title=" &raquo; A framework for discussing responsive images solutions Cloud Four Blog">アートディレクションの例</a> / Photo from <a href="https://www.flickr.com/photos/barackobamadotcom/5795228030/" title="Barack Obama at Chrysler, Toledo, OH 06/03/11 | Flickr - Photo Sharing!">Barack Obama</a> (<a href="https://creativecommons.org/licenses/by-nc-sa/2.0/" title="Creative Commons &mdash; Attribution-NonCommercial-ShareAlike 2.0 Generic &mdash; CC BY-NC-SA 2.0">CC BY-NC-SA 2.0</a>)</p></div>
<p>
<abbr title="Responsive Images Community Group">RICG</abbr> はこれらレスポンシブ画像をめぐる様々な要求を、以下のように、既存規格の拡張で実現できるよう検討を進めています。
</p>
<ul>
<li>HTML の拡張
<ul style="list-style-type:none">
<li>ビューポートとデバイス・ピクセル比に応じて適切な画像が選択できるよう、ユーザーエージェントにヒントを与えるマークアップ仕様</li>
</ul>
</li>
<li>HTTP の拡張
<ul style="list-style-type:none">
<li>ユーザーエージェントの表示能力を HTTP リクエストに載せ、サーバーとのコンテンツ・ネゴシエーションにより適切な画像を提供する仕組み</li>
</ul>
</li>
</ul>
<p>
ビューポートやデバイス・ピクセル比は、従来からスタイルやレイアウトで扱うべきと要素と考えられており、既に <a href="http://www.w3.org/TR/css3-mediaqueries/" title="Media Queries">CSS3 メディア・クエリ</a> で扱えます。
</p>
<p>
しかしアート・ディレクションの例でも分かる通り、もはやレスポンシブ画像に関する要求はコンテンツ自体の問題となり、ビューポートやデバイス・ピクセル比を HTML でも扱えるようにする必要が出てきた言えます。
</p>
<p>
いずれにしても当初言われていた「ワンソースでマルチデバイスに対応」というレスポンシブデザインの謳い文句は、もはや画像に関しては「死語」に近く、要求が複雑化していくと共に、今後はマルチソースの方向になると思われます。
</p>
<h3 class="chapter">Retina 用の画像は低画質で良い！ &#8211; Retina 革命</h3>
<p>
2012年の初頭は、レスポンシブWebデザインが <a href="http://alistapart.com/article/future-ready-content" title="Future-Ready Content - An A List Apart Article">Future-Ready なコンテンツ</a> で <a href="http://futurefriendlyweb.com/" title="Future Friendly">Future Friendly</a> なサイトを作る技術としてもてはやされていた頃です。
</p>
<p>
ところが Retina の出現をキッカケに「画像のボケ」が問題になり、そのクオリティを保つため、通信量の増加には目をつぶり、デバイス・ピクセル比に応じて縦横2倍の画像を提供するよう、コンテンツを修正せざるを得なくなりました。
</p>
<p>
以降、相当数の「レスポンシブな画像を実現する手段」が提案されてきましたが、<a href="http://css-tricks.com/which-responsive-images-solution-should-you-use/" title="Which responsive images solution should you use? | CSS-Tricks">どの手法を使えば良いのか</a>、未だ決定打がない状態が続いていると思います。
</p>
<p>
一方で、<a href="http://www.netvlies.nl/over-ons/medewerkers/daan-jobsis" title="Daan Jobsis - Netvlies Internetdiensten">Daan Jobsis さん</a> の2012年7月27日の記事 <q><a href="http://www.netvlies.nl/blog/design-interactie/retina-revolution" title="Retina revolution">Retina 革命</a></q> が大きな反響を呼びました。彼は、Retina 用の高解像度画像なら、画質をかなり落としても十分綺麗に見えるということを明らかにしたのです。
</p>
<p>
例えば、320&#215;240 の画像なら Retina 用には 640&#215;480 の画像を作るわけですが、その際 jpeg の画質を 80 とか 90 にする必要はなく、20 か 30 で十分で、かつ非 Retina 用画像に比べてファイルサイズが 75% 程度で済むというのです。
</p>
<div id="attachment_2234" style="width: 1290px" class="wp-caption aligncenter"><a href="http://contentloaded.com/responsive/quality/"><img aria-describedby="caption-attachment-2234" src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/RetinaImage.jpg" alt="画質とファイルサイズ" width="1280" height="867" class="size-full wp-image-2234" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/RetinaImage.jpg 1280w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/RetinaImage-300x203.jpg 300w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/RetinaImage-1024x693.jpg 1024w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/06/RetinaImage-624x422.jpg 624w" sizes="(max-width: 1280px) 100vw, 1280px" /></a><p id="caption-attachment-2234" class="wp-caption-text"><a href="http://commons.wikimedia.org/wiki/File:Neste_Oil_Rally_2010_-_Jari-Matti_Latvala_in_shakedown.jpg" title="File:Neste Oil Rally 2010 - Jari-Matti Latvala in shakedown.jpg - Wikimedia Commons">Neste Oil Rally 2010 &#8211; Jari-Matti Latvala in shakedown</a> by <a href="http://commons.wikimedia.org/wiki/User:Kallerna" title="User:Kallerna - Wikimedia Commons">kallerna</a> (<a href="http://creativecommons.org/licenses/by-sa/3.0" title="Creative Commons &mdash; Attribution-ShareAlike 3.0 Unported &mdash; CC BY-SA 3.0">CC-BY-SA-3.0</a> or <a href="http://www.gnu.org/copyleft/fdl.html" title="GNU Free Documentation License v1.3 - GNU Project - Free Software Foundation">GFDL</a>)</p></div>
<p>
同時にその画像は、非 Retina デバイスで見ても遜色ないことや、元ファイルの解像度が足りない場合でも Photoshop で拡大した画像の方が良い結果が得られることも明らかにしています。
</p>
<p>
つまり、Retina 用と非 Retina 用に画像ファイルを分ける必要がなく、常に2倍の（低画質な）高解像度画像を提供すればイイというワケです。
</p>
<blockquote><p>
どのデバイスでも、ファイルサイズが小さく、より高品質だなんて、あり得ない！
</p></blockquote>
<p>
彼はデザイナーとしての視点から、ハードウェアの技術革新が従来の常識を覆したことに、純粋に驚いたのでしょう。これが「Retina 革命」とタイトル付けされた理由です。
</p>
<p>
もちろん、このような画像のレンダリングは電力を余計に消費するため、通信時間の短縮とを天秤にかける必要があるかも知れません。それでも、読み込みとレンダリングを最悪2回実行してしまう <a href="http://imulus.github.io/retinajs/" title="Retina.js | Retina graphics for your website">Retina.js</a> を使うよりは、はるかにマシでしょう。
</p>
<p>
むしろ Daan さんの発見は単なるテクニックではなく、デバイスピクセル比の問題を HTML 外で解決する道を示唆しているとも考えられます。
</p>
<p>
現に <a href="https://github.com/yoavweiss/Responsive-Image-Container" title="yoavweiss/Responsive-Image-Container - GitHub">複数のレイヤーに解像度毎の画像を差分として載せ、圧縮率を高めるレスポンシブ画像コンテナ</a> や <a href="https://yoavweiss.github.io/respimg-edge-presentation/#/38">全画像の同時並列な読み込みとレンダリングを可能にするプログレッシブ・ダウンロード</a> の研究などが進んでいます。
</p>
<p>
また Google の開発者は <a href="http://www.youtube.com/watch?v=4tu2SJfSalA" title="Faster, smaller and more beautiful web with WebP - YouTube">将来 webp で 3D 画像を扱いたい</a> と語っていますし、そのうち 3D 表示デバイスなどがもっと一般化するかもしれません。これらの研究成果は、新しいメディア・タイプの出現を予感させます。
</p>
<p>
特に過渡期においては Daan さんの様なテクニックやハックの類いが必ず出現するものですが、<abbr title="Responsive Web Design">RWD</abbr> に関する要求の複雑化を念頭に置けば、標準規格の整備と共に、ブラウザの進化が不可欠な状況にあると思います。
</p>
<h3 class="chapter">ブラウザの漸進的な進化</h3>
<p>
レスポンシブな画像を実現する <a href="http://design-spice.com/2012/06/13/responsive-web-design-image/" title="レスポンシブWebデザインの画像問題の解決法5種 │ Design Spice">様々な手法</a> の中には、異なるサイズの画像を二重に読み込み、サイト速度の低下や電池の消耗を引き起こすものがあります。
</p>
<p>
例えば JavaScript を使う手法では、<code>&lt;img&gt;</code> 要素の <code>src</code> 属性を差し替える前（つまり HTML 解析時）に <a href="http://www.html5rocks.com/ja/tutorials/internals/howbrowserswork/#Speculative_parsing" title="投機的な解析 - ブラウザのしくみ: 最新ウェブブラウザの内部構造 - HTML5 Rocks">ブラウザの先読み機能</a> が働いてしまいます。
</p>
<p>
また回線速度に応じた画像を選ぶ場合も、 <a href="https://github.com/adamdbradley/foresight.js/" title="adamdbradley/foresight.js - GitHub">foresight.js</a> 等のスクリプト読み込み後ではなく、<del><a href="http://www.w3.org/TR/navigation-timing-2/" title="Navigation Timing - W3C">Navigation Timing</a></del> <a href="https://developer.mozilla.org/en-US/docs/tag/Network%20Information%20API" title="Articles tagged: Network Information API | MDN">Network Information API</a> を元に、 HTML 解析時に選ぶのが理想的です。
</p>
<p>
このような <a href="https://yoavweiss.github.io/velocity-eu-13-presentation/" title="Yoav Weiss - Responsive images techniquess and beyond">レスポンシブ画像が抱える様々な課題を解決する</a> には、その手段が <a href="http://blog.cloudfour.com/the-real-conflict-behind-picture-and-srcset/" title="&raquo; The real conflict behind &lt;picture&gt; and @srcset Cloud Four Blog">ブラウザのネイティブな機能として取り込まれることが必須</a> です。
</p>
<p>
このため2011年台から <a href="http://html5doctor.com/html5-adaptive-images-end-of-round-one/" title="HTML5 adaptive images: end of round one | HTML5 Doctor"><code>&lt;picture&gt;</code> 要素が提案</a> されてきたワケですが、ここにきてようやく <a href="http://www.webkit.org/demos/srcset/" title="Image srcset attribute example - WebKit"><code>&lt;img&gt;</code> 要素の <code>srcset</code> 属性</a> が <a href="http://www.publickey1.jp/blog/14/chrome_34img.html" title="Chrome 34ではimgタグで解像度に応じた複数の画像を出し分けられるよう、レスポンシブイメージ対応に － Publickey">Chrome 34 に実装</a> されました。その元になった RICG の仕様案は以下の通りです。
</p>
<dl>
<dt><code>srcset="<em>url</em> [<em>descriptor</em>] [, <em>url ...</em>]"</code></dt>
<dd>
<dl>
<dt><code><em>url</em></code></dt>
<dd>画像への URL</dd>
<dt><code><em>descriptor</em></code></dt>
<dd>
<dl>
<dt>device pixel ratio</dt>
<dd>小数点を含むデバイス・ピクセル比（<abbr title="Device Pixel Ratio">DPR</abbr>）に &quot;<code>x</code>&quot; を付加</dd>
<dt>image dimension</dt>
<dd>正の整数である画像の幅に &quot;<code>w</code>&quot; を付加</dd>
</dl>
</dd>
</dl>
</dd>
</dl>
<p>
例えば次のマークアップでは、DPR に適した画像が選択されます。
</p>
<p>[html]<br />
&lt;img src=&#8221;small.jpg&#8221; srcset=&#8221;small.jpg 1x, medium.jpg 2x&#8221; alt=&#8221;&#8230;&#8221;&gt;<br />
[/html]</p>
<p>
さて、ここで私が注目したいのは DPR を直接指定する第1の書式ではありません。ビューポートが絡むと、例えばスマホ用 <code>small.jpg</code> の <q><code>2x</code></q> が、デスクトップ用 <code>medium.jpg</code> の <q><code>1x</code></q> と同になったりする可能性もあり、この書式では表現できないからです。
</p>
<p>
かつては <a href="https://yoavweiss.github.io/respimg-edge-presentation/#/18" title="Yoav Weiss - the responsive images saga">第1と第2の書式が混在した仕様案</a> もありましたが、<a href="http://ericportis.com/posts/2014/srcset-sizes/" title="Srcset and sizes —  ericportis.com">最近の仕様案</a> では、両者は区別されています。
</p>
<p>
実は RICG の案には「<code>sizes</code>」という属性があります。これはデバイス・ピクセル比に振り回されることなく、レイアウト指向でマークアップできるようにするためのもので、ブラウザが最適な画像を選択できるようヒントを与える役割りを果たします。
</p>
<p>
簡単化のために <code>&lt;img&gt;</code> 要素の例でちょっと説明しますネ。
</p>
<p>[html]<br />
&lt;img src=&#8221;small.jpg&#8221; alt=&#8221;&#8230;&#8221;<br />
	sizes=&#8221;(min-width: 40em) 45vw, 90vw&#8221;<br />
	srcset=&#8221;small.jpg 480w, medium.jpg 960w, large.jpg 1920w&#8221;&gt;<br />
[/html]</p>
<p>
<code>sizes</code> 属性には <q><code>45vw</code></q> とか <q><code>90vw</code></q> などの <q><a href="http://www.w3.org/TR/css3-values/#vw-unit" title="CSS Values and Units Module Level 3">ビューポートに対する表示幅の百分率</a></q> を指定します（<q><code>%</code></q> も指定可）。
</p>
<p>
一方 <code>srcset</code> 属性には <q><code>1x</code></q> とか <q><code>2x</code></q> の代わりに <q><code>480w</code></q> とか <q><code>960w</code></q> などが指定されています。これらは一見すると <q>ビューポート幅</q> を指しているようですが、実は各画像ファイルの横幅（CSS ピクセル値）を表します。
</p>
<p>
これらによりブラウザは、次式で算出される値を元に <code>srcset</code> 属性の中から最適な幅を持つ画像ファイルを選択します。
</p>
<p>[text]<br />
最適な画像ファイルの幅 = ビューポートに対する表示幅の百分率 / 100 × ビューポート幅 × デバイス・ピクセル比<br />
[/text]</p>
<p>
この書式であれば、純粋にレイアウト上の計算から導かれる選択肢をマークアップすれば OK で、ブラウザは、自らのビューポート幅やデバイス・ピクセル比に適した画像を選択することが出来るのです。
</p>
<p>
残念ながら Chrome 34 でこの書式は実装されていません。ですが <abbr title="Responsive Images Community Group">RICG</abbr> の <a href="http://responsiveimages.org/#implementation" title="Implementation status">実装状況リスト</a> にあるように、 <code>&lt;picture&gt;</code> 要素とのセットでリリースされるのではないかと思っています。
</p>
<p>
少しずつかも知れませんが、 RICG の活動が実を結ぶとイイですネ。
</p>
<h3 class="chapter">コンテンツとスタイルの境界</h3>
<p>
そもそも <a href="http://picture.responsiveimages.org/" title="he picture Element"><code>&lt;picture&gt;</code> 要素の仕様案</a> は <a href="http://www.brucelawson.co.uk/2011/notes-on-adaptive-images-yet-again/" title="Bruce Lawson’s personal site  : Notes on Adaptive Images (yet again!)"><code>&lt;video&gt;</code> 要素と相関性のある案</a> を元に策定されました。例えば以下のマークアップでは、ブラウザが適切なフォーマットを選ぶことができます。
</p>
<p>[html]<br />
&lt;video poster=&#8221;firstframe.jpg&#8221;&gt;<br />
	&lt;source src=&#8221;sample.mp4&#8243; type=&#8221;video/mp4; codecs=&#8217;&#8230;'&#8221;&gt;<br />
	&lt;source src=&#8221;sample.ogv&#8221; type=&#8221;video/ogg; codecs=&#8217;&#8230;'&#8221;&gt;<br />
&lt;/video><br />
[/html]</p>
<p>
ここまではコンテンツ側の問題であり、特に違和感はありません。これに対し、<code>&lt;picture&gt;</code> では、例えばこんな感じです。
</p>
<p>[html]<br />
&lt;picture&gt;<br />
	&lt;source media=&#8221;(min-width: 480px)&#8221; srcset=&#8221;small.jpg medium.jpg 2x&#8221;&gt;<br />
	&lt;source media=&#8221;(min-width: 960px)&#8221; srcset=&#8221;medium.jpg, large.jpg 2x&#8221;&gt;<br />
	&lt;img src=&#8221;small.jpg&#8221; alt=&#8221;&#8230;&#8221;&gt;<br />
&lt;/picture&gt;<br />
[/html]</p>
<p>
この仕様であれば、新しいメディア・タイプの出現やアート・ディレクションの要求を受け入れることが出来るでしょう。
</p>
<p>
一方、サイトのブレークポイントと上記 <code>media</code> 属性とが一致していないと、意図したリソースが選ばれないという問題が出てきます。こうなるともはや、「ドキュメント（HTML）とスタイル（CSS）の分離」という Web の原則や常識は、どこに行っちゃたの？ と疑いたくなります。
</p>
<p>
この仕様案に関しては、下位互換性のためとは言え、それ自体でコンテンツを表示しない画像系のタグが増えることに、ブラウザ・ベンダーが反対していたという話があったようです（すみません、出典は失念しました）。
</p>
<p>
最初の章でも書きましたが、実のところ、ドキュメントとスタイルの境界が極めて曖昧になる、というか、両者の結び付きが強まることが、今後の大きな課題だと思います。
</p>
<p>
先に「<code>&lt;picture&gt;</code> 要素はいずれ実装される」などと無責任な予測を書きましたが、この課題がどう決着されるのかは見ものです。これまでのように、そこそこの期間を要する可能性もあると思いますが、皆さんはどうお考えでしょうか？
</p>
<h3 class="chapter">さて過渡期の今、どう対処するか？</h3>
<p>
ハッキリ言って、分かりません（オィ、コラァ！）。少なくとも今回、記事に貼る画像を、デスクトップでの表示幅の2倍かつ画質 0 で作成してみました。まぁ、jpeg ならそれなりに減量効果はあります。
</p>
<p>
次回は、レスポンシブ画像を実現する様々な手法を取り上げながら、世界の人たちがどう対処しているのかを見ると共に、レスポンシブ画像に要求される近々の要件を整理しながら、さらに掘り下げてみたいと思います。
</p>
<p>
ご期待ください（するかぁ！？）。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/web-technology/future-of-responsive-design/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
							</item>
		<item>
		<title>GradeAの先行くWordPress高速化 &#8211; 必ず結果の出る実践的HTTPリクエスト削減法</title>
		<link>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/concatenate-resources/</link>
				<comments>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/concatenate-resources/#comments</comments>
				<pubDate>Wed, 23 Apr 2014 02:35:58 +0000</pubDate>
		<dc:creator><![CDATA[tokkonoPapa]]></dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[site optimization]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[tool]]></category>

		<guid isPermaLink="false">http://tokkono.cute.coocan.jp/blog/slow/?p=2214</guid>
				<description><![CDATA[WordPress は、プラグインで手軽に機能が拡張できる反面、あちこちに css や js が散乱し、放っておくとベスト・プラクティスからは程遠い状態になりがちです。 もちろんこういった問題の解決を図るプラグインも多数 [&#8230;]]]></description>
								<content:encoded><![CDATA[<p>
WordPress は、プラグインで手軽に機能が拡張できる反面、あちこちに css や js が散乱し、放っておくとベスト・プラクティスからは程遠い状態になりがちです。
</p>
<p>
もちろんこういった問題の解決を図るプラグインも多数リリースされていますが、ページ単位の処理なので、サイト全体の構成を通して最適にはなりません。
</p>
<p>
そこで第1部「<a href="/blog/slow/index.php/xhtmlcss/strategy-and-tactics-for-faster-site/">サイト高速化の「戦略」と「戦術」- GradeAのその先へ</a>」、第2部「<a href="/blog/slow/index.php/xhtmlcss/resource-potitioning-best-practice/">サイトに適したリソース配置とasync/defer完全マスター &#8211; レンダリング優先のグッド・プラクティス</a>」では、数あるベスト・プラクティスの全体を俯瞰し、個々の Tips やテクニックからは見え難い、最適化の考え方や道筋を提案しました。
</p>
<p>
その総仕上げとして今回は、WordPress サイトを例題に、必ず結果の出る HTTP リクエストの削減方法を提案したいと思います。
</p>
<p><span id="more-2214"></span></p>
<h3 class="chapter">実践的手法の概要</h3>
<p>
HTTP リクエストの削減を目的とした css、js の結合系プラグインでは、「サイトが正しく機能しない」といったことが頻繁に起き、その修正にはトライ＆エラーが必要です。
</p>
<p>
プラグインの幾つかは、トラブルに対処するための調整機能を提供してくれていますが、サポート・フォーラムを見ていると、そういった機能を使いこなす前に（あるいは存在すら知らずに）導入を断念するケースも少なくありません。
</p>
<p>
元はと言えばプラグインの導入で増えた乱雑な css や js を、ページ内の文脈に合わせて自動で結合すること自体、ムリな話です。「どのファイルをどう結合すべきか」は人手で仕分け、ある程度シンプルになったところでプラグインの力を借りる &#8211; 数あるプラグインを試して私が得た結論は、結局はこれが王道かつ近道だと言うことです。
</p>
<p>
そこで今回は、どのプラグインにも手を加えることなく css や js を見通しよく人手で結合し、残りをプラグインで自動結合する、という方針で臨むことにします。<q>人手</q> とは言え、結合を簡単化する補助的なツールを作成しましたので、ご安心を。
</p>
<p>
以下、その概要です。
</p>
<h4 class="chapter">人手による結合</h4>
<p>
「<a href="/blog/slow/index.php/xhtmlcss/strategy-and-tactics-for-faster-site/">サイト高速化の「戦略」と「戦術」- GradeAのその先へ</a>」でも述べたように、まずは以下の観点で css や js をグループに仕分けます。
</p>
<ul>
<li><code>&lt;head&gt;</code> に配置するリソース：「Above the hold」のコンテンツに関連するリソース</li>
<li><code>&lt;/body&gt;</code> に配置するリソース：サイト全体を通して共通なリソース</li>
</ul>
<p>
このうち、結合の対象とするのは WordPress の標準的な方法で挿入されたファイルとします。
</p>
<p>
「標準的な方法」とは、<code>wp_enqueue_*()</code> で挿入されたことを意味します（アクション・フックの <a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_head" title="Plugin API/Action Reference/wp head &laquo; WordPress Codex"><code>wp_head</code></a> や <a href="https://codex.wordpress.org/Plugin_API/Action_Reference/wp_footer" title="Plugin API/Action Reference/wp footer &laquo; WordPress Codex"><code>wp_footer</code></a> をトリガーに、外部ファイルの読み込みコードを直接 <code>echo</code> で吐き出すのは、今や時代遅れなのですョ <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ）。
</p>
<p>
作戦としては以下の通りです。
</p>
<ul>
<li><code>wp_enqueue_*()</code> でキューイングされているリソースを抽出する</li>
<li>一旦個々のリソースを <code>wp_dequeue_*()</code> で解除する</li>
<li>解除したリソースを、適当なツールで結合する</li>
<li>結合したリソースを <code>wp_enqueue_*()</code> でキューに登録する</li>
</ul>
<p>
最も面倒な作業が「キューイングされているリソースの抽出」ですが、各プラグインのソースコードを調べることなく、この作業を簡単化するツールは後半で説明します。
</p>
<p>
また、リソースの結合には PHP プログラム「<a href="https://code.google.com/p/minify/" title="minify - Combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads. - Google Project Hosting">minify</a>」を使います。応答性という点ではベストではありませんが、次のようなメリットがあります。
</p>
<ol>
<li>使い方が簡単</li>
<li>インストールが簡単</li>
<li>グループが構成できる</li>
<li>gzip 圧縮やキャッシュ有効期限の設定ができる</li>
<li>圧縮ファイルを予めキャッシュできるため、負荷が低い</li>
<li>304 Not Modified の応答ができる</li>
<li>APC や Memcache の導入も可能</li>
<li>幾つかの WordPress プラグインと親和性が良い</li>
</ol>
<p>
特にグループを構成できる点が、今回の趣旨にはぴったりです。また安定運用の暁には、構成したグループを静的ファイルに置き換え、CDN に叩き込めば完璧です！
</p>
<h4 class="chapter">プラグインによる結合</h4>
<p>
前章の結合で残ったリソースは次のいずれかでしょう。
</p>
<ul>
<li>ページに個別のリソース</li>
<li>ベスト・プラクティスに従い、<code>&lt;/body&gt;</code> 直前に置けば良いスクリプト</li>
</ul>
<p>
これらをプラグインで再結合します。
</p>
<p>
<a href="/blog/slow/index.php/wordpress/css-top-script-bottom-by-headcleaner/" title="&quot;CSSは上、JSは下&quot; を簡単に &#8211; Head Cleaner 使い方のコツ | ゆっくりと…">過去</a> の <a href="/blog/slow/index.php/wordpress/minify-css-and-javascript-files-for-faster-page/" title="WP MinifyでCSS/JavaScriptをまとめて軽量化、ページの応答速度を向上させる | ゆっくりと…">記事</a> では <a href="http://wordpress.org/plugins/head-cleaner/" title="WordPress &#8250; Head Cleaner &laquo; WordPress Plugins">Head Cleaner</a> や <a href="http://wordpress.org/plugins/wp-minify/" title="WordPress &#8250; WP Minify &laquo; WordPress Plugins">WP Minify</a>（現在は更新停止、セキュリティ問題アリ）をオススメしましたが、改めて19のプラグインをざっと評価した結果、以下の理由により、今回は <a href="http://wordpress.org/plugins/autoptimize/" title="WordPress &#8250; Autoptimize &laquo; WordPress Plugins">Autoptimize</a> をイチオシとします。
</p>
<ul>
<li>インラインの css や js も結合ファイルに含めるため、不具合が起きにくい</li>
<li>結合から外す除外指定の自由度が高く、柔軟な構成が可能</li>
<li><code>&lt;/body&gt;</code> 直前の配置を基本に、一部を &lt;head&gt; に置くことも可能</li>
<li>細かな調整を可能とするアクション・フックが豊富</li>
<li>予め不具合の出るプラグインへの対応が埋め込まれている</li>
<li><code>defer</code> 属性がサポートされている</li>
<li>サポート・フォーラムが活発で、何より作者の気合いが感じられる</li>
</ul>
<table class="responsive" id="minify-list" style="margin-left: auto; margin-right: auto;">
<caption>評価したプラグイン一覧</caption>
<thead>
<tr>
<th style="text-align:center">プラグイン名</th>
<th style="text-align:center">結合対象</th>
<th style="text-align:center">除外指定</th>
<th style="text-align:center">gzip圧縮</th>
<th style="text-align:center">cache設定</th>
<th style="text-align:center">備考</th>
</tr>
</thead>
<tbody>
<tr>
<td>
			<a href="http://wordpress.org/plugins/autoptimize/" title="WordPress &#8250; Autoptimize &laquo; WordPress Plugins">Autoptimize</a>
		</td>
<td>全 css、js</td>
<td>y</td>
<td>y</td>
<td>y</td>
<td>除外指定が秀逸、css の遅延読み込みも可</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/bwp-minify/" title="WordPress &#8250; Better WordPress Minify &laquo; WordPress Plugins">Better WordPress Minify</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>y</td>
<td>y</td>
<td>css の <code>url()</code> 展開OK、cache 期限はデフォルト2時間</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/assetsminify/" title="WordPress &#8250; AssetsMinify &laquo; WordPress Plugins">AssetsMinify</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>n</td>
<td>n</td>
<td>jQuery 依存関係ダメ、Compass・SASS・LESS 可、要 PHP 5.3+</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/simple-minify/" title="WordPress &#8250; Simple Minify &laquo; WordPress Plugins">Simple Minify</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>n</td>
<td>n</td>
<td>AssetsMiify の改悪版、結合数少、プロトコル省略不可</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/minify/" title="WordPress &#8250; Minify &laquo; WordPress Plugins">Minify</a>
		</td>
<td><code>wp_head()</code>, <code>wp_footer()</code></td>
<td>n</td>
<td>n</td>
<td>n</td>
<td>Memcached 利用可、要 <code>.htaccess</code> 連携、設定項目少</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/wp-minify-fix/" title="WordPress &#8250; WP Minify Fix &laquo; WordPress Plugins">WP Minify Fix</a>
		</td>
<td>全 css、js</td>
<td>y</td>
<td>y</td>
<td>y</td>
<td><a href="http://wordpress.org/plugins/wp-minify/" title="WordPress &#8250; WP Minify &laquo; WordPress Plugins">WP Minify</a> のセキュリティ対策版、他ドメイン結合可、HTML 縮小、FirePHP 連携</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/dependency-minification/" title="WordPress &#8250; Dependency Minification &laquo; WordPress Plugins">Dependency Minification</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>y</td>
<td>y</td>
<td>有効後サイト閲覧要、プロトコル省略不可</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/combine-css/" title="WordPress &#8250; Combine CSS &laquo; WordPress Plugins">Combine CSS</a> / <a href="http://wordpress.org/plugins/combine-js/" title="WordPress &#8250; Combine JS &laquo; WordPress Plugins">Combine JS</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>y</td>
<td>n</td>
<td>デバッグ機能あり</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/minipress/" title="WordPress &#8250; MiniPress &laquo; WordPress Plugins">MiniPress</a>
		</td>
<td>全 css、js</td>
<td>n</td>
<td>n</td>
<td>n</td>
<td>β版、設定項目無</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/asynchronous-javascript/" title="WordPress &#8250; Asynchronous Javascript &laquo; WordPress Plugins">Asynchronous Javascript</a>
		</td>
<td><code>wp_print_scripts()</code></td>
<td>n</td>
<td>n</td>
<td>n</td>
<td><a href="http://headjs.com/" title="Head.JS, the only script in your HEAD">Head.JS</a>、結合不可、Jetpack, WP Most Popular 併用不可</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/async-js-and-css/" title="WordPress &#8250; Async JS and CSS &laquo; WordPress Plugins">Async JS and CSS</a>
		</td>
<td><code>wp_head()</code>, <code>wp_footer()</code>, <code>wp_enqueue_*()</code></td>
<td>y</td>
<td>n</td>
<td>n</td>
<td>設定項目多め、結合不可、css インライン化</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/mncombine/" title="WordPress &#8250; MnCombine &laquo; WordPress Plugins">MnCombine</a>
		</td>
<td><code>wp_head()</code>, <code>wp_footer()</code></td>
<td>y</td>
<td>n</td>
<td>y</td>
<td>開発／製品の2モード</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/minqueue/" title="WordPress &#8250; MinQueue &laquo; WordPress Plugins">MinQueue</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>n</td>
<td>y</td>
<td>css、js のリストアップ機能あり</td>
</tr>
<td>
			<a href="https://wordpress.org/plugins/wp-deferred-javascripts/" title="WordPress &#8250; WP Deferred Javascripts &laquo; WordPress Plugins">WP Deferred Javascripts</a>
		</td>
<td><code>wp_enqueue_scripts()</code></td>
<td>y</td>
<td>n</td>
<td>n</td>
<td><a href="http://labjs.com/" title="LABjs Script Loader :: Home">LABjs</a>、結合不可</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/js-css-script-optimizer/" title="WordPress &#8250; JS &amp; CSS Script Optimizer &laquo; WordPress Plugins">JS &#038; CSS Script Optimizer</a>
		</td>
<td><code>wp_enqueue_*()</code></td>
<td>y</td>
<td>?</td>
<td>?</td>
<td>メモリ消費で落ちるとのコメント多数</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/external-files-optimizer/" title="WordPress &#8250; External Files Optimizer &laquo; WordPress Plugins">External Files Optimizer</a>
		</td>
<td>全 css、js</td>
<td>n</td>
<td>n</td>
<td>n</td>
<td>更新停止</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/cleanerpress/" title="WordPress &#8250; CleanerPress &laquo; WordPress Plugins">CleanerPress</a>
		</td>
<td><code>wp_enqueue_scripts()</code>, <code>wp_head()</code>, <code>wp_print_styles()</code></td>
<td>y</td>
<td>n</td>
<td>y</td>
<td><code>&lt;head&gt;</code> 整形、<a href="http://headjs.com/" title="Head.JS, the only script in your HEAD">Head.JS</a></td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/head-cleaner/" title="WordPress &#8250; Head Cleaner &laquo; WordPress Plugins">Head Cleaner</a>
		</td>
<td>全 css、js</td>
<td>y</td>
<td>y</td>
<td>y</td>
<td><code>&lt;head&gt;</code> の整形</td>
</tr>
<tr>
<td>
			<a href="http://wordpress.org/plugins/w3-total-cache/" title="WordPress &#8250; W3 Total Cache &laquo; WordPress Plugins">W3 Total Cache</a>
		</td>
<td>全 css、js</td>
<td>y</td>
<td>y</td>
<td>y</td>
<td>超多機能</td>
</tr>
</tbody>
</table>
<h3 class="chapter">css、js結合の実践的手法</h3>
<p>
例題として、ローカルに仕立てたサーバー <q><code>http://localhost/</code></q> のドキュメント・ルート直下に WordPress 3.9 + <a href="http://wordpress.org/themes/twentyfourteen" title="WordPress &#8250; Twenty Fourteen &laquo; Free WordPress Themes">TwentyFourteen</a> を、そして以下のプラグインをインストールしました。
</p>
<ul>
<li><a href="http://wordpress.org/plugins/meteor-slides/" title="WordPress &#8250; Meteor Slides &laquo; WordPress Plugins">Meteor Slides</a>
<ul>
<li style="list-style-type:none">インラインと外部スクリプトを組み合わせて使うため、自動結合で問題が起き易いパターンです。本例では「Above the fold」のコンテンツ、かつ各ページ共通のリソースという想定です。スクリプトの読み込み後にレンダリングするので表示が遅れがちですが、カスタマイズ機能を活用し、初期のレンダリングに必要な HTML をサーバー側で構築する例をお見せします。</li>
</ul>
</li>
<li><a href="http://wordpress.org/plugins/jquery-smooth-scroll/" title="WordPress &#8250; jQuery Smooth Scroll &laquo; WordPress Plugins">jQuery Smooth Scroll</a>
<ul>
<li style="list-style-type:none">これも各ページ共通で使う想定です。</li>
</ul>
</li>
<li><a href="http://wordpress.org/plugins/syntaxhighlighter/" title="WordPress &#8250; SyntaxHighlighter Evolved &laquo; WordPress Plugins">SyntaxHighlighter Evolved</a>
<ul>
<li style="list-style-type:none">クライアント側でレンダリングするタイプの代表で、<a href="/blog/slow/index.php/web-technology/reflow-and-repaint-in-browser/" title="ブラウザ動作の理解－リフローとリペイント及びその最適化 | ゆっくりと…">リフロー</a> や <abbr title="Flash Of Unstyled Content">FOUC</abbr> が避けらません。高速化の観点からは、サーバー側で HTML を構築する <a href="http://qbnz.com/highlighter/" title="GeSHi - Generic Syntax Highlighter :: Home">GeSHi</a> を使った <a href="/blog/slow/index.php/wordpress/speed-up-of-rendering-syntaxhighlighter/" title="Syntax Highlighter 系プラグインの比較と高速化 | ゆっくりと…">プラグイン</a> の方が良いでしょう。コードに応じて読み込むリソースが変わるので、ページ毎に個別のリソースという想定です。</li>
</ul>
</li>
<li><a href="http://wordpress.org/plugins/wp-social-bookmarking-light/" title="WordPress &#8250; WP Social Bookmarking Light &laquo; WordPress Plugins">WP Social Bookmarking Light</a>
<ul>
<li style="list-style-type:none"><code>wp_head</code>、<code>wp_footer</code> を介して css や js の読み込みを直接 <code>echo</code> するプラグインの代表です。Hatena に対応してるので、背に腹は代えられないという人なら。</li>
</ul>
</li>
</ul>
<p>
この例題に対するリソース配置のゴールを以下のように設定しました。
</p>
<ul>
<li>スライドショーを素早く表示させるため、そのリソースは <code>&lt;head&gt;</code> に配置する</li>
<li>ただし後続のページ解析を妨げないよう、スクリプトは <code>async</code> 付きで読み込む</li>
<li>また体感速度が速くなるよう、HTML は可能な限りサーバー側で構築する</li>
<li>Syntax Highlighter 用のリソースは、結合した上で <code>&lt;/body&gt;</code> 直前に配置する</li>
<li>ソーシャルメディア用のスクリプトは <code>&lt;/body&gt;</code> 直前に配置する</li>
</ul>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/SampleGoal.png" alt="ページ構成のゴール" width="580" height="500" class="aligncenter size-full wp-image-2216" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/SampleGoal.png 580w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/SampleGoal-300x258.png 300w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p>
以下、この例題を元に具体的に説明していきます。手順は多目ですが、ガンバって付いて来て下さい。きっと報われます <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<ol class="toc">
<li><a href="#pickup-handles">キューイングされているリソースのハンドル名を調べる</a></li>
<li><a href="#install-minify">minify のインストールと基本設定</a></li>
<li><a href="#define-groups"><code>groupsConfig.php</code> に結合対象のリソースをグループとして登録する</a></li>
<li><a href="#dequeue-resources"><code>functions.php</code> でグループ化した各リソースをキューから削除する</a></li>
<li><a href="#enqueue-resources"><code>functions.php</code> でグループをキューに登録する</a></li>
<li><a href="#minify-remainder">残ったリソースをプラグインで結合する</a></li>
<li><a href="#initial-view">初期のレンダリングを高速化する</a></li>
<li><a href="#minify-references">参考情報</a></li>
</ol>
<h4 class="chapter" id="pickup-handles">キューイングされているリソースのハンドル名を調べる</h4>
<p>
まずは次のコードを、テーマ（あるいは子テーマ）の <code>functions.php</code> に追加します。
</p>
<p>[php]<br />
/**<br />
 * Make the list of enqueued resources<br />
 **/<br />
function my_get_dependency( $dependency ) {<br />
    $dep = &#8220;&#8221;;<br />
    if ( is_a( $dependency, &#8220;_WP_Dependency&#8221; ) ) {<br />
        $dep .= &#8220;$dependency->handle&#8221;;<br />
        $dep .= &#8221; [&#8221; . implode( &#8221; &#8220;, $dependency->deps ) . &#8220;]&#8221;;<br />
        $dep .= &#8221; &#8216;$dependency->src'&#8221;;<br />
        $dep .= &#8221; &#8216;$dependency->ver'&#8221;;<br />
        $dep .= &#8221; &#8216;$dependency->args'&#8221;;<br />
        $dep .= &#8221; (&#8221; . implode( &#8221; &#8220;, $dependency->extra ) . &#8220;)&#8221;;<br />
    }<br />
    return &#8220;$dep\n&#8221;;<br />
}</p>
<p>function my_style_queues() {<br />
    global $wp_styles;<br />
    echo &#8220;&lt;!&#8211; WP_Dependencies for styles\n&#8221;;<br />
    foreach ( $wp_styles->queue as $val ) {<br />
        echo my_get_dependency( $wp_styles->registered[ $val ] );<br />
    }<br />
    echo &#8220;&#8211;&gt;\n&#8221;;<br />
}<br />
add_action( &#8216;wp_print_styles&#8217;, &#8216;my_style_queues&#8217;, 9999 );</p>
<p>function my_script_queues() {<br />
    global $wp_scripts;<br />
    echo &#8220;&lt;!&#8211; WP_Dependencies for scripts\n&#8221;;<br />
    foreach ( $wp_scripts->queue as $val ) {<br />
        echo my_get_dependency( $wp_scripts->registered[ $val ] );<br />
    }<br />
    echo &#8220;&#8211;&gt;\n&#8221;;<br />
}<br />
add_action( &#8216;wp_print_scripts&#8217;, &#8216;my_script_queues&#8217;, 9999 );<br />
[/php]</p>
<p>
続いてページを表示し、HTML ソースから以下のようなコメントを抜き出します。
</p>
<p>[text]<br />
&lt;!&#8211; WP_Dependencies for styles<br />
ハンドル名 [依存するハンドル名&#8230;] &#8216;パス&#8217; &#8216;バージョン&#8217; &#8216;属性&#8217; (付加情報&#8230;)<br />
&#8230;<br />
&#8211;&gt;</p>
<p>&lt;!&#8211; WP_Dependencies for scripts<br />
ハンドル名 [依存するハンドル名&#8230;] &#8216;パス&#8217; &#8216;バージョン&#8217; &#8216;属性&#8217; (付加情報&#8230;)<br />
&#8230;<br />
&#8211;&gt;<br />
[/text]</p>
<dl>
<dt>ハンドル名</dt>
<dd><code><a href="http://codex.wordpress.org/Function_Reference/wp_enqueue_style" title="Function Reference/wp enqueue style &laquo; WordPress Codex">wp_enqueue_style()</a></code>、<code><a href="http://codex.wordpress.org/Function_Reference/wp_enqueue_script" title="Function Reference/wp enqueue script &laquo; WordPress Codex">wp_enqueue_script()</a></code> でキューに挿入されるリソースのハンドル名です。</dd>
<dt>依存するハンドル名</dt>
<dd>先立って読み込んでおくべきリソースのハンドル名が上位から順に並びます。</dd>
<dt>パス</dt>
<dd><code><a href="http://codex.wordpress.org/Function_Reference/wp_register_style" title="Function Reference/wp register style &laquo; WordPress Codex">wp_register_style()</a></code>、<code><a href="http://codex.wordpress.org/Function_Reference/wp_register_script" title="Function Reference/wp register script &laquo; WordPress Codex">wp_register_script()</a></code> で登録されたリソースへのパスです。</dd>
<dt>バージョン</dt>
<dd>登録時に指定されたバージョン文字列です。</dd>
<dt>属性</dt>
<dd>css の場合はメディアタイプが表示されます。同一タイプであれば結合が可能です。</dd>
<dt>付加情報</dt>
<dd>css であれば IE 用の条件付コメントがここに表示されます。js の場合、<code>1</code> (<code>true</code>) が立っていればフッターで読み込まれることを示し、それ以外は「読み込みに先立って実行されるべきインライン・コード」が現れます。</dd>
</dl>
<p>
ここでのポイントは、色々なタイプのページを表示し、サイトに共通なリソース群や、優先して <code>&lt;head&gt;</code> に配置すべきリソース群など、グループ分けを行うことです。
</p>
<p>
今回は、Meteor Slides が各ページ共通、かつ優先すべきリソースという想定ですので、以下を <code>&lt;head&gt;</code> に置くリソースとして抽出しました。個別ページ用の <q><code>comment-reply.min.js</code></q> や IE 用の css などは含んでいません。
</p>
<p>[text]<br />
&lt;!&#8211; WP_Dependencies for styles<br />
genericons [] &#8216;http://localhost/wp-content/themes/twentyfourteen/genericons/genericons.css&#8217; &#8216;3.0.2&#8217; &#8216;all&#8217; ()<br />
twentyfourteen-style [genericons] &#8216;http://localhost/wp-content/themes/twentyfourteen/style.css&#8217; &#8221; &#8216;all&#8217; ()<br />
twentyfourteen-ie [twentyfourteen-style genericons] &#8216;http://localhost/wp-content/themes/twentyfourteen/css/ie.css&#8217; &#8216;20131205&#8217; &#8216;all&#8217; (lt IE 9)<br />
meteor-slides [] &#8216;http://localhost/wp-content/plugins/meteor-slides/css/meteor-slides.css&#8217; &#8216;1.0&#8217; &#8216;all&#8217; ()<br />
blogsynthesis-scroll-to-top-style [] &#8216;http://localhost/wp-content/plugins/jquery-smooth-scroll/css/jss-style.min.css&#8217; &#8221; &#8216;all&#8217; ()<br />
&#8211;&gt;</p>
<p>&lt;!&#8211; WP_Dependencies for scripts<br />
jquery [jquery-core jquery-migrate] &#8221; &#8216;1.10.2&#8217; &#8221; ()<br />
jquery-cycle [jquery] &#8216;http://localhost/wp-content/plugins/meteor-slides/js/jquery.cycle.all.js&#8217; &#8221; &#8221; ()<br />
jquery-metadata [jquery] &#8216;http://localhost/wp-content/plugins/meteor-slides/js/jquery.metadata.v2.js&#8217; &#8221; &#8221; ()<br />
jquery-touchwipe [jquery] &#8216;http://localhost/wp-content/plugins/meteor-slides/js/jquery.touchwipe.1.1.1.js&#8217; &#8221; &#8221; ()<br />
twentyfourteen-script [jquery] &#8216;http://localhost/wp-content/themes/twentyfourteen/js/functions.js&#8217; &#8216;20131209&#8217; &#8221; (1)<br />
meteorslides-script [jquery jquery-cycle] &#8216;http://localhost/wp-content/plugins/meteor-slides/js/slideshow.js&#8217; &#8221; &#8221; (var meteorslidessettings = {&#8220;meteorslideshowspeed&#8221;:&#8221;2000&#8243;,&#8221;meteorslideshowduration&#8221;:&#8221;5000&#8243;,&#8221;meteorslideshowheight&#8221;:&#8221;200&#8243;,&#8221;meteorslideshowwidth&#8221;:&#8221;940&#8243;,&#8221;meteorslideshowtransition&#8221;:&#8221;fade&#8221;};)<br />
blogsynthesis-scroll-to-top-script [jquery] &#8216;http://localhost/wp-content/plugins/jquery-smooth-scroll/js/jss-script.min.js&#8217; &#8221; &#8221; ()<br />
&#8211;&gt;<br />
[/text]</p>
<p>
ハンドル名 <q><code>jquery</code></q> には <q>パス</q> が現れず、<q><code>jquery-core</code></q> と <q><code>jquery-migrate</code></q> への依存が指定されています。それぞれのパスは次の通りです。
</p>
<ul>
<li><code>wp-includes/js/jquery/jquery.js</code></li>
<li><code>wp-includes/js/jquery/jquery-migrate.min.js</code></li>
</ul>
<p>
パスが空のハンドル名が出てきたら、面倒でも <a href="http://codex.wordpress.org/Function_Reference/wp_register_script" title="Function Reference/wp register script &laquo; WordPress Codex">Handles and Their Script Paths Registered by WordPress</a> を調べて下さい。
</p>
<p>
またこれらの情報は優先度が高い順に並ぶとは限りません。結合対象とする css と js のハンドル名をピックアップし、順番に注意した上で並べ換えておきましょう。
</p>
<h4 class="chapter" id="install-minify">minify のインストールと基本設定</h4>
<p>
<a href="https://code.google.com/p/minify/downloads/list" title="Downloads - minify - Combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads. - Google Project Hosting">ダウンロード・リンク</a> から最新版を落とし、解凍後、「<code>min</code>」ディレクトリだけをサーバーにアップロードします。「<code>min</code>」はドキュメント・ルートに置くことが推奨されていますが、今回は <code>wp-content</code> の直下に配置してみました。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/minify-2.1.7.jpg" alt="minifyの構成" width="580" height="200" class="aligncenter size-full wp-image-2217" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/minify-2.1.7.jpg 580w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/minify-2.1.7-300x103.jpg 300w" sizes="(max-width: 580px) 100vw, 580px" /></p>
<p>
基本設定で重要なのは2か所です。<code>min/config.php</code> を開き、以下を参考に設定して下さい。
</p>
<h5 class="chapter">キャッシュ保存場所の設定</h5>
<p>
次は、「<code>min</code>」の直下に「<code>cache</code>」というディレクトリを作成する場合の例です。
</p>
<p>[php]<br />
/**<br />
 * For best performance, specify your temp directory here. Otherwise Minify<br />
 * will have to load extra code to guess. Some examples below:<br />
 */<br />
//$min_cachePath = &#8216;c:\\WINDOWS\\Temp&#8217;;<br />
//$min_cachePath = &#8216;/tmp&#8217;;<br />
//$min_cachePath = preg_replace(&#8216;/^\\d+;/&#8217;, &#8221;, session_save_path());<br />
$min_cachePath = dirname(__FILE__) . &#8216;/cache&#8217;;<br />
[/php]</p>
<p>
作成したディレクトリには、お使いのサーバーに合わせてパーミッションを設定します。大抵の場合は <code>755</code> で OK でしょう。
</p>
<h5 class="chapter">キャッシュ有効期間</h5>
<p>
ブラウザやプロキシー・サーバーに保持させるキャッシュ期間を「秒」で指定します。出来る限り長く（1か月）設定し、「Grade A」の条件を保ちましょう。
</p>
<p>[php]<br />
/**<br />
 * Cache-Control: max-age value sent to browser (in seconds). After this period,<br />
 * the browser will send another conditional GET. Use a longer period for lower<br />
 * traffic but you may want to shorten this before making changes if it&#8217;s crucial<br />
 * those changes are seen immediately.<br />
 *<br />
 * Note: Despite this setting, if you include a number at the end of the<br />
 * querystring, maxAge will be set to one year. E.g. /min/f=hello.css&amp;123456<br />
 */<br />
$min_serveOptions[&#8216;maxAge&#8217;] = 2592000; /* one month */<br />
[/php]</p>
<h5 class="chapter">その他</h5>
<p>
<code>$min_builderPassword</code> は、<code>min/builder</code> を利用しない（<code>$min_enableBuilder = false</code>）限り、気にする必要はありません。<code>min/builder</code> は、<code>index.php</code> に引き渡すクエリ文字列を構築する補助ツールです。詳しくは <q><a href="http://www.mrclay.org/2008/09/19/minify-21-on-mrclayorg/" title="Minify 2.1 on mrclay.org | mrclay.org">Minify 2.1 on mrclay.org</a></q> を参照してください。
</p>
<h4 class="chapter" id="define-groups"><code>groupsConfig.php</code> に結合対象のリソースをグループとして登録する</h4>
<p>
ピックアップしておいた結合対象の css と js を、サイト共通のリソース・グループとして <code>min/groupsConfig.php</code> に登録します。条件付きコメントで読み込まれる IE 用 css は含まないよう注意してください。
</p>
<p>
今回は、<code>&lt;head&gt;</code> に置く <q><code>site-css</code></q> と <q><code>site-js</code></q> をグループとして登録しました。もちろんグループは幾つでも定義する事ができます。
</p>
<p>[php]<br />
/**<br />
 * You may wish to use the Minify URI Builder app to suggest<br />
 * changes. http://yourdomain/min/builder/<br />
 *<br />
 * See http://code.google.com/p/minify/wiki/CustomSource for other ideas<br />
 **/</p>
<p>return array(<br />
    // &#8216;css&#8217; => array(&#8216;//css/file1.css&#8217;, &#8216;//css/file2.css&#8217;),<br />
    &#8216;site-css&#8217; => array(<br />
        &#8216;//wp-content/themes/twentyfourteen/genericons/genericons.css&#8217;,<br />
        &#8216;//wp-content/themes/twentyfourteen/style.css&#8217;,<br />
        &#8216;//wp-content/plugins/meteor-slides/css/meteor-slides.css&#8217;,<br />
        &#8216;//wp-content/plugins/jquery-smooth-scroll/css/jss-style.min.css&#8217;,<br />
    ),</p>
<p>    // &#8216;js&#8217; => array(&#8216;//js/file1.js&#8217;, &#8216;//js/file2.js&#8217;),<br />
    &#8216;site-js&#8217; => array(<br />
        &#8216;//wp-includes/js/jquery/jquery.js&#8217;,<br />
        &#8216;//wp-includes/js/jquery/jquery-migrate.min.js&#8217;,<br />
        &#8216;//wp-content/plugins/meteor-slides/js/jquery.cycle.all.js&#8217;,<br />
        &#8216;//wp-content/plugins/meteor-slides/js/jquery.metadata.v2.js&#8217;,<br />
        &#8216;//wp-content/plugins/meteor-slides/js/jquery.touchwipe.1.1.1.js&#8217;,<br />
        &#8216;//wp-content/plugins/meteor-slides/js/slideshow.js&#8217;,<br />
        &#8216;//wp-content/plugins/jquery-smooth-scroll/js/jss-script.min.js&#8217;,<br />
        &#8216;//wp-content/themes/twentyfourteen/js/functions.js&#8217;,<br />
    ),<br />
);<br />
[/php]</p>
<p>
（コメント以外の）先頭の <q><code>//</code></q> は minify 独自の表記法で、ドキュメント・ルートを表します。
</p>
<p>
上の例ではローカルの <q><code>jquery.js</code></q> を結合対象にしていますが、CDN を使いたい場合には外してください。またリモート・ファイルを加えることも可能です。詳しくは <a href="http://code.google.com/p/minify/wiki/CustomSource#Non-File_Sources" title="CustomSource - minify - Using Minify_Source objects for more flexibility - Combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads. - Google Project Hosting">Non-File Sources</a> を参考にして下さい。
</p>
<p>
設定後、<q><code>http://localhost/wp-content/min/?g=site-css</code></q>、<q><code>http://localhost/wp-content/min/?g=site-js</code></q> にそれぞれアクセスできるか確認しておきましょう。
</p>
<p>
ちなみに <a href="http://httpd.apache.org/" title="Welcome! - The Apache HTTP Server Project">Apache サーバー</a> なら、「<code>min/.htaccess</code>」の設定により <q><code>?</code></q> が省略可能です。プロキシーによっては <q><code>?</code></q> 付きのリクエストがキャッシュされないことがあるそうなので、できれば省略しましょう。
</p>
<h4 class="chapter" id="dequeue-resources"><code>functions.php</code> でグループ化した各リソースをキューから削除する</h4>
<p>
次に、結合対象の各リソースをキューから削除するコードを追加します。同時にこれらと依存関係のある IE 用 css も解除しておきます（後で復活させるので、ご心配なく）。
</p>
<p>[php]<br />
/**<br />
 * Dequeue resources<br />
 **/<br />
function my_dequeue_styles() {<br />
    wp_dequeue_style( &#8216;genericons&#8217; );<br />
    wp_dequeue_style( &#8216;twentyfourteen-style&#8217; );<br />
    wp_dequeue_style( &#8216;twentyfourteen-ie&#8217; );<br />
    wp_dequeue_style( &#8216;meteor-slides&#8217; );<br />
    wp_dequeue_style( &#8216;blogsynthesis-scroll-to-top-style&#8217; );<br />
}<br />
add_action( &#8216;wp_print_styles&#8217;, &#8216;my_dequeue_styles&#8217; );</p>
<p>function my_dequeue_scripts() {<br />
    wp_dequeue_script( &#8216;jquery&#8217; );<br />
    wp_dequeue_script( &#8216;jquery-cycle&#8217; );<br />
    wp_dequeue_script( &#8216;jquery-metadata&#8217; );<br />
    wp_dequeue_script( &#8216;jquery-touchwipe&#8217; );<br />
    wp_dequeue_script( &#8216;meteorslides-script&#8217; );<br />
    wp_dequeue_script( &#8216;twentyfourteen-script&#8217; );<br />
    wp_dequeue_script( &#8216;blogsynthesis-scroll-to-top-script&#8217; );<br />
}<br />
add_action( &#8216;wp_print_scripts&#8217;, &#8216;my_dequeue_scripts&#8217; );<br />
[/php]</p>
<h4 class="chapter" id="enqueue-resources"><code>functions.php</code> でグループをキューに登録する</h4>
<h5 class="chapter">css の挿入</h5>
<p>
続いて、グループ <q><code>site-css</code></q> を挿入します。
</p>
<p>
ポイントは IE 用 css の再挿入です。<a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_enqueue_scripts" title="Plugin API/Action Reference/wp enqueue scripts &laquo; WordPress Codex"><code>wp_enqueue_scripts()</code></a> と <a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_print_styles" title="Plugin API/Action Reference/wp print styles &laquo; WordPress Codex"><code>wp_print_styles()</code></a> とでは、後者の方が後に実行されるため、ハンドル名を変えて再登録します。
</p>
<p>[php]<br />
/**<br />
 * Eequeue resources<br />
 **/<br />
function my_enqueue_styles() {<br />
    wp_enqueue_style( &#8216;site-css&#8217;, site_url() . &#8216;/wp-content/min/?g=site-css&#8217;, array(), &#8216;1.0&#8217; );<br />
    wp_enqueue_style( &#8216;my-enqueue-ie&#8217;, get_template_directory_uri() . &#8216;/css/ie.css&#8217;, array( &#8216;site-css&#8217; ) );<br />
    wp_style_add_data( &#8216;my-enqueue-ie&#8217;, &#8216;conditional&#8217;, &#8216;lt IE 9&#8217; );<br />
}<br />
add_action( &#8216;wp_enqueue_scripts&#8217;, &#8216;my_enqueue_styles&#8217; );<br />
[/php]</p>
<h5 class="chapter">js の挿入</h5>
<p>
さらに、グループ <q><code>site-js</code></q> を挿入します。
</p>
<p>
ここでの最初のポイントは js の配置です。今回 <q><code>site-js</code></q> は <code>&lt;head&gt;</code> に配置するので、<a href="http://codex.wordpress.org/Function_Reference/wp_enqueue_script" title="Function Reference/wp enqueue script &laquo; WordPress Codex"><code>wp_enqueue_script()</code></a> の5番目の引数 <q><code>$in_footer</code></q> には <q><code>false</code></q> を設定します。
</p>
<p>
第2のポイントは「読み込みに先立って実行されるべきインライン・コード」の設定です。本例ではスライドショーの設定がこれに当たり、<a href="http://codex.wordpress.org/Function_Reference/wp_localize_script" title="Function Reference/wp localize script &laquo; WordPress Codex"><code>wp_localize_script()</code></a> を使って埋め込みます。
</p>
<p>[php]<br />
function my_enqueue_scripts() {<br />
    wp_enqueue_script( &#8216;site-js&#8217;, site_url() . &#8216;/wp-content/min/?g=site-js&#8217;, array(), &#8216;1.0&#8217;, false );<br />
    wp_localize_script( &#8216;site-js&#8217;, &#8216;meteorslidessettings&#8217;, array(<br />
        &#8220;meteorslideshowspeed&#8221;      => &#8220;2000&#8221;,<br />
        &#8220;meteorslideshowduration&#8221;   => &#8220;5000&#8221;,<br />
        &#8220;meteorslideshowheight&#8221;     =>  &#8220;200&#8221;,<br />
        &#8220;meteorslideshowwidth&#8221;      =>  &#8220;940&#8221;,<br />
        &#8220;meteorslideshowtransition&#8221; => &#8220;fade&#8221;,<br />
    ) );<br />
}<br />
add_action( &#8216;wp_enqueue_scripts&#8217;, &#8216;my_enqueue_scripts&#8217; );<br />
[/php]</p>
<p>
またより低レベルな関数 <a href="https://core.trac.wordpress.org/browser/tags/3.9/src/wp-includes/class.wp-dependencies.php#L225" title="class.wp-dependencies.php in tags/3.9/src/wp-includes – WordPress Trac"><code>add_data()</code></a> を使う方法もあります（css には <code>add_data()</code> のラッパー関数 <a href="https://core.trac.wordpress.org/browser/tags/3.9/src/wp-includes/functions.wp-styles.php#L220" title="functions.wp-styles.php in tags/3.9/src/wp-includes – WordPress Trac"><code>wp_style_add_data()</code></a> が有るのに js に無いのは何故でしょう？）。
</p>
<p>[php]<br />
function my_enqueue_scripts() {<br />
    wp_enqueue_script( &#8216;site-js&#8217;, site_url() . &#8216;/wp-content/min/?g=site-js&#8217;, array(), &#8216;1.0&#8217;, false );<br />
    $js = <<<EOT
var meteorslidessettings = {
    "meteorslideshowspeed":"2000",
    "meteorslideshowduration":"5000",
    "meteorslideshowheight":"200",
    "meteorslideshowwidth":"940",
    "meteorslideshowtransition":"fade"
};
EOT;
    global $wp_scripts;
    $wp_scripts->add_data( &#8216;site-js&#8217;, &#8216;data&#8217;, $js );<br />
}<br />
add_action( &#8216;wp_enqueue_scripts&#8217;, &#8216;my_enqueue_scripts&#8217; );<br />
[/php]</p>
<p>
CDN の jQuery を使う場合は、<q><code>site-js</code></q> の登録を次のコードに置き換えます。
</p>
<p>[php]<br />
function my_enqueue_scripts() {<br />
    wp_deregister_script( &#8216;jquery&#8217; );<br />
    wp_enqueue_script( &#8216;jquery&#8217;, &#8216;//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js&#8217;, array(), &#8216;1.11.0&#8217;, false );<br />
    wp_enqueue_script( &#8216;site-js&#8217;, site_url() . &#8216;/wp-content/min/?g=site-js&#8217;, array( &#8216;jquery&#8217; ), &#8216;1.0&#8217;, false );<br />
    &#8230;<br />
}<br />
[/php]</p>
<p>
最後のポイントは、<q><code>site-js</code></q> への <code>async</code> 属性の付与です。ちょっと危ういハックですが、<a href="https://core.trac.wordpress.org/attachment/ticket/12009/defer%20and%20async.patch" title="defer and async.patch on Ticket #12009 – Attachment – WordPress Trac">公式サポートがまだ実現していない</a> 以上、やむを得ないですネ。
</p>
<p>[php]<br />
function my_add_async( $url ) {<br />
    if ( strpos( $url, &#8216;/min/?g=site-js&#8217; ) !== FALSE ) {<br />
        return &#8220;$url&#8217; async id=&#8217;site-js&#8221;;<br />
    }<br />
    return $url;<br />
}<br />
add_filter( &#8216;clean_url&#8217;, &#8216;my_add_async&#8217;, 11, 1 );<br />
[/php]</p>
<p>
他にも非同期化できるスクリプトがあれば可能な限り <code>async</code> や <code>defer</code> を付けましょう。詳しくは「<a href="/blog/slow/index.php/xhtmlcss/resource-potitioning-best-practice/">サイトに適したリソース配置とasync/defer完全マスター &#8211; レンダリング優先のグッド・プラクティス</a>」を参考にしてください。
</p>
<h4 class="chapter" id="minify-remainder">残ったリソースをプラグインで結合する</h4>
<p>
ここまでで結合していない or できない css、js は次のいずれかでしょう。
</p>
<ul>
<li>標準的な手法で登録されてはいるが、ページごとに異なるリソース</li>
<li><a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_head" title="Plugin API/Action Reference/wp head &laquo; WordPress Codex"><code>wp_head</code></a> や <a href="https://codex.wordpress.org/Plugin_API/Action_Reference/wp_footer" title="Plugin API/Action Reference/wp footer &laquo; WordPress Codex"><code>wp_footer</code></a> などのアクション・フックをトリガーに直接埋め込まれたリソース</li>
</ul>
<p>
これらを <a href="http://wordpress.org/plugins/autoptimize/" title="WordPress &#8250; Autoptimize &laquo; WordPress Plugins">Autoptimize</a> で結合し、<code>&lt;/body&gt;</code> 直前に配置します。
</p>
<p>
今回の例題では、「読み込みに先立って実行されるべきインライン・コード」への対応がキモです。そのままではインライン部分がファイルに結合され、<code>&lt;/body&gt;</code> 直前へと持っていかれてしまいます。
</p>
<p>
これを防止するため Autoptimize の除外リストに、インライン・スクリプトに含まれる文字列 <q><code>meteorslides</code></q> を（ついでに <q><code>googleapis</code></q> や <q><code>site-js</code></q> も）設定します。
</p>
<p><img src="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/Autoptimize.jpg" alt="Autoptimizeの設定" width="570" height="440" class="aligncenter size-full wp-image-2218" srcset="http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/Autoptimize.jpg 570w, http://tokkono.cute.coocan.jp/blog/slow/wp-content/uploads/2014/03/Autoptimize-300x231.jpg 300w" sizes="(max-width: 570px) 100vw, 570px" /></p>
<p>
あるいは次のようにアクション・フィルタでも設定できます。詳しくは Autoptimize に同梱されている <code>autoptimize_helper.php_example</code> を参照して下さい。
</p>
<p>[php]<br />
/*<br />
 * Autoptimize filter: Exclude js files<br />
 * @see: /wp-content/plugins/autoptimize/autoptimize_helper.php_example<br />
 */<br />
function my_jsexclude( $exclude ) {<br />
    return &#8220;googleapis,site-js,meteorslides,&#8221; . $exclude;<br />
}<br />
add_filter( &#8216;autoptimize_filter_js_exclude&#8217;, &#8216;my_jsexclude&#8217;, 10, 1 );<br />
[/php]</p>
<p>
Autoptimize は、デフォルトで <code>&lt;/body&gt;</code> 直前のスクリプトに <code>defer</code> 属性を付けてくれますが、他との依存関係がなければ、さらに <code>async</code> 属性も付けちゃいましょう！
</p>
<p>[php]<br />
/*<br />
 * Autoptimize filter: Add async attribute<br />
 * @see: /wp-content/plugins/autoptimize/autoptimize_helper.php_example<br />
 */<br />
function my_override_defer( $defer ) {<br />
    return $defer . &#8220;async &#8220;;<br />
}<br />
add_filter( &#8216;autoptimize_filter_js_defer&#8217;, &#8216;my_override_defer&#8217;, 10, 1 );<br />
[/php]</p>
<h4 class="chapter" id="initial-view">初期のレンダリングを高速化する</h4>
<p>
Meteo Slides は、スライドショーのテンプレートや css、js を（子）テーマのディレクトリに放り込んでおくことで、元ファイルを修正せずにカスタマイズが可能です。
</p>
<p>
そこで、<code>wp-content/plugins/meteor-slides/includes/meteor-slideshow.php</code> を（子）テーマのディレクトリにコピーし、127行目付近の次のコードを改修します。
</p>
<p>[php]<br />
echo &#8216;&lt;img style=&#8221;visibility: hidden;&#8221; class=&#8221;meteor-shim&#8221; src=&#8221;&#8216; . $meteor_shim[0] . &#8216;&#8221; alt=&#8221;&#8221; /&gt;&#8217;;<br />
[/php]</p>
<p>
上記コードでは、スクリプトが実行されるまで1枚目の画像が表示されません。「Above the fold のコンテンツは、可能な限りサーバーサイドで構築する」ために、「<code>style="visibility: hidden;"</code>」を削除しちゃいましょう！
</p>
<p>
以上で終了です。フ〜、お疲れ様でした <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h4 class="chapter" id="minify-references">参考情報</h4>
<ul>
<li>2012年06月13日 <a href="http://www.nxworld.net/wordpress/wp-action-hook1.html" title="WordPress：functions.phpでJSやCSSを一元管理する方法とバージョン表記を消す方法 | NxWorld">WordPress：functions.phpでJSやCSSを一元管理する方法とバージョン表記を消す方法</a></li>
<li>2010年08月14日 <a href="http://ottopress.com/2010/passing-parameters-from-php-to-javascripts-in-plugins/" title="Passing parameters from PHP to Javascripts in plugins &raquo; Otto on WordPress">Passing parameters from PHP to Javascripts in plugins</a></li>
<li>2011年08月03日 <a href="http://wordpress.stackexchange.com/questions/24851/wp-enqueue-inline-script-due-to-dependancies" title="wp enqueue inline script due to dependancies - WordPress Answers">wp enqueue inline script due to dependancies</a></li>
<li>2012年05月10日 <a href="http://wordpress.stackexchange.com/questions/51692/should-3rd-parties-use-wp-scripts-wp-styles-add-data" title="wp dependencies - Should 3rd Parties Use $wp_scripts/$wp_styles-&gt;add_data? - WordPress Answers">Should 3rd Parties Use $wp_scripts/$wp_styles->add_data?</a></li>
<li>2012年01月12日 <a href="http://wordpress.stackexchange.com/questions/38319/how-to-add-defer-defer-tag-in-plugin-javascripts" title="filters - How to add defer=&quot;defer&quot; tag in plugin javascripts? - WordPress Answers">How to add defer=&quot;defer&quot; tag in plugin javascripts?</a></li>
<li>2012年06月14日 <a href="http://css-tricks.com/one-two-three/" title="One, Two, or Three | CSS-Tricks">One, Two, or Three | CSS-Tricks</a></li>
</ul>
<h3 class="chapter">おまけ &#8211; Autoptimize を使いこなす</h3>
<p>
Autoptimize は、ページ中のすべてのインライン・コードや自サイトにホストされた外部リソースを1つのファイルに結合することを基本に、そこから問題のあったリソースを外していくというアプローチを元に設計されています。
</p>
<p>
そこで、トラブルを解消し、効果を最大限に引き出す Autoptimize の隠れた機能とオプションの使い方を紹介しておきます。
</p>
<dl>
<dt>【 結合の対象外とするブロックの指定 】</dt>
<dd>
<p><code>&lt;!--nooptimize--&gt;</code> ～ <code>&lt;!--/noptimize--&gt;</code> で囲んだコード・ブロックを、結合の対象外とします。</p>
<p>[html]<br />
&lt;!&#8211;noptimize&#8211;&gt;<br />
    &lt;script&gt;alert( &#8216;this will not get autoptimized&#8217; );&lt;/script&gt;<br />
&lt;!&#8211;/noptimize&#8211;&gt;<br />
[/html]
	</dd>
<dt>【 Force JavaScript in <code>&lt;/body&gt;</code>? 】</dt>
<dd>
<p>Autoptimize はデフォルトで、スクリプトの読み込みを <code>&lt;/body&gt;</code> 直前に移動させます。JavaScript は HTML の最後で読み込むのがパフォーマンス上はベストですが、問題が生じる場合が多々あります。</p>
<p>このオプションを有効にすると、Autoptimize は <code>&lt;head&gt;</code> セクションにあるスクリプトをそのまま <code>&lt;head&gt;</code> にとどめます。特に jQuery ベースのテーマに有効なオプションです。</p>
</dd>
<dt>【 Look for scripts only in <code>&lt;head&gt;</code>? 】</dt>
<dd>
<p>jQuery ベースのテンプレートなど、大抵は上記と組み合わると効果を発揮するオプションで、<code>&lt;head&gt;</code> 内のスクリプトだけを結合対象とします。例えばサイトに共通なリソースが <code>&lt;head&gt;</code> セクションに集約されていれば、キャッシュ<a href="#ao-cache" title="脚注"><span>&nbsp;*&nbsp;</span></a> のサイズを適切に維持することができます。</p>
<p><span id="ao-cache">*</span> Autoptimize がサーバーに生成するキャッシュとブラウザ・キャッシュの両方を指します。詳しくは <a href="http://blog.futtta.be/2014/03/19/how-to-keep-autoptimizes-cache-size-under-control-and-improve-visitor-experience/" title="How to keep Autoptimize&#8217;s cache size under control (and improve visitor experience) | Frank Goossens&#039; blog">作者のブログ記事</a> をご覧ください。</p>
</dd>
<dt>【 Exclude scripts from Autoptimize 】</dt>
<dd>
<p>結合対象外とするスクリプトを、そのブロックに含まれる文字列をカンマ区切りで指定します。例えば <q>whatever.js, another.js</q> などです。またカンマ前後の空白はトリムされます。</p>
<p>デフォルトの設定が必要なければ、空にしておきましょう。また先頭から順に処理されるので、追加は先頭に行うのが吉です。</p>
</dd>
<dt>【 Add try-catch wrapping 】</dt>
<dd>
<p>外部スクリプトの読み込みとインライン・スクリプトの実行順序が崩れると、エラーが発生する場合があります。このオプションを有効にすると、エラー発生時にも繰り返し実行を試みる <code>try-catch</code> ループでインライン・スクリプトを囲みます（同時にログをコンソールに出力）。JavaScript のエラーが発生する場合に試すべきオプションです。</p>
</dd>
<dt>【 Generate data:URIs for images 】</dt>
<dd>
<p>小さな背景画像を Data URI 化します。画像ファイルへの HTTP リクエストを削減する効果があります。</p>
</dd>
<dt>【 Look for styles only in <code>&lt;head&gt;</code>? 】</dt>
<dd>
<p><code>&lt;head&gt;</code> セクション外にある CSS を結合の対象外とします。スタイル崩れが発生した時に、試してみるべきオプションです。</p>
</dd>
<dt>【 Defer CSS loading 】</dt>
<dd>
<p>CSS を遅延読み込みします。特にモバイル向けコンテンツは、「Above the fold」のレンダリングを優先させるため、必要最低限のスタイルをインラインで展開し、残りを後から読み込むのが良いとされます。</p>
<p>このオプションを有効にする場合、<code>&lt;head&gt;</code> セクションにインライン展開したスタイルを <code>&lt;!--noptimize--&gt;</code> ～ <code>&lt;!--/noptimize--&gt;</code> で囲む必要があります。</p>
</dd>
<dt>【 Inline all CSS? 】</dt>
<dd>
<p>ページ・ビューや訪問者の少ないサイトなら、CSS のインライン化が有効な場合もありますが、それ以外では、パフォーマンスを低下させるでしょう。このオプションは、CSS の遅延読み込みを無効にします。</p>
</dd>
<dt>【 Exclude CSS from Autoptimize 】</dt>
<dd>
<p>結合の対象外とする CSS を、そのブロックに含まれる文字列をカンマ区切りで指定します。スタイル崩れが発生した時に、試してみるべきオプションです。</p>
</dd>
</dl>
<h3 class="chapter">注意事項 !!</h3>
<p>
本記事では全てを一気に設定する感じで説明しましたが、本来は少しずつグループ化するリソースを増やしながら動作確認をし、進めるべきです。
</p>
<p>
また提案したプロセスの最大の難点は、<code>functions.php</code> と <code>groupsConfig.php</code> の2つを同時に更新しなければならないことです。本番環境でこれら2つの更新に時間差が生じるとマズイことになるのは容易に想像がつきますよネ。
</p>
<p>
万全を期するなら、<code>groupsConfig.php</code> に登録するグループ名を <q><code>site-js-0.1</code></q>, <q><code>site-js-0.2</code></q>, … というように1ステップずつ刻んで追加していき、運用が安定したら整理するというやり方があるかと思います。
</p>
<p>
また少なくとも <code>functions.php</code> は、すぐに元に戻せるようバックアップしておきましょう。可能なら、テスト環境を準備するのが吉です <img src="https://s.w.org/images/core/emoji/11.2.0/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 。
</p>
<h3 class="chapter">まとめ</h3>
<p>
サイト全体を通して共通するリソースとページに個別のリソースを分けて束ねることで、初回訪問時はもとより、ページ遷移時の表示速度をも向上させることができます。これは、直帰率を下げることにもつながると思います。
</p>
<p>
その際、すべてをプラグイン任せにせず、逆に手作業を主体とすることで、起こりがちなトラブルを回避し、また個々のプラグインに手を入れることなく css や js を結合する方法について述べました。
</p>
<p>
そもそも「どのリソースをどう束ねるか」にはヒトの高度な分析力が必要で、完全自動というワケにはいかないでしょう。ただし面倒なところにはツールを使って簡単化できることを提案したつもりです。
</p>
<p>
またプラグイン導入の際は、単に機能面だけじゃなく、高速化の観点で選定することも大事な Tips の1つだと思います。
</p>
<p>
「CloudFlare 導入、一発 OK！」も悪くはありませんが（そういうサービスですからネ）、自サイトのリソース削減に四苦八苦している人、サイト全体を通した最適化で更なる高みを目指したい人は、ぜひお試しあれ。必ず結果は出ると思いますョ。</p>
]]></content:encoded>
							<wfw:commentRss>http://tokkono.cute.coocan.jp/blog/slow/index.php/wordpress/concatenate-resources/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
							</item>
	</channel>
</rss>
