投稿者「admin」のアーカイブ

2段階認証の誤解

不正引き出しとは

金融機関にある取引口座とチャージ対象(キャッシュレス手段等)の持ち主(管理者)が異なり、取引口座の資金が無断で移動させられること

今回だと例えば、

キャッシュレス手段取引口座備考
D払い(他人)ゆうちょ(自分)ドコモ口座
LINEペイ(他人)ゆうちょ(自分)

#上の表の「他人」と「自分」が逆になると、攻撃者そのものか、犯罪に巻き込まれているか、になるだろう

①2段階認証はひとつでよい、という誤解

2段階認証(2要素認証ともいう)は英語では2-factor-authenticationとなるが、3-factorや4-factorの方が突破されにくい。ドアについている鍵の数が1つより2つ、2つより3つの方が開けにくいのと同じ。

ちなみに、昔NYではドアに数個鍵を掛けると言われ映画やドラマでもそのような場面が出てくるが、「8つ鍵を付けると狙われない」としていたと記憶する。(そりゃそうだろう)

2段階認証として設定できるのは、(口座番号や暗証番号は当然のこととして、)他にはだいたい

  • ワンタイムパスワード
  • 第2暗証
  • 生体認証
  • 合言葉
  • マイナンバー

位だが、どれも抜け穴がある。

#最悪、例えば家族なら全て突破できる場合がありえる。一卵性双生児なら生体認証も??

②xx銀行、xxペイ、xxサービスのどれかひとつで2段階認証を導入しているから安心、という誤解

ゆうちょとLINEペイを例にすると、

  • ゆうちょは2段階認証していない
  • LINEペイは2段階認証は(オプション)。住所や名前などは実在のものでなくともOK

なので、他人のLINEペイから2段階認証していないゆうちょ口座への紐づけが可能になっている。ゆうちょで2段階認証等の対策がとられていれば、かなり防げるものだが、それがない

③攻撃者の前提は把握可能という誤解

普通はこうするだろう、と攻撃者の動きを想像すると、痛い目を見る。被害者が気づくまで、普通では考えられないことをやっているはず。

また、不正被害が世の中に知られたので、無くなるのも時間の問題だろう、とはいかない。被害が気づかないところでは口座の資金が枯渇(または借り入れ額が上限に達する)迄続く。

どこに気を付ければいいか?

預金口座をもつ金融系(銀行、ゆうちょ)が紐付けサービスを始めたら、リスクがある。口座の取引に異常がないか確認する。メールが来るものならこまめにチェックする。

金融機関からキャッシュレスサービスとの連携を開始する通知があるか。封書でもハガキでもメールでもいいので。契約者全員にアナウンスがあるか。

また、取引口座の取引を逐一メールやハガキで通知するシステムになっているか。これが徹底されていれば、口座を確認するためATMや金融機関にわざわざ出向く手間が省ける。

LINEペイの銀行口座登録の例(2020年9月時点)

登録方法例(LINEペイ)

  • 1口座番号・PWなどの情報を
  • 2銀行選択して必要な情報を入力
  • 3銀行のWebサイトで必要な情報を入力

(例)2020年9月時点のLINEペイの銀行口座登録

金融機関口座登録のため準備するもの(口座情報は省略)備考
ゆうちょなし
三菱UFJ(MUFG)ワンタイムパスワード(OTP)OTPはアプリも可能
三井住友(SMBC)ワンタイムパスワード(OTP)OTPはアプリも可能
みずほ銀行メアド(普通預金口座)合言葉、第2暗証番号(みずほダイレクト)偽サイトで入力、もしくは口座情報を売られていないか
楽天銀行ワンタイムキー
ジャパンネット銀行トークン(OTP)
住信SBIネット銀行アプリ(スマート認証)(SMS認証)生体認証、登録電話番号が変更できなければOK
その他省略
LINEペイの銀行口座登録

それぞれの対応を比較すれば、その脆弱性は一目で分かる。一方にあって他にない認証情報の存在理由を検討していれば済むこと。

例えば、引き出し金額上限が最初1円などになっていて、窓口でしかその上限額が引き上げられないなど、コストのかかるものがないと、上記のような認証情報の差は説明できないはず。

ゆうちょの登録

ゆうちょには2段階認証がない。報道ではキャッシュレス業者に2段階認証の導入をお願いしているらしいが、ゆうちょ側にも必須だ。取引に関するものなら、キャッシュレスへのチャージを含めゆうちょ側でも2段階認証が必要。

