source

자동 HTTPS 연결/node.js/express를 사용한 리디렉션

factcode 2023. 6. 3. 08:47
반응형

자동 HTTPS 연결/node.js/express를 사용한 리디렉션

저는 제가 작업하고 있는 node.js 프로젝트로 HTTPS를 설정하려고 노력해 왔습니다.이 예에서는 기본적으로 node.js 문서를 따릅니다.

// curl -k https://localhost:8000/
var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(8000);

이제, 내가 할 때

curl -k https://localhost:8000/

알겠습니다

hello world

역시하지만 내가 한다면,

curl -k http://localhost:8000/

알겠습니다

curl: (52) Empty reply from server

돌이켜보면 이런 식으로 작동할 것이 분명해 보이지만, 동시에 제 프로젝트를 방문하는 사람들은 https://yadayada를 입력하지 않을 것이며, 사이트를 방문하는 순간부터 모든 트래픽이 https가 되기를 바랍니다.

지정되었는지 여부에 관계없이 노드(및 Express가 내가 사용하는 프레임워크)가 모든 수신 트래픽을 https로 넘겨주도록 하려면 어떻게 해야 합니까?이 문제를 다룬 문서를 찾을 수 없었습니다.아니면 운영 환경에서 노드 앞에 이러한 리디렉션을 처리하는 무언가(예: nginx)가 있다고 가정하는 것입니까?

이것은 제가 웹 개발에 처음으로 진출한 것이므로, 이것이 명백한 것이라면 저의 무지를 용서해 주십시오.

라이언, 올바른 방향을 알려줘서 고마워요.저는 당신의 답변(2번째 단락)에 코드를 조금 더 추가했고 그것은 작동합니다.이 시나리오에서는 다음 코드 스니펫이 내 익스프레스 앱에 저장됩니다.

// set up plain http server
var http = express();

// set up a route to redirect http to https
http.get('*', function(req, res) {  
    res.redirect('https://' + req.headers.host + req.url);

    // Or, if you don't want to automatically detect the domain name from the request header, you can hard code it:
    // res.redirect('https://example.com' + req.url);
})

// have it listen on 8080
http.listen(8080);

https express 서버는 3000에서 ATM을 수신합니다.노드가 루트로 실행되지 않도록 iptables 규칙을 설정했습니다.

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000

다 합쳐서, 이건 제가 원하는 대로 작동합니다.

HTTP를 통한 쿠키 도난을 방지하려면 다음 답변(댓글 참조)을 참조하거나 다음 코드를 사용합니다.

const session = require('cookie-session');
app.use(
  session({
    secret: "some secret",
    httpOnly: true,  // Don't let browser javascript access cookies.
    secure: true, // Only use cookies over https.
  })
);

이 남자 덕분에: https://www.tonyerwin.com/2014/09/redirecting-http-to-https-with-nodejs.html

안전한 경우 https를 통해 요청하고 그렇지 않으면 https로 리디렉션합니다.

app.enable('trust proxy')
app.use((req, res, next) => {
    req.secure ? next() : res.redirect('https://' + req.headers.host + req.url)
})

HTTP가 기본적으로 포트 80을 시도하고 HTTPS가 기본적으로 포트 443을 시도하기 때문에 기존 포트를 따르는 경우 동일한 컴퓨터에 두 개의 서버를 둘 수 있습니다.코드는 다음과 같습니다.

var https = require('https');

var fs = require('fs');
var options = {
    key: fs.readFileSync('./key.pem'),
    cert: fs.readFileSync('./cert.pem')
};

https.createServer(options, function (req, res) {
    res.end('secure!');
}).listen(443);

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

https로 테스트:

$ curl https://127.0.0.1 -k
secure!

http 포함:

$ curl http://127.0.0.1 -i
HTTP/1.1 301 Moved Permanently
Location: https://127.0.0.1/
Date: Sun, 01 Jun 2014 06:15:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked

자세한 정보: 동일한 포트를 통한 Nodejs HTTPHTTPS

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);  
}

0.4.12 현재 Node의 HTTP/HTTPS 서버를 사용하여 동일한 포트에서 HTTP 및 HTTPS를 수신할 수 있는 실질적인 방법은 없습니다.

