Ajaxにおけるクロスドメインの問題を回避する方法

こんにちは!ぐち(@bloguchi)です。

先日ローカルでWeb開発をしていて、localhost内から外部のドメインが提供しているWebAPIを実行しようとしたときに直面した問題について、今更ながら備忘録としてご紹介します。

クロスドメインリクエスト(XDP)

冒頭で軽くご説明した通り、あるドメインで読み込まれたHTMLページ(foo.com)から、Javascriptなどブラウザ上で動作するプログラミング言語によって、異なるドメイン(bar.com)のサービスに接続するとブラウザがエラーや警告を表示することがあります。

これが今回ご紹介したいクロスドメインの問題です。

何が問題なのか

通常HTMLというのは、ブラウザ上で表示され画面上に用意されたフォームやサービスをJavascriptなどのプログラミング言語によって実行します。この時、サービス側は接続してくるクライアント(ブラウザなど)を判断し、適切なクライアントの場合にのみ特定の動作を行う判断をする場合があります。

例えばECサイトなどです。サイトでユーザーAだけが知り得る情報を入力します。クレジットカード番号などです。本来、こういった秘匿性の高い情報はブラウザのみが扱うことができるのですが、プログラミング言語からサービスを扱うことができるとすると、悪意のあるユーザーBがプログラミング言語によるサービス利用時に不正なユーザー情報をリクエストできてしまうことになります。

この場合、サービス側ではそのリクエストが不正なのか正常なのか見分けがつきません。ブラウザが乗っ取られるといったほうが聞き覚えがあるかもしれませんが、そういう情況を作り出せてしまいます。こういったセキュリティの制約を担保するためにクロスドメインリクエストの制限が儲けられています。

回避策はないのか

とは言え、自分が開発中のシステムからこういったアクセスができないのは不便で仕方ありませんよね?こういった場合を考慮し回避策が用意されています。

Access-Control-Allow-Originを設定する

この方法はサーバサイドでの設定が必要です。ご自身で管理しているサーバやサーバ側に変更できる環境の場合にお使いください。

.htaccessPHPなどのプログラムなどでクロスオリジンリソースシェアリング(CORS)の設定を変更します。

.htaccessで設定する場合
<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin: "*"
</IfModule>
PHPで設定する場合
<?php
header('Access-Control-Allow-Origin: *');
?>

上記の例は全てのサイトからのアクセスを許可する場合です。特定のサイトからのみアクセスを許可する場合は*の部分をサイトのURLに書き換えてください。

JSONPとして扱う

JQueryを使った場合は下記のようにdataTypejsonpとするだけです。ただしサーバ側もJSONPでのレスポンスに対応している必要があります。

$.ajax( {
    "url": "http://foo.com/test.php";,
    "dataType" : "jsonp",
    "data": {"id": "12"},
    "success": function(result) {
        // 成功時の処理
    }
} );

プログラムを経由する

この方法が唯一サーバの管理者でなくても実行できる回避方法でしょう。Ajaxでリクエストをしている同じサーバにサーバサイドのプログラムを用意し、それにAPIへのリクエストをさせます。

ajax.php

<?php
if(isset($_GET['url']) && preg_match('/^http(s)?:/', $_GET['url'])){
    echo file_get_contents($_GET['url']);
}
?>

Javascriptでは、前述のようにurlの値を`/ajax.php?url=http://www.foo.com/test.php’のようにパラメータとしてリクエスト先のURLを渡します。これでブラウザ上のAjaxからのリクエストは同じサーバを向きますのでクロスドメインの問題は起きません。

とは言ってもセキュリティ上の制約なので無理に回避せず適切なプログラムを心がけましょう!

では今回はこの辺で。