どこにも2段階認証は出てこない

(口座契約者と同一かの意味で)本当に本人のキャッシュレスアカウントから取引口座への登録要請がきているのか、どうやって確認するのだろう。金融機関の知らないところで認証されたものを、自分で確認しないでどうやって認証するのだろう。

ドコモ口座とdアカウント

ドコモ口座もdアカウント経由で銀行口座と紐づけるが、dアカウント自体には2段階認証が導入されている(必須でないようだが)。ただし、そのことと銀行口座登録時に銀行側に2段階認証がなくていいとは決してならない。紐づけようとしているdアカウント(ドコモ口座)が銀行口座の本人のアカウントとはかぎらないから、dアカウントの方が2段階認証で守られていても全く意味がない。守るべきは銀行口座の方である。

キャッシュレス業者の個人認証は金融機関の個人認証に比べ極端に脆弱だ。プリペイド式で認証が不要だったり、セキュリティの厳しいクレジットカードと紐づけることでチャージ機能を付与してきた。銀行のように免許証を送付したり窓口で手続きということもない。逆に銀行口座へアクセスできることで個人認証の論拠となっている場合もある(Auペイなど)。

まとめ

取引をメールで知らせない金融機関はあぶない。金融機関が損する訳ではないが、口座の契約者が被害が認識できない可能性がある。連携先がメールするからOKで、はない(連携先の登録メールアドレスと金融機関の登録メールアドレスが違っている場合、確認できない)

金融機関が、キャッシュレスなど他の決済サービスと連携している時点であぶない。簡単に連携できるほどあぶない。連携が面倒なほど危険度は減る。

取り扱い額(引き出し金額)の上限を設定できないところはあぶない。特に契約時に「上限なし」など論外(通常は100万円や49万円などが設定されている)。

主たる金融機関が、不正引き出しがないか確認してくれと、口座契約者に依頼しているが、不正かどうかに関係なく、自宅宛てもしくは登録メールアドレス宛てに、取引があったことを通知すべきだ。

認証の厳しい金融機関とあまあまのサービス業者の連携では、常に認証の厳しい金融機関が取引口座を守る対策を取るべきだ。

【コードサンプル】プロセスモニタのScript例

プロセスモニタのScript例

hh30_monitor_process_ME.ps1

  • モニタの場合比較的短い周期(5分や10分)でScriptタスクを起動する必要があるので、メインの処理は hh99_xxxに置いて、修正時のインパクトが少なくなるようにしている
#$scriptName = $myInvocation.MyCommand.name
#************************************************************************************
# 定数定義
#************************************************************************************
Set-Variable -Name 'trigCommand' -Value <IFTTTのEventName>
#************************************************************************************
# メイン処理
#************************************************************************************
.\hh99_monitor_process.ps1 hh99_monitor_process_ME.ps1 mediaespresso PC_A

hh99_monitor_process.ps1

  • ファイルに保存しておいた前回モニタ時のCPU時間を取得して、現在のCPU時間を比較する。差が2秒以内なら「停止状態」としている
#
# プロセスが起動していてCPUを消費しているか監視(モニタ)する
#
#************************************************************************************
# パラメータ定義
#************************************************************************************
Param(
    [parameter(Mandatory=$True)][string]$ScriptName,
    [parameter(Mandatory=$True)][string]$ProcessName,
    [parameter(Mandatory=$True)][string]$MachineName
)
#************************************************************************************
# 定数定義
#************************************************************************************
if ((Get-Variable  -ErrorAction silentlyContinue -Name 'trigCommand' | Measure-Object).count -eq 0){
Set-Variable -Name 'trigCommand' -Value <IFTTTのEventName>
}
#************************************************************************************
# 関数定義
#************************************************************************************
#************************************************************************************
# メイン処理
#************************************************************************************
$vFile =$ScriptName.Replace(".ps1",".txt")
echo "$vFile at $(Get-Date -Format G)"

$cnt = (get-process -ErrorAction SilentlyContinue $ProcessName | Measure-Object).count

if($cnt -eq 0){
# プロセスが見つからない
    $now = Get-Date
    echo "プロセスが起動していません at $now"
    exit
}
#echo ProcessName &"(" & pID &")"

