Webセキュリティの小部屋

Twitter のフォローはこちらから Facebook ページはこちら RSSフィードのご登録はこちらから
公開日:2015年6月28日

jQuery を使わずに Ajax でセキュアに JSON のやりとりする方法

はじめに

最近は、jQuery 以外のライブラリやフレームワークが多く登場してきており、jQuery を使わないケースも増えてきているのではないでしょうか。

Ajax の通信は、jQuery でなくともライブラリやフレームワークが対応していると思いますが、Ajax の通信のためだけにライブラリやフレームワークを導入するというのもよい選択ではないでしょう。

そこで、一度基本に立ち戻り、jQuery を使わず、ネイティブの JavaScript で JSON を Ajax の通信で扱い、さらにセキュリティ対応をする方法をご紹介します。

対応する環境は、Internet Explorer 9 以降になります(一部を変更すれば Internet Explorer 8 でも動作)。

JSON セキュリティ対応

JSON のセキュリティ対応は、以前の記事で解説していますが、対策は以下のようになります。

  • JSONP で Web サービスを呼び出せないようにする
  • JSON を JSON としてブラウザが認識するようにする
  • eval インジェクション対策
  • クロスサイト・スクリプティング対策

 JSONP で Web サービスを呼び出せないようにする

JSONP で Web サービスを呼び出せないようにするには、以下の HTTP ヘッダーをチェックします。jQuery や prototype.js などはデフォルトで対応しているので、ネイティブの JavaScript でもこれを踏襲することにします。

X-Requested-With: XMLHttpRequest

 JSON を JSON としてブラウザが認識するようにする

JSON を JSON としてブラウザが認識するようにするために、レスポンスヘッダーに以下の2つを追加します。

  • Content-Type: application/json; charset=utf-8
  • X-Content-Type-Options: nosniff

eval インジェクション対策

JSON は文字列でサーバーから渡されますが、eval 関数を用いて JavaScript の配列に変換可能ですが、JSON に攻撃用のスクリプトが含まれている場合は、クロスサイト・スクリプティングの脆弱性になってしまいます。

これを防ぐために、JSON 文字列は、JSON.parse 関数 (Internet Explorer 8 以降) を使用します。

クロスサイト・スクリプティング対策

いわゆる DOM based XSS ですが、HTML に要素を追加するときに、HTML として追加してしまうと、攻撃スクリプトが含まれている際にスクリプトが実行され、クロスサイト・スクリプティングの脆弱性となります。

これを防ぐために、HTML に要素を追加する場合は、テキストノードとして追加する必要があります。

サンプルコード

サーバーサイドの言語は PHP で、サンプルコードは以下の sample.html と message.php になります。

sample.html の、ボタンにイベントリスナーを付与している部分を以下のようにすれば、Internet Explorer 8 でも動作すると思います(動作検証未)。

document.getElementById("clickme").onclick = function(e) {
  e = e ? e : window.event; // IE6/7/8 用
  console.log("you clicked " + e.target);
  e.preventDefault();
};

 ■sample.html
 <!DOCTYPE html>
 <html lang="ja">
 <head>
   <meta charset="utf-8">
   <script type="text/javascript">
      window.onload = function() {
        
        //Internet Explorer 9 以降のイベントリスナー付与
        document.getElementById("send").addEventListener("click", function(e) {

          var r = new XMLHttpRequest();
          r.open("POST", "message.php", true);

          //HTTPヘッダー付与、JSON ハイジャック対策
          r.setRequestHeader("X-Requested-With","XMLHttpRequest");

          r.onreadystatechange = function () {
            if (r.readyState != 4 || r.status != 200) return;
            
            //JSON パース(eval インジェクション対策)
            //Internet Explorer 8 以降
            var msg = JSON.parse(r.responseText);

            //テキストノードを作成して要素追加、DOM based XSS 対策
            var div = document.getElementById('message');
            div.appendChild(document.createTextNode(msg["message"]));
          };

          r.send("");
        });
      }
   </script>
 </head>
 <body>
   <div id="message"/>
   <input type="button" id="send" value="送信">
 </body>
 </html>

■message.php
<?php

//XMLHttpRequest 以外はエラー
$headers = getallheaders();

if ($headers["X-Requested-With"] != "XMLHttpRequest") {
  header("HTTP/1.1 403 Forbidden");
  exit;
}

//セキュリティ用ヘッダー付与
header("Content-Type: application/json; charset=utf-8");
header('X-Content-Type-Options: nosniff');

//JSON エスケープして出力
echo json_encode(array("message"=>"Hello!"));

 おわりに

jQuery を使わずに、ネイティブの JavaScript の Ajax で、セキュアに JSON をやりとりする方法を見てきましたが、いかがでしたでしょうか。

ブラウザに依存する部分があったり冗長だったり、jQuery がいかに優れたライブラリかということが再認識できたのではないでしょうか。

同時に、ネイティブ の JavaScript の記述方法を知ることで、いざというときの応用がきくようになると思います。

この記事がみなさんのお役に立てば幸いです。

参考サイト


スポンサーリンク





カテゴリー:ブログ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA