socket.io-clientでoriginが指定されたsocket.ioに接続する

つまりsocket.io-clientを利用したサーバー上のクライアントからのアクセス時には、Originを*:*にして、外部からのアクセス(通常のブラウザからのアクセス)時には、特定のHOST(Origin)のみを許可したい。
(Originで特定のHOSTに絞らない場合は、そもそも下記のような事はする必要はありませんので)

Client(socket.io-client)

まず、socket.io-clientからのアクセス時にヘッダー(下記ではx-dev-session)を追加。
(このヘッダーを持っているアクセス時のみOriginを*:*にします)

// 元のXMLHttpRequest
var Request = require('socket.io-client/node_modules/xmlhttprequest').XMLHttpRequest;

// ワンタイムなsession発行 -> KVSとかに保存
var session = 'xxxxxxxxxxxxxxxxxxxxx';

require('socket.io-client/node_modules/xmlhttprequest').XMLHttpRequest = function(){
    Request.apply(this, arguments);

    var open = this.open;
    this.open = function() {
        open.apply(this, arguments);

        // ヘッダー追加
        this.setRequestHeader('x-dev-session','xxxxxxxxxxxxxxxxxxxxx');
    };
};

上記(local_header.js)を読み込んでserver.jsへアクセスするclient.js

// XMLHttpRequestをoverride
require('./local_header');

var socket = require('socket.io-client').connect("http://localhost:3000");

socket.on('connect',function(){
  // 処理...
});

Server(socket.io)

特定のヘッダー(x-dev-session)のvalueがKVSにあるかチェックして、一致すればOriginを*:*に。

// 元のverifyOrigin
var localOrigin = require('socket.io').Manager.prototype.verifyOrigin;

require('socket.io').Manager.prototype.verifyOrigin = function() {

    // KVSに保存したsessionチェック
    if ( arguments[0].headers['x-dev-session'] == 'xxxxxxxxxxxxxxxxxxxxx' ) {
        // KVSからsessionを消す処理
        // ....

        // originを*:*に
        this.settings['origins'] = '*:*';
        return true;
    }
    else {
        // originを特定のドメインに
        this.settings['origins'] = 'http://www.example.com:*';
    }

    return localOrigin.apply(this, arguments);
}

上記(local_manager.js)を読み込んだserver.jsを作成。


// verifyOriginをoverride
require('./local_manager');

var server = require('http').createServer();
var io = require('socket.io').listen(server);

io.on('connection', function(socket){
    // 処理...
});

server.listen( 3000 );
// ...

これで、server.jsを起動すれば、外からのアクセスは特定のドメイン(www.example.com)のみに絞りつつ、client.jsからの内部的なアクセスもできるはずです。

他のやり方もありそうですが・・

誰かもっと簡単なやり方あったら教えてください。。

ホントは

  • localhostのみ許可(もしくはlocal IPのみ許可)するとか?
  • そもそも接続テスト以外に使いたい(crontabとかで内部的にイベントを発生させたい)場合は、StoreをRedisにして、pub/subでeventを起こすとか?

とかの方が綺麗かも。
そのうち試してみたいところ。