Get-Content $vFile | Foreach-Object{
   $var = $_.Split('=')
   Set-Variable -Name $var[0] -Value $var[1]
}

echo "CPU:$cpu"

$cpuAfter = 0
((Get-Process -ErrorAction SilentlyContinue $ProcessName).CPU | ForEach-Object { $cpuAfter = $cpuAfter + $_})
$cpuAfter = [int]$cpuAfter

echo "CPUAFTER:$cpuAfter"

# フラグファイルを生成するだけにする(IFFFへMAKERイベント発火)
if ($cpu -gt $cpuAfter){ # 初期化する
    echo "CPU=$cpuAfter" | Out-File -FilePath $vFile
}else{
    if ($cpu -gt ($cpuAfter - 2)){ # 誤差があるので2とした
        .\hh99_IFTTT_trig.ps1 $trigCommand "アイドル状態($MachineName)"
    }else{
        echo "CPU=$cpuAfter" | Out-File -FilePath $vFile
    }
    echo "CPU=$cpuAfter" | Out-File -FilePath $vFile
}

流行りのフレームワークで作りました!「暗記の井戸クラウド」をβリリース

Javascript(jQuery)のMVCフレームワークというのか、いわゆるBackbone.jsと、アプリケーションサーバが不要なCakePHPを組み合わせた「暗記の井戸クラウド」をβリリースします。

スマホ版
タブレット版
PC版

※上記URLの最初にある「krapsiup」は、「quizpark」から来ています。お気づきになられた方もいらっしゃるかと思いますが、「park」を並べ替えると「krap」に、「quiz」を鏡面でみる(裏から眺める?)と「siup」になります

暗記の井戸シリーズの中でコード量が圧倒的に少なくなったにも関わらず、結構いろいろ拡張できそうな予感もあり、面白いと感じています。

とりあえずは、本サイトで紹介している「暗記データ例」を、PCでもスマホでも同じデータをいつでもどこでも参照できるようにしました。例えオフラインになっても最後にアクセスしたデータが残ってますので、気合を入れて暗記に集中できます。

画面は3種類あります

BOX画面、LIST画面、QUIZ画面の3種類。他に各種設定や編集画面がありますが、主なものは左記の3つです。

  • [BOX画面]メールボックスのリストような画面で、クイズ(問題)の集まりのリストです。
  • [LIST画面]メールボックスのような画面で、クイズ(問題)の集まりです。
  • [QUIZ画面]メッセージのような画面で、、クイズ(問題)の詳細です。画面の上半分にクイズ(問題)、下半分にアンサー(解答)、がそれぞれ表示されます

タイムトライアル機能を入れました

タイムトライアル機能?を入れてみました。画面の上半分をタッチ(もしくはクリック)すると機能をON/OFFできます。
※タイムトライアルの時間を変更できます。「BOX画面」下の「Settings」から「TimeTrialInterval」の数字を変更します。単位は秒数です(初期値は10)

「QUIZ画面」の前後移動は画面のタッチで

「QUIZ画面」の下半分の左側をタッチするとひとつ前の問題の「QUIZ画面」に移動します。右半分をタッチするとひとつ後の問題の「QUIZ画面」に移動します

※前後への移動でなく任意の問題の「QUIZ画面」に移動したい場合には、一旦LIST画面に戻ってから問題を選択します

関連する記事・ページ

暗記データ例 | 暗記の井戸HTML5
あなた方は神です!?古いCakePHPの導入で先人の知恵を拝借

お世話になったリンク

[CakePHP] JSON出力時にstring型をint型に戻す | XPages、ロータスノーツ・ドミノのモバイル・WEBアプリの開発・相談ならKTrick LLC.
AJAX ? CakePHP Cookbook v1.3 documentation
CakePHPでビューやレイアウトを使わない方法。 | Wataame Frog
Cakephp 1.3系でBackbone.jsの生成したjsonを受け取る。 – Qiita [キータ]

以上です。

あなた方は神です!?古いCakePHPの導入で先人の知恵を拝借

現在開発中のシステムではDBアクセスにCakephpを使っています。最新版で開発したものを、レンタルサーバの環境に合わせて調整する必要があり、その際に苦労したことを書いてみたいと思います。個人と組織。そのいづれがその能力を発揮できるのか。システム開発で参考になるネットの情報は個人から発信された情報が殆どだと思います。この記事がその一助になればと思います。

