Node.js

社内プロキシに打ち勝つフォワードプロキシに苦戦した話(node + http-proxy)

はじめに

社内でフロント向け開発ツールを作成していた時、クロスドメイン問題を回避するためにフォワードプロキシが必要になった。

やりたいこと

クライアントからのHTTPリクエストを受け、認証付き社内プロキシを経由して別サーバへフォワードする。
リクエストとレスポンスは改変しない。そのまま横流しするだけ。

使ったもの

修正前ソース

server.js
const httpProxy = require('http-proxy');
const http = require('http');

var proxy = httpProxy.createProxyServer({});

// http server
var httpServer = http.createServer(function (req, res) {
    res.setHeader('tekitou', 'tekitou');
    var opt = {target:'http://tekitou.com'};
    proxy.web(req, res, opt, function (err) {
        console.log(" !! translate error. ");
        console.log(err);
        res.write("<p> Translate error.</p>");
        res.write("<p>Host name : " + req.headers.host + "</p>");
        res.end();
        return;
    });
    return;
});
var port=1234
httpServer.listen(port, function () {
    console.log("-- start forward proxy server(http) . listen " + port + " port. --");
});

はまったところ

  • 認証付きの社内プロキシが通らない

そのままhttp-proxyでプロキシを作っても、認証付きの社内プロキシは通してくれない。
tunnnelを使って認証プロキシのagentをoptionに付与する必要あり。
<改変後>

server.js
const httpProxy = require('http-proxy');
const http = require('http');
// new!
const tunnel = require('tunnel');

var tunnelingAgent = tunnel.httpOverHttp({
    proxy: {
        host: 'hoge,co.jp',
        port: 1111,
        proxyAuth: 'proxyid:proxypass'
    }
});

var proxy = httpProxy.createProxyServer({});


// http server
var httpServer = http.createServer(function (req, res) {
    res.setHeader('tekitou', 'tekitou');
// new!
    var opt = {target:'http://tekitou.com' , agent:tunnelingAgent };
    proxy.web(req, res, opt, function (err) {
        console.log(" !! translate error. ");
        console.log(err);
        res.write("<p> Translate error.</p>");
        res.write("<p>Host name : " + req.headers.host + "</p>");
        res.end();
        return;
    });
    return;
});
var port=1234
httpServer.listen(port, function () {
    console.log("-- start forward proxy server(http) . listen " + port + " port. --");
});
  • フォワード先をhttpsに向けると通らない

optionにsecure=falseとchangeOrigin=trueを付与したら通った。
さらに、tunnnelのhttpOverHttpsのagentが必要。
<改変後>

server.js
const httpProxy = require('http-proxy');
const http = require('http');
const tunnel = require('tunnel');

var tunnelingAgent = tunnel.httpOverHttp({
    proxy: {
        host: 'hoge,co.jp',
        port: 1111,
        proxyAuth: 'proxyid:proxypass'
    }
});

// new!!
var tunnelingAgentForHttps = tunnel.httpOverHttps({
    proxy: {
        host: 'hoge,co.jp',
        port: 1111,
        proxyAuth: 'proxyid:proxypass'
    }
});

var proxy = httpProxy.createProxyServer({});


// http server to https
var httpServer = http.createServer(function (req, res) {
    res.setHeader('tekitou', 'tekitou');
    var opt = 
            { target:'https://tekitou.com',
              agent : tunnelingAgentForHttps ,
              secure : false,
              changeOrigin : true
             };
    proxy.web(req, res, opt, function (err) {
        console.log(" !! translate error. ");
        console.log(err);
        res.write("<p> Translate error.</p>");
        res.write("<p>Host name : " + req.headers.host + "</p>");
        res.end();
        return;
    });
    return;
});
var port=1234
httpServer.listen(port, function () {
    console.log("-- start forward proxy server(http) . listen " + port + " port. --");
});

さいごに

踏み込んだ説明がなくてごめんなさい。
スマートな方法があったら教えてください。