Hapijs在一个连接上同时使用Http和Https

ram*_*n22 3 security https hapijs

新来Hapijs,并试图用它来创建一个使用HTTPS所有请求的应用程序和HTTP重定向到安全connection.The问题是应用程序进去HTTPS模式没有问题,但如果我改变的URL为http服务器没有响应并且不知道原因.

这是我到目前为止所提出的,它可以工作但不适用于HTTP

var connectionOptions = {
    port: 3000,
    tls: {
        key: fs.readFileSync(path.join(__dirname, 'key/key.pem'), 'utf8'),
        cert: fs.readFileSync(path.join(__dirname, 'key/cert.pem'), 'utf8')
    }
};

var server = new Hapi.Server();
server.connection(connectionOptions);

//This method not called when its HTTP
server.ext('onRequest', function (request, reply) {
     if (request.headers['x-forwarded-proto'] === 'http') {
            reply.redirect('https://' + request.headers.host +
                            request.url.path).code(301);
            return reply.continue();
      }
      reply.continue();       
});

var routes = require('./routes')(server);
server.route(routes);

if (!module.parent) {
    server.start(function () {
         console.log('Server running at:', server.info.uri);
    });
 }
Run Code Online (Sandbox Code Playgroud)

如何强制所有请求为HTTPS.感谢您的帮助

Mat*_*son 14

您不能在同一连接上使用http和https.幕后哈皮将创建一个节点http服务器一个https根据服务器tls的配置,如在此行从lib/connection.js:

this.listener = this.settings.listener || (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer());

您应该创建另一个不使用TLS的服务器连接,然后将非TLS请求重定向到https URL.

const Hapi = require('hapi');
const Fs = require('fs');
const Url = require('url');

const config = {
    host: 'localhost',
    http: { port: 3001 },
    https: {
        port: 3000,
        key: Fs.readFileSync('key.key'),
        cert: Fs.readFileSync('cert.pem')
    }
}

const server = new Hapi.Server();

// https connection

server.connection({
    port: config.https.port,
    tls: {
        key: config.https.key,
        cert: config.https.cert
    }
});

// http connection

server.connection({ port: config.http.port });

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply('Hello world');
    }
});

server.ext('onRequest', (request, reply) => {

    if (request.connection.info.port !== config.https.port) {

        return reply.redirect(Url.format({
            protocol: 'https',
            hostname: request.info.hostname,
            pathname: request.url.path,
            port: config.https.port
        }));
    }

    return reply.continue();
});

server.start((err) => {

    if (err) {
        throw err;
    }

    console.log('Started server');
});
Run Code Online (Sandbox Code Playgroud)

编辑

如果在重定向到HTTPS之前允许与服务器进行不安全的连接,请考虑使用HTTP严格传输安全性(HSTS)来防止MITM攻击.您可以使用route config security选项设置HSTS标头:

server.route({
    config: {
        security: {
            hsts: {
                maxAge: 15768000,
                includeSubDomains: true,
                preload: true
            }
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        ...
    }
});
Run Code Online (Sandbox Code Playgroud)


Adr*_*udt 5

另一个解决方案就是重新路由每个http调用,不检查每个请求.您必须使用2个连接.

// create the 2 connections and give the http one a specific label e.g. http
// apply the http catch all route to only the http connection
// I make use of connection label to make sure I only register the catch all route on the http connection
server.select('http').route({
    method: '*',
    path: '/{p*}',
    handler: function (request, reply) {

        // redirect all http traffic to https
        // credit to Matt for the URL.format
        return reply.redirect(Url.format({
            protocol: 'https',
            hostname: request.info.hostname,
            pathname: request.url.path,
            port: config.https.port
        })).permanent();
    },
    config: {
        description: 'Http catch route. Will redirect every http call to https'
    }
});
Run Code Online (Sandbox Code Playgroud)

有关重定向的更多信息,请参阅文档