「Cakephp」とは

「Cakephp」とは、小・中規模WEBアプリケーションでは大きなシェアを占めるPHPのフレームワークのひとつです。サーバ(DBへのアクセスが主体)とのアクセスモジュールとしてみると、生PHPで書くのとは格段に違う生産性と読み易さが得られますし、単体でもMVCが構築できる秀逸なオープンソースです。

現在利用している「HostGator」などの格安レンタルサーバでもPHPがデフォルトで導入されています。今ご覧になっている本ブログのCMSであるWordPress自体がまさにPHPで書かれていて、MySQL仕様のDBともPHPでアクセスします。

生のPHPで書くシステムを企業やら行政やら金融やらで使えるようにする場合、コード量は現在の10倍以上になるでしょう。いろいろなケースに想定しないといけないからです。生PHPで簡単に書いたコードは「裸でジャングルに入るようなもの」なんでしょうね。

それに比べるとCakephpなどのフレームワークでは、「裸で」に比べるとかなり改善されるようです。いろいろ例外的な状況への対処が簡単な仕組みにカプセル化されているとのこと。すばらしいですね。これまで一生懸命条件分岐のコードを書いていたのは「何だったんだろう!あの時間を返してくれ!」と思わせるものがあります。

こうしてみるとメリットばかりのように見えますが、そうでもありません。学習のためのコストが掛かったりします。そしてもうひとつ重要なのがレンタルサーバなど自分で自由に環境構築できない場所での扱いです。例えば「HostGator」の場合PHPの版数がちょっと古いんです。古いのは安定につながるのでそれはそれで仕方ありませんが、こうした新しいものを取り入れるときにちょっとした障壁になりえます。

「HostGator」でCakePHP2.xxが使えない

「HostGator」がサポートするPHPの現在の版数は5.2.17です。CakePHP2.xxのサポート版数より低いです。フレームワークによってはベースとなるシステムの版数が低くても使えるものが多いんですけどね。CakePHPは違いました。受け付けてくれません

で、結局開発につかったCakePHP2.xxではなくCakePHP1.xxを導入せざるを得なくなりました。それでもJavaサーブレットやStrutsに比べるとかなりましです。Tomcat6などのアプリケーションサーバ環境自体を用意する必要がないからです。

格安レンタルサーバでアプリケーションサーバ環境をデフォルトで用意してくれるところはあるのでしょうかね。

新しい版から古い版へのフレームワークのマイグレーションは大変?

古い版のものには、リリースされて時間が経つ分皆が使っているので、情報が揃っています。ただ、新しい版のものでできたことを古い版でやろうとするとちょっとハードルが高いです。

もちろん、いきなりレンタルサーバにUPLOADしてコードをいじることはありません。まずはローカルな環境で古いCakePHP1.xxを入れて、それから本番環境にマイグレーションします。

ただし、ローカルに構築したそうした環境で動作するからといってレンタルサーバにそれをそのままコピペしても同じように動くとは限りません。逆に「まったく同じに動くことはないのだ」と思ったほうが幸せになれます

日本語のシステムなら「database.php」の「utf8」設定を有効に

これも「まったく同じに動くことはないのだ」のひとつですが、「database.php」の「utf8」設定を、ローカルでは外して動作していました。このときの「動作していました」の意味はキチンと日本語が見れましたの意味です。レンタルサーバでは日本語がみな「????????」と表記されるのです。まず、DBの中身をいろいろ調べ、次にローカルとの間でコードの違いを調べました。これに数時間も費やして、結局「utf8」を陽に設定すれば即解決しました。

JSON用のserialize機能がCakePHP1.xxにはない!

開発中のシステムは、CakePHPが動くサーバとAjaxで通信するAjaxアプリケーションから構成されます。こうした場合情報のやりとりにはJSONを使うのが定石のようですので、CakePHP2.xxでもそうした実装をしていました。たった2行書くだけでJSONをserialize出力できる便利な機能があるんですね。

ところがこの機能がCakePHP1.xxにはありません。当然ローカル環境でも遭遇しました。そこで、「お世話になったリンク」にもあるように、(CakePHP2.xxでは必要なかった)Viewの定義と、デフォルトLayoutsをバイパスしてあげることの2点で問題が解決しました。

Controller内でArray_map関数を使うとエラーになってしまう