일부 사용자는 노드의 HTTPS 서버(Express.js에서도 작동함)가 443(또는 일부 다른 포트)을 수신하도록 하고 작은 http 서버를 80에 바인딩하여 사용자를 보안 포트로 리디렉션하여 이 문제를 해결했습니다.

단일 포트에서 두 프로토콜을 모두 처리할 수 있어야 하는 경우 nginx, lighttpd, apache 또는 다른 웹 서버를 해당 포트에 배치하고 노드의 역방향 프록시 역할을 수행해야 합니다.

나는 Basarat에서 제안한 솔루션을 사용하지만 HTTP와 HTTPS 프로토콜을 위해 2개의 서로 다른 포트를 가지고 있었기 때문에 포트를 덮어써야 합니다.

res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });

또한 루트 권한 없이 nodejs를 시작할 수 있도록 표준 포트가 아닌 포트를 사용하는 것을 선호합니다.저는 8080과 8443을 좋아합니다. 왜냐하면 저는 Tomcat에서 여러 해 동안 프로그래밍을 해왔기 때문입니다.

나의 완전한 파일은

var fs = require('fs');
var http = require('http');
var http_port    =   process.env.PORT || 8080; 
var app = require('express')();

// HTTPS definitions
var https = require('https');
var https_port    =   process.env.PORT_HTTPS || 8443; 
var options = {
   key  : fs.readFileSync('server.key'),
   cert : fs.readFileSync('server.crt')
};

app.get('/', function (req, res) {
   res.send('Hello World!');
});

https.createServer(options, app).listen(https_port, function () {
   console.log('Magic happens on port ' + https_port); 
});

// Redirect from http port to https
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
    console.log("http request, will go to >> ");
    console.log("https://" + req.headers['host'].replace(http_port,https_port) + req.url );
    res.end();
}).listen(http_port);

그런 다음 HTTP 및 HTTPS 포트에서 80 및 443 트래픽 포워드에 iptable을 사용합니다.

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8443

express-force-https 모듈을 사용할 수 있습니다.

npm install --save express-force-https

var express = require('express');
var secure = require('express-force-https');

var app = express();
app.use(secure);

저는 express를 사용할 때 req.protocol이 작동한다는 것을 발견했습니다(없이 테스트하지는 않았지만 작동하는 것으로 의심됩니다).현재 노드 0.10.22와 express 3.4.3 사용

app.use(function(req,res,next) {
  if (!/https/.test(req.protocol)){
     res.redirect("https://" + req.headers.host + req.url);
  } else {
     return next();
  } 
});

Express 4.0에서 작동하려면 이 답변을 업데이트해야 합니다.별도의 http 서버를 작동시키는 방법은 다음과 같습니다.

var express = require('express');
var http = require('http');
var https = require('https');

// Primary https app
var app = express()
var port = process.env.PORT || 3000;
app.set('env', 'development');
app.set('port', port);
var router = express.Router();
app.use('/', router);
// ... other routes here
var certOpts = {
    key: '/path/to/key.pem',
    cert: '/path/to/cert.pem'
};
var server = https.createServer(certOpts, app);
server.listen(port, function(){
    console.log('Express server listening to port '+port);
});


// Secondary http app
var httpApp = express();
var httpRouter = express.Router();
httpApp.use('*', httpRouter);
httpRouter.get('*', function(req, res){
    var host = req.get('Host');
    // replace the port in the host
    host = host.replace(/:\d+$/, ":"+app.get('port'));
    // determine the redirect destination
    var destination = ['https://', host, req.url].join('');
    return res.redirect(destination);
});
var httpServer = http.createServer(httpApp);
httpServer.listen(8080);

앱이 신뢰할 수 있는 프록시(예: AWS ELB 또는 올바르게 구성된 nginx) 뒤에 있으면 이 코드가 작동해야 합니다.

app.enable('trust proxy');
app.use(function(req, res, next) {
    if (req.secure){
        return next();
    }
    res.redirect("https://" + req.headers.host + req.url);
});

