まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:html5

NHK が最近また流行りだしたワンクリック詐欺サイトのニュースを流していました:
スマホに「消せないメッセージ」 注意を


(2015/02/06 追記)
NHK のニュースページが消えてしまい、リンク切れになっていたので、同様のニュースを紹介しているページのリンクを貼っておきます:
【注意!】スマホに消せない画面を表示し金を奪うサイトが続出!
(2015/02/06 追記終わり)


ニュースの内容によると、どうもこれは
 ・(アプリとかではなく)特定のウェブページを
 ・スマホを使って
 ・閲覧した瞬間に
起こる仕組みがある、というものでした。

試しに見てボタンをクリックしたら、ではなく、見た瞬間に発生するらしいです。なので詐欺とわかっていても何が起こるかわからないので試してみるのも怖い、、、、ですよね。

せっかくなので(笑)、勇気を出して比較的安全と思われる方法で何をやっているのかを調べてみました。

このニュースで報じられていたサイトは、どうやら http://XXXXX-avnavi.net/ というサイトです(XXXXX 部分は僕の判断で伏せ字にしてます)。 結論から言うと、このサイトは PC のブラウザでアクセスすれば、単に JavaScript の alert が繰り返し表示されるだけの迷惑ページで済むのですが、最初は何が起こるかわからないので PC ブラウザも使いません。Linux 環境から基本の wget でソースコードだけいただきます:
(トップページの HTML ソースコードだけいただいて X.html という名前で保存)
# wget http://XXXXX-avnavi.net/ -O X.html

取り出した内容を vi で表示します。何よりも驚いたのは丁寧でわかりやすいコメントが大量に書かれていました。おかげで何をやっているのか、とても理解しやすかったです(笑)。この姿勢に限っては真似してもいいと思う。

さてその内容ですが、まず最初にこんな JavaScript コードが実行されてました(コメントもそのまま):
<script>
// History API が使えるブラウザかどうかをチェック
if( window.history && window.history.pushState ){
  //. ブラウザ履歴に1つ追加
  history.pushState( "nohb", null, "" );
  $(window).on( "popstate", function(event){
    //. このページで「戻る」を実行
    if( !event.originalEvent.state ){
      //. もう一度履歴を操作して終了
      history.pushState( "nohb", null, "" );
      return;
    }
  });
}
</script>

非常に丁寧なコメントですよね~(苦笑)。実を言うとこの時点で「おや?」と気付くこともあったのですが、その内容は後述します。

肝心な内容は JavaScript で HTML5 の History API が利用できるブラウザかどうかをチェックした上で、popState/pushState を操作して「戻る」を実行しても戻れないように(要するに「戻る」の無効化)操作しています。このページを見て、怖くなって「戻る」を押しても戻れないように予め設定されてしまうのです。用意周到ですね。。

ちなみにここのテクニックに関しては以前に僕のブログエントリでも紹介しています。興味ある方はそちらを参照ください:
HTML5 の pushState/popState でヒストリバックを無効にする