次に、CakePHPのController定義で、レスポンスオブジェクトにある余計な情報を削除するため、Array_map関数をつかったところ、レンタルサーバでエラーになりました。ローカル環境では全く問題なかったのに。不思議です。

function index(){

    $this->layout = "";
    $shares = $this->Share->find('all');
    $shares = array_map(funtion($e){
        return $e['Share'];
    },$shares);
    $this->set('datas', $shares);
}

結局、次のように無名関数の定義を止めたら通りました。

function index(){

    function res($e){return $e['Share'];}// only Hostgator does this way!!!

    $this->layout = "";
    $shares = $this->Share->find('all');
    $shares = array_map("res",$shares);
    $this->set('datas', $shares);
}

極めつけはこれ。こんな情報どこにもなかった。あなたは神です

以上はCakePHPがDBにアクセスして一覧を出力するところに関連する部分になります。

ここからは通信方向が逆でAjaxアプリからCakePHPへのXmlHttpRequstのPUTリクエストに関するものです。POSTでも同じ方向のやりとりが発生します。URL情報と並行してテキストやストリームなどの情報が渡されます。

CakePHPのController定義内でこの情報にアクセスするには「this.requst」というオブジェクトを使います。でも下記リンクにもあるようにこれがあろうことか「null(空の意味)」になってしまいお手上げ状態です。いろいろ調べても本来渡されてくるべき情報がないので途方にくれていたところ、本当に凄い裏技を発見、というか、凄い裏技を発見した方がいました。こんな発見必要ないひとには本当に何でもないことですが、開発している最中にこれに出会ったときには「神がいらした」と感動しました。

Cakephp 1.3系でBackbone.jsの生成したjsonを受け取る。 – Qiita [キータ]

$this->data = json_decode(file_get_contents('php://input'));

こんなコードどうやって調べたんだろう!

結構複雑でわかりにくい話ですみません

関連する記事・ページ

お世話になったリンク

[CakePHP] JSON出力時にstring型をint型に戻す | XPages、ロータスノーツ・ドミノのモバイル・WEBアプリの開発・相談ならKTrick LLC.
AJAX ? CakePHP Cookbook v1.3 documentation
CakePHPでビューやレイアウトを使わない方法。 | Wataame Frog
Cakephp 1.3系でBackbone.jsの生成したjsonを受け取る。 – Qiita [キータ]

以上です。

不可解過ぎます!WebViewのHTML5アプリケーションキャッシュ

AndroidアプリからWEBアプリを操作するハイブリッドアプリを開発リリースしています。その際に用いたWebViewという機能。PC版Javaにも同様のものがあり非常に便利そうに見えるのですが、WebViewが提供するHTML5アプリケーションキャッシュに不可解なことが多くて困っています。

「アプリケーションキャッシュ」とは

「アプリケーションキャッシュ」とは、HTML5で導入されたもので、ネットワークへの接続があってもなくても、scriptやら画像データやらHTMLやら、本体のHTMLから参照される全ての外部ファイルを、そのアプリ専用のキャッシュから読み込んでくれるというもの。極論すればネイティブのアプリケーションのように動作しているように見えるというもの(多少遅いけど)。

この機能は非常に便利で、一度キャッシュされると、ちょっと厳格すぎるように見える手続きを陽に踏まない限り、テコでもキャッシュを更新してくれない位強力なものです。SafariやChromeブラウザでの経験しかありませんが、普通のいわゆるキャッシュとは全然違うようです。

キャッシュとアプリケーションキャッシュの違い

ネットを探してみると、膨大な情報がありますが、なんとなく「キャッシュ」と「アプリケーションキャッシュ」を同じものとして扱っている記事が多い感じです。名前が似ているので当たり前なのですが、それでは何故わざわざ「アプリケーション」キャッシュという言い方をするのでしょうね。

同じ、もしくは包含関係にある、それとも、全く排他的なものなのか、それも不明です。実際どちらにも当てはまりそうな場合がありました。

ここでは、「アプリケーションキャッシュ」でネイティブのアプリケーションのように動作させていながら、必要なときにはキャッシュを消去したり更新したりするにはどうすればいいか、ということを考えます。「更新が効く」/「更新が効かない」は、WebViewで呼ばれるURLにあるscriptファイルの文字列を一部変えてみて、表示に変化があれば「更新が効く」、なければ「更新が効かない」としています。もちろんscriptファイルはmanifestファイル内のCACHEフィールドに記述されておりmanifestファイルの文字列を一部マニュアルで更新しています。