주의:

  • 여기에서는 80 및 443에서 사이트를 호스팅하고 있다고 가정합니다. 그렇지 않은 경우 리디렉션할 때 포트를 변경해야 합니다.
  • 또한 프록시에서 SSL을 종료하는 것으로 가정합니다.SSL을 엔드 투 엔드로 사용하는 경우 위의 @basarat의 답변을 사용합니다.엔드 투 엔드 SSL이 더 나은 솔루션입니다.
  • app.enable('trust proxy')을 사용하면 express에서 X-Forwarded-Proto 헤더를 확인할 수 있습니다.

"net" 모듈을 사용하여 동일한 포트에서 HTTP 및 HTTPS를 수신할 수 있습니다.

var https = require('https');
var http = require('http');
var fs = require('fs');

var net=require('net');
var handle=net.createServer().listen(8000)

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(handle);

http.createServer(function(req,res){
  res.writeHead(200);
  res.end("hello world\n");
}).listen(handle)

여기서 대부분의 답변은 req.header를 사용할 것을 제안합니다.호스트 헤더.

Host 헤더는 HTTP 1.1에 필요하지만 실제로는 HTTP 클라이언트가 헤더를 보내지 않을 수 있기 때문에 선택 사항이며 node/express에서 이 요청을 수락합니다.

어떤 HTTP 클라이언트(예: 브라우저)가 해당 헤더가 누락된 요청을 보낼 수 있습니까?라고 물어볼 수 있습니다.HTTP 프로토콜은 매우 사소한 것입니다.호스트 헤더를 보내지 않도록 HTTP 요청을 몇 줄의 코드로 작성할 수 있으며, 잘못된 형식의 요청을 수신할 때마다 예외를 발생시키고 이러한 예외를 처리하는 방법에 따라 서버가 다운될 수 있습니다.

따라서 항상 모든 입력의 유효성을 검사해야 합니다.이것은 편집증이 아닙니다. 서비스에서 호스트 헤더가 부족한 요청을 받았습니다.

또한 URL을 문자열로 처리하지 마십시오.노드 URL 모듈을 사용하여 문자열의 특정 부분을 수정합니다.URL을 문자열로 처리하는 것은 여러 가지 방법으로 이용할 수 있습니다.하지 마세요.

var express = require('express');
var app = express();

app.get('*',function (req, res) {
    res.redirect('https://<domain>' + req.url);
});

app.listen(80);

이것은 우리가 사용하는 것이고 그것은 매우 효과적입니다!

이것은 저에게 효과가 있었습니다.

app.use(function(req,res,next) {
    if(req.headers["x-forwarded-proto"] == "http") {
        res.redirect("https://[your url goes here]" + req.url, next);
    } else {
        return next();
    } 
});

페이지를 로드하는 동안 이 스크립트는 URL 페이지를 저장하고 주소가 https인지 http인지 확인합니다.http인 경우 스크립트가 자동으로 동일한 https 페이지로 리디렉션합니다.

(function(){
  var link = window.location.href;
  if(link[4] != "s"){
    var clink = "";
    for (let i = 4; i < link.length; i++) {
      clink += link[i];
    }
    window.location.href = "https" + clink;
  }
})();

두 개의 Node.js 서버(HTTP 및 HTTPS용 하나)를 인스턴스화할 수 있습니다.

또한 두 서버가 모두 실행하는 설정 기능을 정의하여 중복된 코드를 많이 작성할 필요가 없습니다.

제가 한 방법은 다음과 같습니다. (restify.js를 사용하지만 express.js 또는 노드 자체에 대해서도 작동해야 합니다.)

http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https/

제이크의 답변 코드가 업데이트되었습니다.https 서버와 함께 실행합니다.

// set up plain http server
var express = require('express');
var app = express();
var http = require('http');

var server = http.createServer(app);

// set up a route to redirect http to https
app.get('*', function(req, res) {
  res.redirect('https://' + req.headers.host + req.url);
})

// have it listen on 80
server.listen(80);

이 기능은 익스프레스와 함께 사용할 수:

app.get("*",(req,res,next) => {
    if (req.headers["x-forwarded-proto"]) {
        res.redirect("https://" + req.headers.host + req.url)
    }
    if (!res.headersSent) {
        next()
    }
})

모든 HTTP 처리기 앞에 놓습니다.

이것은 저에게 효과가 있었습니다.

