cert: fs.readFileSync("/디렉토리/xxxx.crt" 도메인정보 로 여겨짐)
};
//위에서 생성한 옵션을 넘겨서 https 서버를 생성하한다.
var httpsServer = https.createServer( https_options, function(request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
//포트설정
httpsServer.listen(8887);
//ws 모듈이 내부적으로 없을경우 설치
var WebSocketServer = require('ws').Server;
//웹소켓 서버 생성
var wss = new WebSocketServer({
server: httpsServer,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
}
wss.on('connection', function connection(ws) {
//.수신처리
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
// 발신
ws.send('something');
});
일반 http 프로토콜 기반 웹소켓 서버를 생성하는것과 그렇게 큰차이는 없다.
그치만 ssl에 대한 기본 적인 개념이 없다면 아마 막히는 부분이 많을 것이다.
ssl 통신.
클라이언트 측에서 https://aaa.com 요청을 보내면
1. aaa.com 도메인에 연결된 웹서버에서 인증서 정보화 공개키 정보를 담아서 클라이언트에게 전달한다.
2. 전달받은 클라이언트는 브라우저 내부적으로 인증기관정보 및 도메인 정보를 가지고 신뢰할수 있는 도메인 유무를 확인후 랜덤으로 생성 한 대칭키를 클라이언트에게 전달한다.
3. 클라이언트는 전달받은 대칭키로 데이터및 url 을 암호화 하고 대칭키를 처음에 서버로부터 받은 공개키로 또 암호화를해서 서버로 데이터를 전송한다.
4. 서버는 받은 대칭키를 개인키로 복호화하고 복호화된 대칭키로 데이터를 다시 복호화 한다.
5. 서버에서 데이터 전송시 데이터를 개인키로 암호화후 전송한고 클라이언트는 공개키로 복호화한다.
예를들면 aaa.com 에 적용된 ssl 인증서 정보로 wss://아이피:포트 웹소켓서버에 ssl을 동일 하게 적용해도 인증업체에 도메인 등록이 되어있지 않으면 통신이 불가능 하다. 따라서 인증업체에 도메인 추가를 한후 다시 인증서를 받아서 처리하거나(그다지 추천하는 방식은아님) ssl 터널링 기술을 이용해야한다.
=======================
=======================
=======================
출처: http://leelsm.tistory.com/2
1. 프로세스
(1) 서버가 실행되면서 websocket 준비
- setAllowedOrigins("*") 을 작성해야 wss 통신 가능
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
메인 웹페이지 자체가 https라면 모든 api 요청, 이미지 로딩, 웹소켓 등에도 동일하게 SSL이 적용되어야 합니다. 웹소켓은 wss, 다른 모든 요청은 https가 되겠지요.
https를 사용하는 이유가 세션 쿠키나 api 토큰 등 민감한 정보가 노출되지 않도록 하기 위해서인데, http를 사용하는 api 요청이나 웹소켓이 단 한 개라도 있다면 거기에 접속할 때 세션 쿠키나 토큰이 노출될 테니 https를 쓰는 의미가 없어집니다. 그래서 최근 브라우저들은 mix content 발생시 이미지 외에는 아예 접속 시도조차 하지 않습니다. (원칙적으로는 이미지도 로딩하면 안되지만, 다 깨져보인다고 사용자들이 너무 싫어해서 타협한 것 같습니다.)
nginx에 이미 https를 세팅해 두셨을 테니 무조건 거기로 접속하시면 됩니다. 웹소켓도 https로 일단 nginx에 접속한 후 /socket.io/ 등 일부 경로만 proxy_pass로 실제 포트에 넘겨주도록 설정하면 인증서 하나로 일괄 적용 가능하고, 별도의 포트를 외부에 노출시킬 필요가 없으니 웹소켓 주소도 훨씬 깔끔해집니다.
답변 감사합니다! 궁금한게 하나 더 있는데요, 웹앱을 제공해주는 클라이언트 서버에는 nginx에 https를 적용 해 둔 상태인데, api, socket 통신을 제공하는 백엔드 서버에는 아직 적용을 안한 상태입니다. (즉, 아직 https -> http 로 api, socket이 mixed content 오류로 request가 불가능한 상태입니다)
저는 똑같이 api, 웹소켓에도 동일하게 SSL이 적용되어야 한다는 말씀을 백엔드 서버에도 nginx를 설치하고 인증서 발급 및 https 등록 (letsencrypt라는 무료 CA를 사용하였습니다), 그리고 nginx 설정 파일에서 proxy_pass 설정을 하면 된다는 것으로 이해 했는데 이것이 맞나요? (백엔드에도 똑같이 https를 적용해서 https -> https가 가능케 하도록)
그리고 인증서 하나로 일괄 적용이라는 부분은 이해가 가지 않습니다 ㅠ 클라이언트 서버에 발급했던 인증서를 백엔드 서버에서 https 적용 할 때 동일한 인증서로 재사용이 가능하다는 말씀이신가요?
헉! 감사합니다 클라이언트 서버는 제가 잘못 말씀드린 것 같네요 react app을 포함한 bundle.js를 index.html과 같이 제공해주기 위해서 따로 node.js를 돌리고 있는 서버를 뜻하는 거였습니다.
이런 웹앱(bundle.js)을 제공해주는 도메인을 A.com 이라고 하면 api는 B.com/api/... 로 구성되어 있는데요 api request를 https://A.com/ 인 ssl이 적용된 클라이언트단에서 http://B.com/api/... 인 서버로 요청하고 있는 상태입니다.
https, wss 요청을 받아서 http, ws로 요청하도록 하게 하는 작업(proxy)을 해줘야 한다는것으로 이해했습니다만 nginx가 설치된 서버(https://A.com)에 proxy_pass 설정을 하면 B주소로 api request를 할 때 그러한 처리를 자동으로 해준다는 것이 제대로 이해 한 것인가요?
네, 웹앱을 제공하고 계신 (SSL 인증서가 설치되어 있는) A.com 서버가 "앞단"입니다. 브라우저 또는 어플에서는 백엔드 주소로 직접 요청하지 않는다는 것이 핵심이고요.
백엔드 주소는 SSL을 지원하지 않거나, 만약 지원하더라도 nginx에서 사용하는 인증서를 node.js에 갖다 붙이고 갱신할 때마다 매번 재설정하려면 매우 귀찮아지기 때문에 브라우저 또는 어플과의 모든 통신은 nginx가 전담하는 구조로 바꾸셔야 합니다.
제가 말씀드린 것은 A.com과 B.com을 모두 "앞단" 서버로 연결한 후 앞단 서버에서 백엔드 서버로 proxy_pass해주는 방법인데요. 브라우저 또는 어플과 앞단 서버 사이에서 사용하는 프로토콜(https, wss)과 앞단 서버와 백엔드 서버 사이에서 사용하는 프로토콜(http, ws)은 전혀 달라도 무방합니다. proxy_pass 설정만 잘 하시면 됩니다.
단, 위의 답변은 도메인이 같을 거라고 추정해서 말씀드렸던 거고요, 도메인이 다르다면 B.com 서버에 nginx를 설치하고 SSL 인증서를 구해서 위와 같은 방법으로 proxy_pass로 구현하셔도 무방합니다. 같은 서버에 nginx가 있으면 다른 서버로 proxy_pass하는 것보다는 성능이 좋아지니까요.
물론 이 경우에도 nginx를 거치면서 프로토콜이 변경되는 것은 마찬가지고요.
양쪽 중 어떤 방법을 쓰더라도 일단 nginx가 요청을 받아서 넘겨준다는 원리는 동일합니다.
만약 B.com에서 api 및 웹소켓 구동을 위해 사용하시는 것이 node.js라면 https/wss를 http/ws로 바꿔야 하니 nginx를 거쳐서 proxy하는 것이 좋겠고요. 반면, 만약 이미 nginx를 거치도록 되어 있다면 거기에 https만 설치하시면 되겠습니다.
넵. 앞단 A에는 node.js 사용으로 웹앱만 제공하도록 했고 백엔드 서버라고 말한 B에는 rest api와 소켓 구현이 되어있고 동일하게 node.js를 사용하였습니다. (따로 거쳐서 가는 것이 아니라 B 내부에서 db를 조회한다던가, socket emit을 한다던가.. 등이 구현이 모두 되어있습니다) 제가 그래서 구조가 좀 이해가 안갔던 것 같네요..
이 경우에는 B에 https 환경을 세팅하면 A로 부터 B로 바로 https -> https 요청이 가능하기 때문에 프록시 설정이 필요 없지 않냐는 질문이었습니다..!
아니면 node.js 환경에서 사용하려면 https/wss로 들어온 요청을 http/ws로 변경을 해주어야 하는 것인가요?
node.js에서 https와 wss를 직접 처리할 수도 있습니다만, 권장하지는 않습니다. 게다가 2개의 어플리케이션이 돌아가고 있다면 (rest api + websocket) 두 군데 따로 인증서를 설정해 줘야 할 가능성이 높기 때문에 그냥 nginx를 앞에다 붙이고 proxy해주는 것이 유지보수하기 편합니다. 성능에는 거의 영향이 없고, 보안면에서도 이쪽이 유리하고요.
메인 웹페이지 자체가 https라면 모든 api 요청, 이미지 로딩, 웹소켓 등에도 동일하게 SSL이 적용되어야 합니다. 웹소켓은 wss, 다른 모든 요청은 https가 되겠지요.
https를 사용하는 이유가 세션 쿠키나 api 토큰 등 민감한 정보가 노출되지 않도록 하기 위해서인데, http를 사용하는 api 요청이나 웹소켓이 단 한 개라도 있다면 거기에 접속할 때 세션 쿠키나 토큰이 노출될 테니 https를 쓰는 의미가 없어집니다. 그래서 최근 브라우저들은 mix content 발생시 이미지 외에는 아예 접속 시도조차 하지 않습니다. (원칙적으로는 이미지도 로딩하면 안되지만, 다 깨져보인다고 사용자들이 너무 싫어해서 타협한 것 같습니다.)