WebView#clearCacheが効かない

ネットによると、キャッシュ消去の標準的なやり方は、WebView#clearCacheを使う方法のようです。onDestroy()中で、WebView#clearCache(true)を実行して「loadStorage」と「アプリケーションキャッシュ」で検証してみました。使い方や呼び出す順序がまずいのか、まったく効きません。ネットでは効くのが当然のような書き方が殆どなので恐らくなにか間違っているのでしょうね。これについては簡単なプログラムで確かめてみたいと思います。

省略値を陽に宣言しないと動作しないのは何故?

Enabling HTML5 AppCache in Android Webview programatically.のページには、WebView#AppCacheEnabled()はよいとして、WebView#AppCachePath()、WebView#AppCacheMaxSIze()にも省略値を陽に指定しないと動作しなかったとあります。実際Path指定がないとエラーになりました。

こういうことがひとつでもあると何を信じてよいか分からなくなりますね。ただ、どこかのページには「Pathを陽に示せ」と書いてあったようにも記憶しています。ちなみにAppCacheMaxSizeに1024*1024*5の代わりに「0」としても「アプリケーションキャッシュ」は動作していました。「0」ではなくて「1」とか思いっきり小さい値がよかったのかも知れませんね、この手の検証では。

「アプリケーションキャッシュ」ではなく、「キャッシュ」だけ使いたい場合にはこのような指定は必要ないのか、これも不明です。

Android端末のアプリケーション設定での謎!?

Android端末の「設定」に「アプリケーション」という設定項目があります。アプリを選び「本体データ削除」「キャッシュ消去」のうち、「キャッシュ消去」を有効にしてみました。すると、そこに出ているキャッシュデータ量を示す数字は0になりますが、依然として「アプリケーションキャッシュ」が動作していました。「キャッシュ消去」前の容量は、ちょうど「アプリケーションキャッシュ」のためにMaxサイズとして指定したものと一致しており、直感的に「キャッシュ」=「アプリケーションキャッシュ」もしくは包含されるように考えてしまいました。

「本体データ削除」だと「アプリケーションキャッシュ」が更新できますね。何故でしょう。ただ本体データ削除のデータ量は70kB程度で自分のアプリは画像を含め150kB程度ありますので、「アプリケーションキャッシュ」が「本体データ」に含まれるというのも数字が合いません。「キャッシュ消去」にでている量は5MB強とリーズナブルです。

やっとみつけたWorkAround(ワークアラウンド、回避策)

「本体データ削除」だと何故か「アプリケーションキャッシュ」が更新できますが、設定が多いと結構つらいです。なので、なにかいい方法はないかと探していたら、すぐ近くにありました。「強制停止」+「キャッシュ消去」です。理由は分かりませんが、設定もそのままでキャッシュ(アプリケーションキャッシュ?)やloadStorageもクリアできるようです。

PHPとは共存できないんでしょうか?

もうひとつ不思議なのが、PHPとの共存です。ご存知かも知れませんが、PHPコードは大抵サーバ側で処理するものですから、manifestファイルにindex.phpとあってもクライアントだけの環境ではうまく動作するはずがありませんが、index.phpそのものではなくindex.phpの処理結果をキャッシュしているのか、それなりに処理できています。いつも厳格な「アプリケーションキャッシュ」の風貌にそぐわない感じがしています。

WebViewのHTML5アプリケーションキャッシュ、不可解過ぎます。

といっても、恐らく私の勉強が足らないだけなのでしょうね。

結構複雑でわかりにくい話ですみません。

関連する記事・ページ

無料Androidアプリ「10秒で10年日記 逆さ日記帳」をGoogle Playにてリリースしました
「10秒で10年日記 逆さ日記帳」の設定に「全てのカレンダ」項目を追加しました
“Just10SecGet10yDiary R10Diary” has another feature of “All Calendars”
自作無料WEBアプリ「10秒で10年日記 逆さ日記帳」に検索機能を追加しました
「10秒で10年日記 逆さ日記帳」というWEBアプリをリリースしました

お世話になったリンク

Enabling HTML5 AppCache in Android Webview programatically.
caching – Cache dynamic page using html5 cache manifest using Android webchromeclient – Stack Overflow

以上です。