【问题标题】:Force requests over https in Express/Node在 Express/Node 中通过 https 强制请求
【发布时间】:2012-03-31 22:14:23
【问题描述】:

我有一个 Express.js (v 2.5.8) (node v0.6.12) 服务器在端口 3100 上运行。它由 Nginx 前端,它将 http 和 https 请求代理到端口 3100。

我想通过 https 强制某些网址。这是一个示例(应用程序是我的 Express 服务器):

app.get('/applyNow', ensureSec, secure.showApplication );

ensureSec 是我试图用来检查连接是否通过 ssl 的函数:

function ensureSec(req, res, next) {
    if (req.session.ssl == true) { 
        return next(); 
    } else {
        req.session.ssl = true;
        res.redirect('https://' + url.parse(req.headers.referer).host +
        url.parse(req.url).pathname);
    }
}

重定向有效,但节点(在超时后)抛出错误,提示“无法 GET /applyNow

重定向到ssl的正确方法是什么?

【问题讨论】:

    标签: node.js express


    【解决方案1】:

    据我了解,您正在使用 nginx 协商 SSL 并将 http 和 https 请求代理到您的 Express 应用程序。如果可能的话,我会选择在 nginx 中解决这个问题,但是如果 nginx 不知道应该保护哪些路径(即只能通过 https 获得)或者你想在你的 express 应用程序中执行此操作出于其他原因,这里有一些资料:

    您应该从 nginx 获取 X-Forwarded-Proto,仅当原始协议为 https 时才设置为 https。以下是在 nginx 中执行此操作的方法:

    proxy_set_header X-Forwarded-Proto https;
    

    我还会转发Host 标头:

    proxy_set_header Host $http_host;
    

    在您的 express 应用中,检查该内容,或重定向到标头中的主机和请求的路径(express 将其解析为 req.path,因此您不必这样做):

    function ensureSec(req, res, next) {
        if (req.headers['x-forwarded-proto'] == 'https') { 
            return next(); 
        } else {
            res.redirect('https://' + req.headers.host + req.path);
        }
    }
    

    【讨论】:

    • X-Forwarded-Proto 标头确实是一个隐藏的宝石。已修复,谢谢。
    • 在这种情况下,任何人都可以将标头“x-forwarded-proto”设置为(使用类似邮递员的工具)https,但实际 url 为http,最终响应将是http。那么这样安全吗?
    【解决方案2】:

    您需要 2 个不同的 express app 对象来执行此操作。 Express 服务器的每个实例一次只能监听一个协议。这都可以在一个 node.js 进程中,但您需要 2 个配置不同的 express 服务器 app 实例,一个用于 http,另一个用于 https。例如,请参阅我的答案:

    How to force SSL / https in Express.js

    另请参阅:Automatic HTTPS connection/redirect with node.js/express?

    还请注意,您不应分配req.session.ssl。将其设置为 true 并不会神奇地使客户端连接到 TLS 而不是明文 HTTP。这是一个只读属性。分配它没有任何效果。

    您还应该注意,您不能在单个端口上同时运行 http 和 https。这就是为什么 http 使用 80 而 https 使用 443。

    当您收到Cannot GET /applyNow 错误时,这意味着您的快速路由从未与请求路径匹配,因此您的ensureSec 中间件从未被调用。

    【讨论】:

    • 我正在使用 Nginx。 Nginx 可以处理 http 和 https 连接,所以我可以从我的应用程序中卸载它。我只需要强制一些路径通过 ssl。
    • 同样,您需要 2 个不同的端口和 2 个不同的 express 应用实例。真的。这可以是一个 node.js 进程,你可以强制一些 http 路径重定向到 https,但是你不能同时在同一个端口上运行 2 个完全不同的协议,比如 http 和 https。这不是 node.js 的限制,而是协议的设计方式。
    • 彼得,据我了解,Rob 前面有一个 nginx 服务器,将请求代理到 node.js 服务器。因此,对于 express 应用程序,所有请求都将是 http。但是有些路径,Rob 不希望 express 服务器处理,除非它是一个 https 请求(到 nginx)。我建议改为在 nginx 中执行此操作,这似乎要简单得多。另外,我的理解是 Rob 使用 req.session.ssl 来跟踪客户端是否通过 https 连接,这看起来很不稳定(您需要在正确的情况下重置它)。
    • 啊,我误解了这个问题。
    • 谢谢,是的,会话值不稳定。
    【解决方案3】:

    您可以在 nginx 服务器上配置 ssl 端口,并像其他请求一样将请求代理到 node.js。

    http://nginx.org/en/docs/http/configuring_https_servers.html

    无需更改 node.js 应用程序。只需使用您的证书和对 node.js 应用程序的代理请求在 nginx 上配置 443 端口。

    【讨论】:

    • 谢谢。我已经这样做了。我只想保护某些路径。我想在节点应用程序而不是 nginx 中这样做。这样做会使部署更容易。
    【解决方案4】:

    补充一下 Peter Lyons 所说的,明确要求您在一个端口上只运行一个服务器。如果你尝试在一个端口上运行两个 http 服务器,它会抛出一个 EADDRINUSE 错误。

    【讨论】:

      【解决方案5】:

      如此处所述:http://elias.kg/post/14971446990/force-ssl-with-express-js-on-heroku-nginx,使用 Nginx,您可以利用“x-forwarded-proto”标头:

      function ensureSec(req, res, next){
          if (req.headers["x-forwarded-proto"] === "https"){
             return next();
          }
          res.redirect("https://" + req.headers.host + req.url);  
      });
      

      【讨论】:

        【解决方案6】:

        当您在前端使用 Nginx 时,实现此目的的最简洁和最简单的方法是将 Nginx 中的 http URL 转发(重写)到 HTTPS,而不是尝试在 Express 中重定向。这可以按如下方式完成:

        server {
          listen 12.34.56.78:80;
          server_name yourserver.com;
        
          location / {
              rewrite ^ https://$server_name$request_uri permanent;
          }
        }
        

        你可以用这一行重写:

        rewrite ^ https://ducklington.org$request_uri permanent;
        

        只需设置您的位置以匹配您需要转发到 https 的路由或规则。

        【讨论】:

          【解决方案7】:

          app.enable('信任代理');

          “在 Varnish 或 Nginx 等反向代理后面使用 Express 很简单,但它确实需要配置。通过 app.enable('trust proxy') 启用“信任代理”设置,Express 将知道它正在坐在代理之后,并且 X-Forwarded-* 标头字段可能是可信的,否则很容易被欺骗。”

          Express behind proxies doco

          【讨论】:

            猜你喜欢
            • 2021-10-15
            • 2017-02-12
            • 2014-12-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-06
            相关资源
            最近更新 更多