/* Headers */
require('./security/Headers/HeadersOptions').Headers(app);

/* Server */
const ssl = {
    key: fs.readFileSync('security/ssl/cert.key'),
    cert: fs.readFileSync('security/ssl/cert.pem')
};
//https server
https.createServer(ssl, app).listen(443, '192.168.1.2' && 443, '127.0.0.1');
//http server
app.listen(80, '192.168.1.2' && 80, '127.0.0.1');
app.use(function(req, res, next) {
    if(req.secure){
        next();
    }else{
        res.redirect('https://' + req.headers.host + req.url);
    }
});

https로 리디렉션하기 전에 헤더를 추가하는 것이 좋습니다.

이제, 당신이 할 때:

curl http://127.0.0.1 --include

다음을 얻을 수 있습니다.

HTTP/1.1 302 Found
//
Location: https://127.0.0.1/
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 40
Date: Thu, 04 Jul 2019 09:57:34 GMT
Connection: keep-alive

Found. Redirecting to https://127.0.0.1/

고속 4.17.1을 사용합니다.

이 아이디어는 수신 요청이 https로 이루어졌는지 확인하는 것입니다. 그렇다면 다시 https로 리디렉션하지 말고 평소와 같이 계속 진행하십시오.그렇지 않으면 http인 경우 https를 추가하여 리디렉션합니다.

app.use (function (req, res, next) {
  if (req.secure) {
          next();
  } else {
          res.redirect('https://' + req.headers.host + req.url);
  }
});

http에서 https로 완벽하게 리디렉션하기 위한 오랜 연구 끝에 완벽한 솔루션을 찾았습니다.

const http = require("http");
const https = require("https");

const { parse } = require("url");
const next = require("next");
const fs = require("fs");

const ports = {
http: 3000,
https: 3001
}

const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();

const httpsOptions = {
key: fs.readFileSync("resources/certificates/localhost-key.pem"),
cert: fs.readFileSync("resources/certificates/localhost.pem")
};

// Automatic HTTPS connection/redirect with node.js/express
// source: https://stackoverflow.com/questions/7450940/automatic-https- 
connection-redirect-with-node-js-express
app.prepare().then(() => {

// Redirect from http port to https
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(ports.http, ports.https) + req.url });
    console.log("http request, will go to >> ");
    console.log("https://" + req.headers['host'].replace(ports.http, ports.https) + req.url);
    res.end();
}).listen(ports.http, (err) => {
    if (err) throw err;
    console.log("ready - started server on url: http://localhost:" + ports.http);
});

https.createServer(httpsOptions, (req, res) => {
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
}).listen(ports.https, (err) => {
    if (err) throw err;
    console.log("ready - started server on url: https://localhost:" + ports.https);
});
});

이 경우 포트도 변경하고 두 포트를 모두 수신해야 합니다.

appr.get("/", (req, res) => {
  res.redirect('https://' + req.headers['host'].replace(PORT, PORTS) + req.url);
});

IIS에 노드 응용 프로그램을 설치하는 경우 web.config에서 이 작업을 수행할 수 있습니다.

<configuration>
    <system.webServer>

        <!-- indicates that the hello.js file is a node.js application 
    to be handled by the iisnode module -->

        <handlers>
            <add name="iisnode" path="src/index.js" verb="*" modules="iisnode" />
        </handlers>

        <!-- use URL rewriting to redirect the entire branch of the URL namespace
    to hello.js node.js application; for example, the following URLs will 
    all be handled by hello.js:
    
        http://localhost/node/express/myapp/foo
        http://localhost/node/express/myapp/bar
        -->
        <rewrite>
            <rules>
                <rule name="HTTPS force" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="^OFF$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
                </rule>
                <rule name="sendToNode">
                    <match url="/*" />
                    <action type="Rewrite" url="src/index.js" />
                </rule>
            </rules>
        </rewrite>

        <security>
            <requestFiltering>
                <hiddenSegments>
                    <add segment="node_modules" />
                </hiddenSegments>
            </requestFiltering>
        </security>

    </system.webServer>
</configuration>

언급URL : https://stackoverflow.com/questions/7450940/automatic-https-connection-redirect-with-node-js-express

반응형