そして、ページを戻れなくした上で行っているのがこちらのコードです。赤字部分は僕が加えた説明コメントです:
<script type="text/javascript">
client_id1 = getCookie('id'); //. クッキーから(別途設定した) ID を取得
console.log("in template"); //. この2行要らないと思う
console.log(client_id1);
var HogeTimer = setInterval("hogemoge()",1000); //. 1秒毎に以下を実行
function hogemoge(){
(この一行があまりにも長くて見にくかったので改行しています。
 問い合わせ先電話番号 NNNNNNNNNNNNN はこちらで伏せ字にしました)

alert('【御登録完了】\nお申込み承諾致しました。\n 動画再生準備完了中。\n\n 【18禁アダルト動画サイト】\n 【365日間の視聴期間】\n\n ★只今お客様還元祭★\n ★キャンペーン期間中で割引適用中★\n 99800円\n 会員ID:' +client_id1 +'\n問い合わせ先\nNNNNNNNNNNNNN\n ※キャンペーン期間内にご精算下さい※\n\n ※誤作動登録の場合※\n →24時間以内に登録削除(自動処理)へご連絡ください。\n\n ※24時間経過後※\n→誤作動登録の場合でもご精算頂きます。');
//. ↑怖いメッセージを表示した後に、、 location.href = "tel:NNNNNNNNNNNNN"; //. スマホの場合、ここで電話をかけようとする

//. 終了しても1秒後にメッセージ表示から繰り返される } </script>

まず別途設定したクッキーを使って、お客様番号っぽい情報を作り、それを取り出します(お客様番号でも何でもありません)。 その直後の console.log 2行は気持ちは分かるけど消しておいた方がいいと思う(苦笑)。

そして JavaScript の setInterval を使って、1000ミリ秒(1秒)毎に実行する処理を指定しています。ここでいう「1秒毎」は、この処理が実行されて、最後まで実行して、そこから1秒たったらまた初めから実行、です。要は1秒の間をとりながら延々と繰り返される処理、ということになります。ここまではよくあるブラクラと同じ原理です。

気になる肝心の処理内容ですが、(1)怖いメッセージを表示して(「OK」ボタンだけ表示されるので押すしかない)、(2)「OK」を押すと(スマホでは)特定の番号に国際電話をかけようとする です。実際には「電話をかけますか?」という確認メッセージが表示されて、かけるかどうかを選択できるのですが、書けずに終了しても、1秒後にまた (1) へ戻るだけです。ちなみに電話をかけても (1)へ戻ります。

「怖い」と感じて、前のページに戻ろうとしても前述のように「戻る」は無効化されています。普通にホームボタンを押してブラウザを閉じてしまうことはできますが、(別の目的で)ブラウザを使おうとすると、履歴が残っているのでまたこの画面に戻ってしまいます。パニックにさせて、「電話をかけるしかないのか?」と思わせようとしてるんですかね。ちなみに電話をかける実験まではしてないので、どういう内容かはわかりません。 (^^;


もしも、間違ってこのページを PC ブラウザで開いてしまった場合は、CTRL+ALT+DEL キーを押してタスクマネージャーを出すなどして、ブラウザごと終了してしまいましょう。

スマホでこのページを見ちゃった場合はこちらのページを参考に履歴ごと消してしまってください:
http://did2memo.net/2013/11/15/iphone-endless-pop-up-message-page/



サイトの仕組みの説明は以上です。この下は気付いた雑感を2つほど。

まず、このページの HTML / JavaScript は非常に読みやすいです、メンテナンスしやすそう(苦笑)。ある意味で優秀なエンジニアが関わってるんだろうなあ、と思いました。デバッグ用と思われる console.log が残っているのはご愛嬌ですが、JavaScript 以外の HTML でも例えばこんな感じの記述がされています:
2015013101


いやあ、わかりやすい(笑)。 <div> でちゃんとパーツ化されている上に HTML コメントが非常に適切で、実際の画面を見なくてもどういうページを作ろうとしているのか想像できます。感心してる場合じゃないけど、これ作った人とは話が合いそう。。 (^^;

そしてもう1つ気になったこと。それは上記で紹介した僕のブログエントリ
HTML5 の pushState/popState でヒストリバックを無効にする

で紹介している JavaScript の内容と、このサイトで実際に使われている JavaScript の内容が変数やコメントの使い方のレベルで非常に似ている、というか似すぎている!? あれ?もしかして参照してくれた!? ということに気付いてしまいました。 良い子はこういう使い方に応用しないでね。 d(o^ )

#念のため補足しておくと、僕が紹介した無効化は問い合わせフォームなどで 入力→確認→送信 みたいなページ遷移をする時に 送信後のページから確認ページに戻られると色々不都合があるので、そういった挙動をさせなくするための手段として紹介したつもりでした。


というわけで、メンテナンス性も含めた色んな意味で意外と完成度の高い詐欺サイトでした。




 

HTML5 の File API を使った、OS からウェブ画面へのファイルドラッグ&ドロップを実現する方法を紹介します。

まず、何も準備しないでウェブ画面へファイルをドラッグ&ドロップすると、デフォルト挙動によって、そのファイルがブラウザで開かれます。例えば画像ファイルをウェブ画面にドラッグ&ドロップすると、その画像ファイルがブラウザ内で開かれて表示されます。

ドラッグ&ドロップを実現するには、まずブラウザのこのデフォルト挙動を上書きして、別の挙動にするよう指定する必要があります。そのためにファイルドロップのエリア(<div>)への drop イベントに対して、preventDefault(); を指定しておく必要があります。これでファイルをドロップしてもブラウザでは開かなくなります。

また、ドロップイベントのパラメータである event の event.dataTransfer.files プロパティにはドラッグ&ドロップしたファイルの情報が配列で入ってきます。このオブジェクトの内容が画像であるかどうかを調べた上で、画像と判別できたら Dynamic JavaScript を使って <img> タグを追加し、innerHTML でその画像を表示する、という挙動を実装しています。こうすることで動的に(リロードなしに)そのドロップされたファイルをブラウザ内に表示することができるようになります。

この挙動を実装したのが以下です。ピンクの枠(<div id="droparea">)がドラッグ&ドロップのドロップイベントを制御するエリアになっていて、この中に画像ファイルを(ドラッグ&)ドロップすると、その画像をリロードなしにその直下の <ul id="files"></ul> の中で表示します:


ここにファイルをドロップ

    この HTML および JavaScript は以下になります:
    <script type="text/javascript">
    window.onload=function(){
     var URL_BLANK_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
     var elDrop = document.getElementById('droparea');
     var elFiles = document.getElementById('files');
    
     elDrop.addEventListener('dragover', function(event) {
      event.preventDefault();
      event.dataTransfer.dropEffect = 'copy';
      showDropping();
     });
    
     elDrop.addEventListener('dragleave', function(event) {
      hideDropping();
     });
    
     elDrop.addEventListener('drop', function(event) {
      event.preventDefault();
      hideDropping();
    
      var files = event.dataTransfer.files;
      showFiles(files);
     });
    
     document.addEventListener('click', function(event) {
      var elTarget = event.target;
      if (elTarget.tagName === 'IMG') {
       var src = elTarget.src;
       var w = window.open('about:blank');
       var d = w.document;
    
       d.open();
       d.write('<img src="' + src + '" />');
       d.close();
      }
     });
    
     function showDropping() {
      elDrop.classList.add('dropover');
     }
    
     function hideDropping() {
      elDrop.classList.remove('dropover');
     }
    
     function showFiles(files) {
      elFiles.innerHTML = '';
    
      for (var i=0, l=files.length; i<l; i++) {
       var file = files[i];
       var elFile = buildElFile(file);
       elFiles.appendChild(elFile);
      }
     }
    
     function buildElFile(file) {
      var elFile = document.createElement('li');
    
      if (file.type.indexOf('image/') === 0) {
       var elImage = document.createElement('img');
       elImage.src = URL_BLANK_IMAGE;
       elFile.appendChild(elImage);
    
       attachImage(file, elImage);
      }
    
      return elFile;
     }
    
     function attachImage(file, elImage) {
      var reader = new FileReader();
      reader.onload = function(event) {
       var src = event.target.result;
       elImage.src = src;
       elImage.setAttribute('title', file.name);
      };
      reader.readAsDataURL(file);
     }
    }
    </script>
    
    <div  effectallowed="move" id="droparea">ここにファイルをドロップ</div>
    <ul id="files"></ul>
    
    

    参考にしたのはこちら:
    http://jsfiddle.net/ginpei/bSF9z/
     

    Firefox OS 向けのネイティブアプリケーションを開発する手順を紹介します。

    「ネイティブアプリケーション」と言うと、開発言語は iPhone だと Objective-C や Swift、Android だと Java 、といった具合にネイティブ開発用のコンパイル言語が一般的ですが、Firefox OS アプリの場合は HTML5 でアプリケーションを開発します。HTML5 で作る、ということは HTML やら JavaScript や CSS を組み合わせて UI やロジックを作っていく、ということを意味しています。これは C や Java で開発する場合と比べて、非常にハードルが低く、より多くのエンジニアが参画できるのではないかと感じます。

    ただ Firefox OS の開発ではマニフェストファイルの存在や、その中で API の許可設定を行うこと、そして Android で言うところの「インテント」に近い連携が可能になっていることなど、Android の開発手法と似ている所が多い、という事実もあります。開発言語こそ Java と HTML5 の違いはありますが、アプリケーションパッケージの考え方としてはかなり近いという印象を持っています。そのため Android での開発経験があるエンジニアからすると、「開発言語が Java から HTML5 になった」という感じで、非常にとっつきやすいのではないかとも感じています。 


    そんな Firefox OS 向けアプリケーション、まずは Hello World レベルのものを作ってみます。

    事前に用意する必要があるのは Firefox OS シミュレータ、これは動作確認用です。Firefox OS シミュレータの導入方法については以前の私のブログエントリを参照してください:
    Firefox OS シミュレータ

    そしてテキストエディタです。もちろん Eclipse などの統合開発環境でも構いませんが、この Firefox OS 用アプリは HTML5 で作るので、HTML や JavaScript、CSS が記述できるエディタであれば何でも構いません。あまり複雑でないうちは Windows のメモ帳でも充分だと思います。


    では Firefox OS 向け "Hello World" アプリケーションを作っていきます。これから作るアプリは3つのファイルから構成されます:
    - helloworld.html (アプリケーション本体)
    - manifest.webapp (マニフェストファイル)
    - icon.png (アイコン画像ファイル)
    

    helloworld.html はアプリケーションの本体となるファイルです。通常は JavaScript や CSS を外出しにして外部から読み込む形になるのが一般的ですが、今回は(それほど複雑な内容ではないので)全て1ファイル内に定義することにします。

    manifest.webapp がマニフェストファイルです。アプリケーションの属性を指定するファイルです。Android アプリケーション開発の経験がある方であれば、同様のマニフェストファイルの存在をご存知だと思います。

    そして icon.png はアプリケーションのアイコンです。無くても(デフォルトのアイコンが使われるだけなので)いいんですが、アプリをいくつも作っているとアイコンだけで区別できなくなってしまうので、とりあえず用意しておきました。今回は128x128 ピクセルのファイルを用意しました。Firefox OS アプリで使う画像ファイルには何種類かありますが、マーケットにリリースする際には 128x128 の画像ファイルが必要になります。その意味もあって最初に用意しておきました。なお、このファイルはマニフェストファイルで指定するので、ファイル名は何でも構いません。今回はこのようなシンプル(?)な画像を用意しました。
    2014110401


    icon.png は画像ファイルなので、あらかじめ用意しておく必要があります。では残る2つのテキストファイルをこれから作っていきましょう。


    まずはこのアプリケーションプロジェクトを作るために専用のフォルダ(ディレクトリ)を1つ作っておきます。例えば c:\tmp\helloworld といったフォルダを作ります。これから3つのファイルをこのフォルダ内に作ります(icon.png はこのフォルダ内にコピーしておきます)。Eclipse を使う場合は "Static Web Application" のプロジェクトを作成して、全てのファイルをプロジェクトフォルダの直下に配置することになります。最終的にはこの図のようなフォルダ/ファイル構成になるように作っていきます:
    2014110402


    ではフォルダ直下に helloworld.html という名前の HTML5 ファイルを以下の内容で作成します。なお、日本語を使う場合のエンコードは UTF-8 にしてください:
    <!DOCTYPE html>
    <html lang="ja">
    <head>
    <meta charset="UTF-8"/>
    <title>Hello World</title>
    <script>
    function sayHello(){
    	alert( "Hello World!" );
    }
    </script>
    <body>
    <header>
    <h3>Hello World.</h3>
    </header>
    <p><button onclick="sayHello();">メッセージ</button></p>
    </body>
    </head>
    </html>
    

    この HTML5 ファイルの内容についてはあまり解説は要らないと思っています。画面上に <h3> によるタイトルと、ボタンを1つ配置し、そのボタンがクリックされると sayHello() 関数が呼ばれ、画面に "Hello World!" というアラートダイアログが表示される、というだけのものです。

    続いてマニフェストファイルを作成します。フォルダ直下に以下の内容で manifest.webapp という名前で、JSON 形式のテキストファイルを作成します:
    {
      "name": "Hello World App",
      "description": "FireFox OS 用 Hello World アプリ",
      "launch_path": "/helloworld.html",
      "icons": {
        "128": "/icon.png"
      }
    }
    

    この manifest.webapp ファイルの中ではアプリケーションの情報を指定しています。まず "name" でアプリケーションの名前を128文字以内で定義します(必須)。"description" では、これがどのようなアプリケーションなのか、その説明を1024 文字以内で記述します(必須)。 "launch_path" では最初に読みこむファイルを指定します(必須)。

    "icons" ではアプリケーションのアイコンを配列型で指定します。サイズに応じた指定が可能になっており、1つしか登録しない場合でも配列にする必要があります。この例では "128" を指定しているので 128x128 のアイコンが登録されています。マーケットプレースに登録する場合は最低でも 128x128 のアイコンが必要です。

    マニフェストファイルに指定する項目は他にもあるのですが、今回はこれだけで動きます。では実際に Firefox OS シミュレータを使って動かしてみましょう。こちらを参考にして Firefox OS シミュレータのダッシュボード画面を起動します。そして "Add Directory" ボタンをクリックして、上記で作った manifest.webapp ファイルを指定します:
    2014110403


    manifest.webapp に書かれた内容に従ってアプリケーションやアイコンが読み込まれ、ダッシュボードに表示されます。このアプリケーションが読み込まれた状態で左の "Simulator: Stopped" と書かれた箇所をクリックして Firefox OS シミュレータを起動します:
    2014110404


    HelloWorld アプリケーションが Firefox OS シミュレータの中で実行されている状態で起動します:
    2014110405


    「メッセージ」ボタンをクリックすると、(JavaScript でプログラミングした通りに)メッセージボックスが表示されるはずです:
    2014110406


    これだけ、HTML5 で作ったアプリケーションが Firefox OS(シミュレータ)内で動作するところまでを確認できました。内容がシンプルという面もありますが、特別な環境なしのメモ帳程度のテキストエディタだけで作れるし、そんなに難しくなさそうですよね。

    もちろん実際にアプリを作ろうとすると、CSS やライブラリを使ってモバイル端末に最適化したUIを用意したり、各種 API を利用するための権限設定をしたり、データの受け渡しの方法を設計した上でマニフェストに加えたり、と色々やることはあります。 ただベースとなるアプリはこの程度のコーディングで実現できる、というのはやはり魅力だと思っています。


     

    最近、少しずつですが Firefox OS のアプリ開発を始めています。いずれこのブログでもまとめていくつもりですが、その準備的な意味もあって、Firefox OS シミュレータの導入手順だけを先に紹介しておきます。これをやっておくことで、アプリ開発はともかく Firefox OS がどんなものか、体験することができるようになります。

    Firefox OS シミュレータは Firefox ブラウザのアドオンとして提供されています。なのでまずは Firefox ブラウザがインストールされていることが前提となります。Firefox 内で Ctrl + Shift + A でアドオンマネージャーを起動します:
    2014110101


    「アドオン入手」タブ内で "Firefox os simulator" を検索すると、最新版の Firefox OS シミュレーターが見つかるので、これをインストールします:
    2014110102


    インストールが完了すると「拡張機能」タブ内から参照できます。これでインストールは無事完了:
    2014110103


    インストール後は FireFox の右上のメニューから 開発ツール > Firefox OS Simulator を選択すると Firefox OS シミュレータのダッシュボードが起動します:
    2014110104


    Firefox OS シミュレータダッシュボードが起動しました:
    2014110105


    ダッシュボード画面左の Simulator: Stopped と表示されているスイッチ部分をクリックすると Simulator: Running の表示に切り替わり、同時に Firefox OS シミュレータが起動します:
    2014110106


    シミュレータ(というか Firefox OS)の使い方はまた別の機会に。とりあえずこれでシミュレータが導入できたので、アプリ開発の動作確認の準備もできました。



    HTML5 で追加された JavaScript の History API を使うと、ブラウザのヒストリ履歴(戻る/進む)の中身を操作できます。これを使って「戻る」を無効にしたページを作ってみます。jQuery を使うので、必要に応じてロードしておきます。

    History API では pushState メソッドで履歴を1つ追加、popState メソッドで履歴を1つ(新しいものから)取り出します。この2つを組み合わせて、以下の様なロジックを実装しています:
    - ページロード時に強制的にニセの1つ履歴を追加
    - そのページ内で「戻る」イベントが発生したら(追加したニセの履歴が取り出されるので)、再度ニセの履歴を1つ追加して処理を終了(return)する

    <script>
    // History API が使えるブラウザかどうかをチェック
    if( window.history && window.history.pushState ){
      //. ブラウザ履歴に1つ追加
      history.pushState( "nohb", null, "" );
      $(window).on( "popstate", function(event){
        //. このページで「戻る」を実行
        if( !event.originalEvent.state ){
          //. もう一度履歴を操作して終了
          history.pushState( "nohb", null, "" );
          return;
        }
      });
    }
    </script>
    

    これでブラウザの「戻る」ボタンをクリックしても、本来の1つ前の URL ではなく、偽装した履歴が取り出されます。このままですとその偽装した履歴の URL に移動してしまう(今回は "" を指定しているので飛びようもありませんが)のですが、その前に return で強制的に処理を止めているので何も起こりません。また履歴を取り出した直後に再度ニセの履歴を追加しているので、更にもう一度「戻る」をクリックしても同じ処理が繰り返されて、結局戻れない、ということになります。

    ちなみにこのブログのエントリの中にもこの JavaScript を埋め込んであります。なので、History API が使えるブラウザでこのページを見ている状態からは「戻る」を押してもどこにも戻れないはずです。


    これ、うまく使うと「戻る」ボタンを押した時に本来とは異なるページに強制移動させることもできちゃったりするんじゃないかな。。



    このページのトップヘ