<?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/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>吾郷 協 &#8211; HTML5Experts.jp</title>
	<atom:link href="/kyo_ago/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>Babelで始める！モダンJavaScript開発</title>
		<link>/kyo_ago/16979/</link>
		<pubDate>Thu, 01 Oct 2015 00:00:56 +0000</pubDate>
		<dc:creator><![CDATA[吾郷 協]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ECMAScript]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[babel]]></category>

		<guid isPermaLink="false">/?p=16979</guid>
		<description><![CDATA[連載： ECMAScript 2015（ECMAScript 6）特集 (3)この記事は「ECMAScript2015/ES6特集」の第3回目です。この特集ではJavaScriptの次世代仕様であるECMAScript ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/ecma2015/" class="series-336" title="ECMAScript 2015（ECMAScript 6）特集" data-wpel-link="internal">ECMAScript 2015（ECMAScript 6）特集</a> (3)</div><p>この記事は「ECMAScript2015/ES6特集」の第3回目です。この特集ではJavaScriptの次世代仕様であるECMAScript 2015（ECMAScript 6）を取り上げ、歴史や経緯から追加された機能や文法の詳細など、複数回に渡って解説していきます。</p>

<p>ここではECMAScriptの新仕様を先取りできるトランスパイラ、Babelの紹介を行います。</p>

<h1>Babelとは</h1>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/09/babel1.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/09/babel1-300x168.png" alt="babel" width="300" height="168" class="alignnone size-medium wp-image-17231" srcset="/wp-content/uploads/2015/09/babel1-300x168.png 300w, /wp-content/uploads/2015/09/babel1-207x116.png 207w, /wp-content/uploads/2015/09/babel1.png 551w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p><a href="https://babeljs.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Babel</a>とは、2014/9から開発が始まっているECMAScriptコンパイラです。</p>

<p>機能としては、ECMAScript2015 (ES6)やECMAScript7などで書かれたソースコードを一般的なブラウザがサポートしているECMAScript5の形式に出力することができます。</p>

<p></p><pre class="crayon-plain-tag">const obj = (() =&gt; {
  return {
    method() {
      alert('Hello Babel!');
    }
  };
})();</pre><p></p>

<p></p><pre class="crayon-plain-tag">'use strict';

var obj = (function () {
  return {
    method: function method() {
      alert('Hello Babel!');
    }
  };
})();</pre><p></p>

<p>Babelは最低限の機能を<a href="http://babeljs.io/docs/advanced/caveats/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">IE8</a>以降で、フル機能をIE10以降でサポートします。<br />
（実際にはIE9以降から使用することを推奨します）</p>

<p>当初Babelは6to5と呼ばれていましたが、ECMAScript7の仕様なども取り込むようになったため、バージョンを想定しないBabelという名前に変更されました。</p>

<h1>Babelの特徴</h1>

<p>Babelと同じように「トランスパイルすることでJavaScriptのコードを出力する」ツールにはTypeScriptやCoffeeScriptなどがあります。</p>

<p>それらと比較するとBabelは「ECMAScript標準仕様をベースにしている(*)」という特徴があります。</p>

<p>(*) 実際にはJSXもサポートしているため、必ずしもECMAScript標準仕様のみをサポートしているわけではありません。</p>

<p>このため、「いずれ標準実装される仕様を先取りできる」、「Babel自体が廃れても同じような標準仕様を扱うツールがあれば乗り換えできる」といった利点があります。</p>

<h1>簡単に始める方法</h1>

<p>それでは早速Babelを使ってみましょう。</p>

<p>お手軽に始める場合、Babelの公式サイトで公開されている<a href="https://babeljs.io/repl/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">オンライン上のトランスパイルサービス</a>が便利でしょう。</p>

<p>これは左側にコードを書くとトランスパイルした結果を右側に出力してくれます。</p>

<p>もちろんこのまま開発を行うのは難しいため、実際には手元にツールをインストールして使うことになります。</p>

<h1>Babelのインストール</h1>

<p>Babelはnpm経由で以下のようにインストールします。</p>

<p><code>
$ npm install --global babel
</code></p>

<p>これで<code>babel</code>コマンドが使用できるようになりました。</p>

<h1>CLIを使った変換方法</h1>

<p>それではまずは<code>babel</code>コマンド経由で変換してみましょう。</p>

<p><code>babel</code>コマンドでは以下のようにファイル名を引数に与えるか、標準入力にソースを渡すことによって標準出力へ変換結果を出力します。</p>

<p><code>
$ cat sample.js
() =&gt; {}
$ babel sample.js
"use strict";</p>

<p>(function () {});</p>

<p>$
</code></p>

<p>この方法でも変換はできますが、実際の現場では次で紹介するような別のコマンド経由で変換されることが一般的です。</p>

<h1>gulpを使った変換方法</h1>

<p>では次に<a href="http://gulpjs.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">gulp</a>を使った変換方法を紹介します。</p>

<p>gulpを使って変換するためには、gulpとBabelを繋げるためのgulp-babelというパッケージをインストールします。</p>

<p><code>
$ npm install --global gulp
$ npm install --save-dev gulp-babel
</code></p>

<p>それでは変換してみましょう。</p>

<p>まず<code>gulpfile.js</code>に以下のように記述します。</p>

<p></p><pre class="crayon-plain-tag">var gulp = require('gulp');
var babel = require('gulp-babel');
 
gulp.task('default', function () {
    return gulp.src(['src/*.js', 'src/**/*.js'])
        .pipe(babel())
        .pipe(gulp.dest('dist'));
});</pre><p></p>

<p>この状態で<code>gulp</code>コマンドを実行することで、<code>src/</code>以下のjsファイルをBabelで変換して<code>dist</code>以下に書き出すことができます。</p>

<h1>gruntを使った変換方法</h1>

<p>次は<a href="http://gruntjs.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">grunt</a>を使った変換方法を紹介します。</p>

<p>gruntを使って変換するためには、gulpの場合と同様にgrunt-babelというパッケージをインストールします。</p>

<p><code>
$ npm install --global grunt-cli
$ npm install --save-dev grunt grunt-babel
</code></p>

<p>それでは変換してみましょう。</p>

<p><code>Gruntfile.js</code>に以下のように記述します。</p>

<p></p><pre class="crayon-plain-tag">module.exports = function(grunt) {
  grunt.initConfig({
    babel: {
      dist: {
        files: [{
          "expand": true,
          "cwd": "src/",
          "src": ["*.js", "**/*.js"],
          "dest": "dist/",
          "ext": ".js"
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-babel');

  grunt.registerTask('default', ['babel']);
};</pre><p></p>

<p>この状態で<code>grunt</code>コマンドを実行することで、<code>src/</code>以下のjsファイルをBabelで変換して<code>dist/</code>以下に書き出すことができます。</p>

<h1>Browserifyを使った変換方法</h1>

<p>ここまではタスクランナー経由での使い方を紹介しましたが、最後に<a href="http://browserify.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Browserify</a>経由での変換方法もご紹介します。</p>

<p>Browserifyとは、以下のようにNode.jsで使える外部ライブラリを読み込むrequire構文（CommonJS）をブラウザ上でも使えるように変換するためのツールです。自動的に外部ライブラリの参照先のファイルを結合してひとつのファイルにまとめてくれます。</p>

<p></p><pre class="crayon-plain-tag">module.exports = function () {
  console.log('Hello browserify!');
};</pre><p></p>

<p></p><pre class="crayon-plain-tag">var exportsCode = require('./exports.js');
exportsCode(); // console.log('Hello browserify!');</pre><p></p>

<p>Babelは、同じように外部ライブラリを読み込むECMAScritpt2015 (ES6)のmodule構文を上記のようなrequire構文）に変換してくれますが、ひとつのファイルにまとめてくれる機能はありません。そのため、実際の実行ではエラーになってしまいます。</p>

<p></p><pre class="crayon-plain-tag">export default function () {
  console.log('Hello ES2015 exports!');
};</pre><p></p>

<p></p><pre class="crayon-plain-tag">import exportsCode from './exports.js';
exportsCode(); // console.log('Hello ES2015 exports!');</pre><p></p>

<p>これを解決するには、Babelだけでなく、Browserifyを組み合わせてrequire構文をブラウザでも実行できるようにする必要があります。これらを組み合わせた場合、ES2015のmodule構文で書いたものが、Babelによってrequire構文に変換され、require構文の（ブラウザでの）実行に必要なファイルの結合処理をBrowserifyが行う形となります。</p>

<p>このようにWebフロントエンドの開発の場合、BrowserifyとBabelはセットで使われることが多いです。</p>

<p>BrowserifyとBabelの連携方法は、単純にBabelの出力結果をBrowserifyに渡すだけでなく、Browserifyのもつプラグイン機構でBabelを呼び出すこともできます。</p>

<p>では、Browserify経由でBabelを実行するためのbabelifyというパッケージをインストールします。</p>

<p><code>
$ npm install --global browserify
$ npm install --save-dev babelify
</code></p>

<p>Browserifyはgruntやgulp経由で起動する方法もありますが、以下のようにコマンドラインからでも起動できます。</p>

<p><code>
$ browserify src/app.js -t babelify -o dist/app.js
</code></p>

<p><code>-t</code>でbabelifyを指定することで変換時にBabelを呼び出しています。</p>

<hr />

<p>ここまで変換方法を紹介してきましたが、これ以外にも<a href="https://babeljs.io/docs/setup/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">様々な方法</a>でコードを変換することができます。</p>

<p>他のツールとの親和性はBabelの大きな特徴で、さまざまなツールを使用している状態でもスムーズに導入することができます。</p>

<h1>オプション</h1>

<p>ここまで紹介してきた内容でも最低限Babelでの変換は行えますが、細かい挙動を制御する場合オプションの指定が必要になる場合があります。</p>

<p>Babelには<a href="https://babeljs.io/docs/usage/options/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">さまざまなオプションがあります</a>が、ここではその中から主要なものを取り上げて紹介します。</p>

<ul>
<li>stage</li>
</ul>

<p>BabelはECMAScript2015 (ES6), ECMAScript7をECMAScript5に変換しますが、ECMAScript2015 (ES6), ECMAScript7の仕様でもまだ議論中のものもあり、安定度はまちまちです。</p>

<p>そこで、ECMAScriptの中でもまだ議論しきれていない仕様に関しては、stageという概念を使って安定度を示しています。</p>

<p>Babelはこのstageを指定する機能を備えており、stageを指定することでまだ議論の進んでいない仕様も使うことができます。</p>

<p>各stageでどういった機能が使えるようになるかは、<a href="https://babeljs.io/docs/usage/experimental/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">こちら</a>をご覧ください。</p>

<p>初期値は2が指定されており、草案（Draft）レベルのものが使用できます。</p>

<p>基本的には初期値で構いませんが、どうしても先取りしたい仕様がある場合には仕様が変わってしまうリスクを踏まえた上で、より新しい仕様を使うこともできます。</p>

<ul>
<li>sourceMaps</li>
</ul>

<p>JavaScriptのコンパイラは性質上、元のソースコードと違った形式で出力されるため、実行時に何か問題があった場合にデバッグが困難になるという性質があります。</p>

<p>この問題に関しては標準仕様としてSourceMapという仕様が存在し、モダンブラウザではこの機能をサポートしています。</p>

<p>SourceMapを使うことで変換前のコードと変換後のコードを対応付けることができるため、実行時に問題が発生しても元のソース上でどこに問題があったのかを容易に把握することができます。</p>

<p>BabelのsourceMapsオプションはソースコードと同時にsourceMapファイルを出力することができ、trueを指定した場合変換後のソースとは別にsourceMapファイルを、&#8221;inline&#8221;を指定した場合変換後のソースファイルにsourceMapファイルを埋め込んで出力できます。</p>

<h1>オプションの指定方法</h1>

<p>さまざまなツールと連携できる点が魅力のBabelですが、連携する場合に問題になるのがBabel自体に対するオプションの指定方法です。</p>

<p>連携するツールによってはBabelに対してのオプションを指定する方法を提供している場合もありますが、場合によってはドキュメントに書かれていなかったり提供されていないこともあります。</p>

<p>そこで便利なのが設定を独立して記述できる<a href="https://babeljs.io/docs/usage/babelrc/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">.babelrc</a>ファイルです。</p>

<p>このファイルをBabelを実行するフォルダ（基本的にpackage.jsonと同じ場所）へ設置することで、連携ツール毎のオプション指定の方法を気にすることなく一括でオプションを指定することができます。</p>

<p><code>
$ cat .babelrc
{
  "stage": 1
}
</code></p>

<h1>最後に</h1>

<p>駆け足でしたがここまでBabelの紹介をしてきました。</p>

<p>Babelを使った開発はすでに一般的に行われており、公開されている製品での使用もよく見るものになっています。</p>

<p>皆様もこれまでブラウザがサポートしなければ使えなかったECMAScriptの最新仕様を、自由に使える環境での開発を是非体験してみてください。</p>
]]></content:encoded>
		
		<series:name><![CDATA[ECMAScript 2015（ECMAScript 6）特集]]></series:name>
	</item>
		<item>
		<title>攻撃シナリオを使って解説するApplicationCacheのキャッシュポイズニング</title>
		<link>/kyo_ago/5153/</link>
		<pubDate>Sun, 09 Feb 2014 23:30:37 +0000</pubDate>
		<dc:creator><![CDATA[吾郷 協]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[ApplicationCache]]></category>
		<category><![CDATA[セキュリティ]]></category>

		<guid isPermaLink="false">/?p=5153</guid>
		<description><![CDATA[最近ウィンナーと燻製の自作にはまっています。@kyo_agoです。 この記事は1/28に行われた、第44回HTML5とか勉強会（HTML5とセキュリティ編）で発表した内容を元に書いています。 今回はApplication...]]></description>
				<content:encoded><![CDATA[<p>最近ウィンナーと燻製の自作にはまっています。<a href="https://twitter.com/kyo_ago" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">@kyo_ago</a>です。</p>

<p><em>この記事は1/28に行われた、第44回HTML5とか勉強会（HTML5とセキュリティ編）で発表した内容を元に書いています。</em></p>

<p>今回はApplicationCacheのキャッシュポイズニングに関してお話したいと思います。</p>

<p>最初に用語について説明します。</p>

<h2>ApplicationCache</h2>

<p>ApplicationCacheとは、HTML5の「<a href="http://www.w3.org/TR/offline-webapps/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Offline Web Applications</a>（<a href="http://www.html5.jp/trans/w3c_offline_webapps.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">日本語訳</a>）」内で定義されているクライアントサイドキャッシュの仕様です。</p>

<h2>キャッシュポイズニング</h2>

<p>キャッシュポイズニングとは、キャッシュに対して攻撃コードを送り込み、そのキャッシュ経由で攻撃コードを実行させる攻撃手法です。</p>

<p><a href="https://www.google.co.jp/search?q=%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%83%9D%E3%82%A4%E3%82%BA%E3%83%8B%E3%83%B3%E3%82%B0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Googleで「キャッシュポイズニングを検索」</a>した場合、検索結果の上位はDNSのキャッシュポイズニングに関する内容がほとんどですが、最近はクライアントサイドのキャッシュポイズニングも話題に上がるようになっています。</p>

<p>「クライアントサイドのキャッシュポイズニング」自体はApplicationCacheに限らず発生し得る問題ですが、ここでは特にApplicationCacheを使った場合のキャッシュポイズニングの問題に関して紹介したいと思います。</p>

<h2>Man in the Middle Attack (MitM：中間者攻撃)</h2>

<p>Man in the Middle Attack (MitM)とは攻撃者がターゲット（被害者）とサーバ（コンテンツ提供者）との通信を中継することで、不正な内容に置き換えたり、秘密の情報を盗み見る攻撃です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2014/02/MitM.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/02/MitM-300x256.png" alt="MitM" width="300" height="256" class="alignnone size-medium wp-image-5176" srcset="/wp-content/uploads/2014/02/MitM-300x256.png 300w, /wp-content/uploads/2014/02/MitM-207x177.png 207w, /wp-content/uploads/2014/02/MitM.png 508w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>具体的な攻撃方法は様々ですが、DHCPサーバの妨害、ルータの乗っ取り、無線APの詐称などで行われることがあります。</p>

<h1>どういった問題か</h1>

<p>まず、この問題の概要に関して紹介します。</p>

<p>簡単に言うと「安全でないネットワーク上でApplicationCacheを使用した場合に、攻撃データをApplicationCacheに追加させられると安全なネットワークに移動後も攻撃を受け続ける」という内容です。</p>

<p>これに関しては、OWASPという団体が公開している「<a href="https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Security Cheat Sheet</a>」や、JPCERT/CCが公開している「<a href="http://www.jpcert.or.jp/research/html5.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 を利用したWeb アプリケーションのセキュリティ問題に関する調査報告書</a>」でも、それぞれ以下のように指摘されています。</p>

<div>
<blockquote>
・<a href="https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Offline_Applications" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 Security Cheat Sheet &#8211; OWASP</a><br>
<em>Offline Applications<br>
Whether the user agent requests permission to the user to store data for offline browsing and when this cache is deleted varies from one browser to the next. Cache poisoning is an issue if a user connects through insecure networks, so for privacy reasons it is encouraged to require user input before sending any manifest file.</em>
</blockquote>
</div>

<p><br></p>

<div>
<blockquote>
・<a href="http://www.jpcert.or.jp/research/html5.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTML5 を利用したWeb アプリケーションのセキュリティ問題に関する調査報告書</a><br>
<em>4.2.3. Offline Web Application<br>
オフラインキャッシュを利用すると、長期にわたりユーザのデバイス上に保存されたリソースが使用されることになる。そのため、例えば暗号化されていないWi-Fiのような信頼できないネットワークを利用している端末に対して、攻撃者が中間者攻撃により汚染したリソースをオフラインキャッシュとして保存させた場合、そのネットワークを離れた後も長く汚染されたリソースをユーザが使い続けることになり、結果として、例えば秘密情報が攻撃者のサイトに送信されるなどの被害の可能性も考えられる。そのため、Offline Web Applicationの機能を利用する場合は、当該リソースを持つサイト全体に対してhttpsを利用することが望ましい。</em>
</blockquote>
</div>

<p><br></p>

<h1>攻撃シナリオ</h1>

<p>概要のみだとどういった攻撃手法か理解しづらいため、具体的にどういった攻撃シナリオになるかを紹介します。</p>

<ol>
<li>ターゲットの通信を乗っ取る（MitMを仕掛ける）  </li>
<li>ターゲットがhttpでhtmlを要求したら、取得したhtml内に汚染したいURLをiframe[src]で記述して返す<br />
<a href="https://html5experts.jp/wp-content/uploads/2014/02/iframe.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/02/iframe-300x123.png" alt="iframe" width="300" height="123" class="alignnone size-medium wp-image-5167" srcset="/wp-content/uploads/2014/02/iframe-300x123.png 300w, /wp-content/uploads/2014/02/iframe-207x85.png 207w, /wp-content/uploads/2014/02/iframe.png 319w" sizes="(max-width: 300px) 100vw, 300px" /></a></li>
<li>iframe[src]で指定したURLをブラウザが取得しようとした場合、正規のhtml内に汚染したJSとApplicationCache自体のURLを記述したApplicationCacheを指定する</li>
</ol>

<p>この攻撃のポイントとしては以下の2点です。</p>

<ol>
<li>中間者攻撃（MitM）が前提である<br />
ターゲットが取得しようとしたhtmlを書き換える必要が有るため、中間者攻撃（MitM）が前提となります。</li>
<li>ApplicationCache自体のURLをApplicationCacheに記述する<br />
ApplicationCacheは以下のようにApplicationCacheファイル（.appcache）にApplicationCacheファイル自体のURLを記述すると自動的にキャッシュが消えなくなります。<br />
<a href="https://developer.mozilla.org/ja/docs/Web/HTML/Using_the_application_cache#.E4.BE.8B_1.3A_.E5.8D.98.E7.B4.94.E3.81.AA.E3.82.AD.E3.83.A3.E3.83.83.E3.82.B7.E3.83.A5.E3.83.9E.E3.83.8B.E3.83.95.E3.82.A7.E3.82.B9.E3.83.88.E3.83.95.E3.82.A1.E3.82.A4.E3.83.AB" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">アプリケーションキャッシュの使用 &#8211; HTML | MDN</a></li>
</ol>

<p><code>
    CACHE MANIFEST
    /manifest.appcache
</code></p>

<h1>再度攻撃シナリオを見返す</h1>

<p>ここで再度上で紹介した「攻撃シナリオ」を見てみたいと思いますが、まず最初にターゲットの通信を乗っ取っています。</p>

<p>つまり、この攻撃は「ターゲットの通信を乗っ取る（中間者攻撃（MitM）を行う）」事が前提になっており、この点でCSRFやXSSなどの攻撃手法とは性質が異なります。<br />
（MitMができない場合、この攻撃は成立しない）</p>

<p>また、この攻撃はApplicationCacheを使うことでファイルが消えにくくなりますが、ApplicationCacheを使用しなかったとしても攻撃者がhttp headerを改変してキャッシュを有効にすることで攻撃コードを埋め込んだまま攻撃を継続することができます。</p>

<h1>キャッシュポイズニングにおける本質的な課題</h1>

<p>この記事ではここまで「各種セキュリティ団体が紹介するApplicationCacheのキャッシュポイズニングに関する注意喚起」の内容を紹介してきました。</p>

<p>しかし、著者はこの問題に関して「中間者攻撃（MitM）が必須である」という点で、他の攻撃手法とは性質が異なると考えます。</p>

<p>そもそもWebの世界では「コンテンツ提供者が中間者攻撃（MitM）に対処するにはhttpsしかない」という前提があります。<br />
（MitMが成立した場合、攻撃者はコンテンツ提供者以上の権限を持つためコンテンツ提供者の対処を全て無効化できる）</p>

<p>そのため、「中間者攻撃（MitM）が必須である」場合、コンテンツ提供者がコーディングレベルで対応できることはありません。</p>

<p>また、「ApplicationCacheを使用しなくても同じような攻撃は可能である」点から、ApplicationCache自体の問題とすることにも疑問を感じます。</p>

<p>この問題は簡単に言うと「中間者攻撃（MitM）でキャッシュを汚染させられる」問題であり、ブラウザに外部の実行コード（html、JS等）をキャッシュする機構が備わっている以上避けられない問題だと考えます。</p>

<h1>コンテンツ提供者がとるべき対応策は？</h1>

<p>それではコンテンツ提供者はこの問題に対してどう対処すべきでしょうか。</p>

<p>基本的にコンテンツ提供者はコーディングレベルでこの攻撃方法に対処する方法はないと考えます。</p>

<p>何らかの対処コードを作成できたとしても、中間者攻撃（MitM）が成立している時点で、攻撃者は対処コードを除外した形でキャッシュを汚染することが可能です。</p>

<p>そもそもこの問題はApplicationCacheの問題ではなく、中間者攻撃（MitM）の問題のためサイト全体をhttpsにする以外、根本的な対応方法はありません。</p>

<h1>結論</h1>

<p>現時点での著者の結論をまとめます。</p>

<p>「ApplicationCacheのキャッシュポイズニング」に関して言うと、「コンテンツ提供者がApplicationCacheを使っている」ことで新しい脅威が増えるということはありません。<br />
（攻撃者はコンテンツ提供者がApplicationCacheを使っているかどうかに関わらず、ApplicationCacheの機能を有効化して汚染できる）</p>

<p>中間者攻撃（MitM）に対しての対応は、これまでどおりサイトをhttps化することが有効になります。</p>

<p>利用者としては汚染が懸念されるネットワークの利用はできるだけ避けて、もし使用せざるを得ない場合ブラウザをシークレットモードで使用し、「サイトがhttpsで通信しているか」も確認した上で使用しましょう。</p>
]]></content:encoded>
			</item>
		<item>
		<title>モバイル対応Webアプリケーションのキャッシュ戦略</title>
		<link>/kyo_ago/2466/</link>
		<pubDate>Tue, 24 Sep 2013 00:00:40 +0000</pubDate>
		<dc:creator><![CDATA[吾郷 協]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Application Cache]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Webアプリケーション]]></category>
		<category><![CDATA[オフラインファースト]]></category>
		<category><![CDATA[高速化]]></category>

		<guid isPermaLink="false">/?p=2466</guid>
		<description><![CDATA[近年、モバイルブラウザ上でアプリケーションを作るにあたり、JavaScriptでも不安定な回線上で動作する設計が求められるようになってきました。 ここでは、「オフラインファースト」をはじめとする、モバイルなどの回線が不安...]]></description>
				<content:encoded><![CDATA[<p><a href="https://html5experts.jp/wp-content/uploads/2013/09/dtl_thm_017.png" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2013/09/dtl_thm_017.png" alt="dtl_thm_017" width="207" height="156" class="alignright size-full wp-image-2593" /></a>
近年、モバイルブラウザ上でアプリケーションを作るにあたり、JavaScriptでも不安定な回線上で動作する設計が求められるようになってきました。</p>

<p>ここでは、「オフラインファースト」をはじめとする、モバイルなどの回線が不安定な状況を想定したWebアプリケーション設計に関して、キャッシュ方法やよく使われるAPIなどを紹介したいと思います。</p>

<p><span id="more-2466"></span></p>

<p>「オフラインファースト」とは2012年ごろから提唱されていた、「回線がオフラインになることを前提にアプリケーションの設計を行う思想」のことで、オフライン前提に設計することにより回線状況によらないサービス提供や、効率的な通信をベースにした高速な動作を目指すものです。</p>

<p>それではここからはキャッシュ方法とそれぞれ向いているコンテンツの紹介を行います。</p>

<h1>読み込みデータのキャッシュ</h1>

<p>ApplicationCacheやlocalStorage、オンメモリキャッシュなどを使って、「サーバから取得したデータをローカルに保持する」ものです。</p>

<p>これは一般に「クライアントサイドキャッシュ」と呼ばれるもので、ネットワークがオンラインの時に読み込んだデータをオフライン時に使用します。</p>

<p>サーバと連動しないコンテンツに向いており、実際のコンテンツ以外でもテンプレートファイルなどの「動的なコンテンツの静的な部分」にも使用されます。</p>

<h1>読み込みデータのマージ</h1>

<p>これは「読み込みデータのキャッシュ」と大きくは変わりませんが、「読み込みデータのキャッシュ」がオンラインになった際に毎回キャッシュを読みなおすのに比べて、「読み込みデータのマージ」はオンラインになった際にサーバ上で更新があった内容のみダウンロードを行います。</p>

<p>更新があった内容のみダウンロードを行うため、帯域の使用量が少なくなる利点がありますが、サーバとクライアントでデータの更新タイミングを管理する必要があるため、「読み込みキャッシュ」に比べて実装が複雑になります。</p>

<p>「多数の画像ファイルの内、更新があったもののみを再取得する」など、やりとりするデータ量が多いコンテンツに使用されます。</p>

<h1>書き込みデータのキャッシュ</h1>

<p>書き込み時に回線状況を確認して、オフラインの場合オンラインになるまでデータの送信を遅延させる方法です。</p>

<p>また、オフラインだった時だけではなく、サーバへの通信に失敗した場合、常にデータを再送する形で実装されることもあります。</p>

<p>実装方法としては独自に定義した通信用のコードを使用するほかに、XMLHttpRequestを乗っ取る方法や、使用しているライブラリ（jQuery）などのajaxメソッドをラッピングする方法などがあります。</p>

<p>「投稿」や「保存」などのサーバへの更新処理に使われますが、ゲーム等のタイミングが重要な通信や、「購入」等のサーバ側との連動が、重要な通信では使用されません。</p>

<h1>書き込みデータのマージ</h1>

<p>これは「読み込みデータのマージ」に書き込みが行われることを想定されたものですが、「書き込みの時系列を保持するか」、「同じデータを同時に編集していた場合にどう整合性を保つか」等によって実装難易度は大きく変わります。<br />
（時系列を保持せず、同時編集時は常に最後の修正が反映されれば良い場合、書き込みデータのキャッシュ実装と大きな差はありません）</p>

<p>これに関してはサーバ側の実装も大きく関わってくるためクライアント側だけで設計するのは難しいですが、もしクライアント側だけで実装したい場合には<a href="https://developers.google.com/drive/realtime/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Google Drive Realtime API</a>などの外部サービスの使用も検討してみてください。</p>

<h1>オフライン動作</h1>

<p>これは単純なデータのキャッシュではなく「ブラウザがオフラインの状態でも動作させる」方法になります。</p>

<p>現状、ブラウザ上でオフライン時にコンテンツを提供するには、基本的にApplicationCacheを使用します。</p>

<p>サーバ側の処理が重要な場合オフライン動作の必要性は高くありませんが、クライアントサイドで完結する要素が多いモバイル向けのツールやアプリケーションなどでは必要性が高くなります。</p>

<p>ここからは実際にキャッシュを実装する際によく使用される機能について紹介します。</p>

<h2>Web Storage（localStorage、sessionStorage）</h2>

<p>IE8以降の主要なブラウザで使用できる同期型の保存領域です。</p>

<p>多くのブラウザは5MB程度のデータを保持することが可能です。</p>

<p>実装も容易なためよく使われますが、同期型で実装されているためパフォーマンス的な問題も指摘されています。</p>

<p><a href="https://dev.mozilla.jp/2012/03/there-is-no-simple-solution-for-local-storage/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ローカルストレージに簡単な解決策はない | Mozilla Developer Street (modest)</a>では具体的な問題点や代替案が書かれています。</p>

<h2>Cookie</h2>

<p>古くから実装されており、サポートブラウザも広いことから、長い間クライアントキャッシュの保存領域としても使用されてきました。</p>

<p>ただ、Cookieに保存した内容はサーバへも送信されてしまうことから、Cookieをキャッシュとして使用する場合、以後の通信すべてで不要なデータをサーバに送ることになるため、大きなデータをキャッシュすることには向いていません。</p>

<h2>location.hash</h2>

<p>URLの # 以降に文字列を設定し、クライアントキャッシュとして使用する方法です。</p>

<p>サーバサイドへも送信されず、古いブラウザでも動作可能ですが、「ブラウザの履歴に残る」、「URLを共有した際にキャッシュも共有される」、「ブックマーク等にキャッシュも保存される」、「#を使った画面遷移時にキャッシュが破棄される」といった問題があるため、キャッシュとして使用する場合は注意が必要です。</p>

<h2>ブラウザキャッシュ</h2>

<p>JavaScriptから直接操作するAPIは提供されていませんが、ブラウザキャッシュもクライアントサイドでは重要なキャッシュになります。</p>

<p>具体的には「非表示のimg要素を作成し、img.srcへ画像のURLを設定して先読みさせる」、「見えないiframeで次に読み込むページを先読みする」といった方法で使用されます。</p>

<h2>Web SQL Database</h2>

<p>ブラウザ内に内蔵されたSQLiteに対して、JavaScriptからAPI経由でSQLを発行することでデータの保存、取得を行うのが<a href="http://www.w3.org/TR/webdatabase/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web SQL Database API</a>です。</p>

<p>もともとWebKit系のブラウザで実装されており、W3Cでも標準仕様として提案されていましたが、SQLiteへの依存などの問題によりW3C上では廃案になりました。<br />
（<a href="http://javascript.g.hatena.ne.jp/edvakf/20091102/1257139731" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ブラウザ上のデータベースに関して &#8211; JavaScriptで遊ぶよ &#8211; g:javascript</a>では廃案になった経緯等がまとめられています）</p>

<p>ただ、<a href="http://caniuse.com/sql-storage" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">モバイル環境では使える環境が多い</a>ため、モバイル環境に限ったウェブアプリケーションなどでは使用されることもあります。</p>

<h2>Indexed Database（Indexed DB）</h2>

<p>標準仕様としての策定が中止されたWeb SQL Databaseに代わり登場したクライアントサイドDBです。</p>

<p>Web SQL DatabaseがあくまでもSQLiteの仕様に準拠しているのに比べて、Indexed DatabaseはJavaScriptからの使用に特化しておりシンプルなObjectやFile objectなどをそのまま格納できます。</p>

<p>Chrome、Firefox、IE10でサポートされるなど、<a href="http://caniuse.com/indexeddb" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">デスクトップブラウザではサポートが広まっています</a>が、Mobile Safari、Android標準ブラウザでのサポートが行われていないためモバイル環境での使用は広まっていません。</p>

<h2>Filesystem API</h2>

<p>ブラウザ上にディレクトリなどのFilesystemを操作するAPIを提供するのが、Filesystem APIです。</p>

<p>DOMFileSystem  objectやDirectoryEntry objectなどを使って、File objectを階層構造で管理することができます。</p>

<p>このAPIはinput[type=&#8221;file&#8221;]やD&amp;Dで渡されたファイルを処理する際に使用する「File API」とは違うAPIであることに注意してください。<br />
（Filesystem APIでも単一のファイルを操作する際はFile APIで提供される機能を使用しますが、File APIはあくまでもFilesystem APIから独立した仕様です）</p>

<p>主にChromeで実装されていますが、<a href="http://caniuse.com/filesystem" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Chrome以外のブラウザでは実装が進んでいない</a>ため、一般的なウェブ環境ではあまり使用されていません。</p>

<p><a href="https://dev.mozilla.jp/2012/07/why-no-filesystem-api-in-firefox/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox に FileSystem API が無いのはなぜか？ | Mozilla Developer Street (modest)</a>ではMozillaのFileSystem APIに対するスタンスが書かれています。</p>

<h2>ApplicationCache</h2>

<p>ApplicationCacheはcache manifestと呼ばれるキャッシュ対象のURLを記述したテキストファイルをhtmlから参照することで、記述されているURLの内容をローカルキャッシュとして使用する仕様です。</p>

<p>ApplicationCacheには以下の様な機能が含まれます。</p>

<ul>
<li>ブラウザがオフラインでも、事前にキャッシュした内容を表示する</li>
<li>ネットワーク通信なしに、cache manifestに書かれたURLのファイルにアクセスする</li>
<li>ブラウザがオフライン時のみ、代替内容を表示する</li>
<li>JavaScriptからキャッシュの取得、更新イベントを受け取る</li>
</ul>

<p>現在、ブラウザがオフライン時でもコンテンツを提供する場合ApplicationCacheが主に使用されますが、ApplicationCacheは「設計に失敗したAPI」と呼ばれるほど使い勝手が悪く、さまざまな問題を抱えています。</p>

<h1>ApplicationCacheの問題点</h1>

<p>ApplicationCacheに関しての紹介で「さまざまな問題を抱えています」と書きましたが、ここではそのうちの主なものについていくつか紹介したいと思います。</p>

<h2>読み込み元htmlがキャッシュされる</h2>

<p>ApplicationCacheを使用する場合、仕様上ApplicationCacheを使用しているhtmlもキャッシュされてしまうため、動的なコンテンツを出力してもすぐに反映されません。</p>

<p>そのため、ApplicationCacheを使用する場合は基本的に1枚の静的なhtmlを用意し、動的な部分はすべてJavaScriptを使用して構築することになります。</p>

<p>これはWebサイト構築の当初から想定している場合は問題ありませんが、サーバサイドで動的にコンテンツを生成している既存のWebサイトに対して、あとからApplicationCacheを導入する場合には大きな障害になります。</p>

<h2>キャッシュのクリアが困難</h2>

<p>ブラウザによってはApplicationCacheをクリアするUIを提供していないものもあり、開発中も含めて一度キャッシュされたApplicationCacheをクリアするのが困難な場合があります。</p>

<p>特にiOSの場合、アプリが独自に使用しているUIWebViewのApplicationCacheをクリアするには、アプリを削除して入れなおす以外の方法がありません。<br />
（アプリが独自のUIを提供している場合を除く）</p>

<h2>JavaScriptからキャッシュを操作することができない</h2>

<p>JavaScriptからApplicationCacheに関しては「キャッシュ状態の確認」、「サーバ上のデータ確認」、「キャッシュの破棄」を行うことができます。</p>

<p>ただし、キャッシュ操作は全キャッシュに対しての操作のみで、個別のファイルに対しての操作は提供されていません。</p>

<p>そのため、「高速化のために出来るだけキャッシュするファイルを多くしたいが、キャッシュするファイルが多いとキャッシュの更新に時間がかかる」という状況になります。</p>

<p>キャッシュの更新は自動的に行われるため基本的にブラウザ側で操作を行う必要はありませんが、逆に「一部のキャッシュのみ更新したい」、「更新順に優先度を付けたい」、「指定したキャッシュが更新されたらJavaScriptからアクセスしたい」と言った内容は実現できません。</p>

<h1>それでも使われるApplicationCache</h1>

<p>問題点の多いApplicationCacheですが、現状ブラウザがオフライン時にコンテンツを提供するためにはもっとも現実的な方法であるため、問題点があることを前提で使用されている状況です。</p>

<p>もしApplicationCacheを導入する場合、以下の点に注意してください。</p>

<h2>最初に導入するか決断する</h2>

<p>ApplicationCacheは仕様的にシングルページアプリケーション（1枚のhtmlをベースにJavaScriptでコンテンツを構築する形式）を想定しており、サーバサイドで毎回htmlを組み立てて出力する形式は想定されていません。</p>

<p>サーバサイドで毎回htmlを組み立てて出力するコンテンツの場合でもiframeを経由するなどして活用することは可能です。しかし、iframe内のApplicationCacheに対する状態管理とiframeと、本体間のキャッシュデータをやりとりするコードが必要になるため、実装は複雑になります。</p>

<h2>最悪の事態を想定する</h2>

<p>ApplicationCacheは使い方によっては完全にサーバから独立して動く事が可能ですが、場合によってはサーバからの変更を一切受け付けなくなってしまう状態に陥る場合があります。</p>

<p>もしサイト上でApplicationCacheを使用する場合、常にネットワーク上からダウンロードするJavaScriptを読み込ませておき、最悪の場合でもJavaScriptからリダイレクトの指示を出せるようにしておくことをおすすめします。</p>

<hr />

<p>ここまでキャッシュの設計やAPIに関して紹介してきましたが、ユーザから見た場合キャッシュとは「最良の通信やパフォーマンスが提供されない場合の代替手段」であり、本来存在しないことが求められる技術でもあります。</p>

<p>そのため、もしキャッシュを使用する場合、「ユーザの意図に反した動作にならないか」、「最良の状態でないことをユーザが理解できるか」といったことを意識して使用してください。</p>
]]></content:encoded>
			</item>
	</channel>
</rss>
