HTTPS 프로토콜
HTTPS(Hyper Text Transfer Protocol Secure Socket Layer)란 HTTP over SSL(TLS) 혹은 HTTP over Secure라고 불린다. HTTPS는 서버와 클라이언트 간 통신하는 과정에서 내용을 SSL || TLS 알고리즘을 사용, 암호화하여 데이터를 전송하는 방식이다. HTTPS는 비대칭 키를 사용한다.
SSL vs TLS
SSL(Secure Socket Layer)는 서버, 클라이언트 간 인증 및 암호화를 제공하는 프로토콜이다. 1995년 Netscape에 의해 개발되 최초 공개되었다. TLS(Transfer Layser Security)는 SSL 이후 출시되었고, SSL 표준화되면서 TLS이름으로 변경되었다.
기존 클라이언트 <--> 서버 통신에서 HTTP를 사용했지만 굳이 HTTPS를 사용해야 하는 이유는 데이터 제공자의 신원을 보장받기 위함이다. 데이터 제공자의 신원을 확인하지 못하는 경우 클라이언트는 중간자 공격을 당해 임의의 해커가 제공한 데이터를 화면에 렌더링 하게 된다. 보안에 취약한 UI가 생성되는 것이다. 해커는 중간에서 요청, 응답 데이터를 탈취/변조할 수 있게 된다.
중간자 공격을 방지하기 위한 간단한 아이디어는 데이터가 중간에 다른 도메인을 거쳐 제공된다는 점을 생각해서 https://xxx.com에서 데이터가 제공되었습니다.라는 데이터를 응답 객체에 실어보내 데이터 제공자와 중간 도메인이 일치하는지 여부를 검토함으로써 중간자 공격 여부를 확인할 수 있다. 중간자 공격해커는 도메인 정보를 변조할 수 있기 때문에 우리에게 필요한 작업은 이 응답 객체를 암호화하는 것이다.
암호화
HTTPS 프로토콜이 안전한 이유는 클라이언트 <---> 서버간 암호화된 데이터를 주고 받기 때문에 중간에 데이터가 탈취된다고 하더라도, 내용을 알아볼 수 없다는 점이다. 클라이언트에서 제공받는 유저의 로그인 정보가 암호화 되지 않은채 교환된다면 중간자 공격을 가하는 해커가 정보를 탈취하기 쉽다.
인증서
HTTPS 프로토콜의 두번째 특징은 클라이언트에서 서버로 부터 전송된 데이터에서 인증서 정보를 확인할 수 있다는 것이다. 클라이언트에서는 인증서 정보를 확인하고 인증서를 발급한 CA 정보를 동시에 확인한다. 만약 인증된 CA가 발급한 인증서가 아닌 경우 서버가 안전하지 않다는 경고 메세지를 띄울 수 있게 된다.
결국 클라이언트 단에서 서버로 부터 받은 데이터 중 인증서 정보를 확인하고 인증서의 도메인 정보와 데이터 제공자의 도메인 정보를 비교하여 중간자 공격을 감지하고 보안 이슈를 해결할 수 있게 되는 것이다. chrome에서도 HTTPS 프로토콜로 전송되지 않은 요청에 대해 경고창을 띄우고 안전한 HTTPS 프로토콜을 사용한 페이지로 유도하고 있는 것이다.
CA(Certificate Authority)
공인된 인증서를 발급하는 기관이다. 자격이 계속 유지되는 것이 아니라 박탈당할 수도 있기 때문에, 주기적으로 Key를 확인해야 한다.
HTTPS 연결 과정
HTTPS 에서는 비대칭키를 사용해서 통신을 성립한다.
① Hand Shake 단계 : 클라이언트의 요청에 서버는 공개키와 인증서 정보를 전달한다. 클라이언트는 CA정보와 공개키를 비교해서 서버가 적합한 인증을 받았는지 검증한다.
② 서버가 적합한 인증서를 가졌다면 클라이언트와 클라이언트는 서버로 부터 받은 공개키로 세션 키를 암호화한다. 세션 키를 암호호환 문자열이 서버로 전송된다. 서버는 비밀키를 가지고 세션키를 복호화한다. 여기서 부터 서버와 클라이언트는 세션키만(대칭키)을 가지고 문자열을 전송할 수 있게 된다.
③ 클라이언트는 세션키를 사용해 암호화된 문자열을 서버에 전송하고, 서버는 이를 세션키로 복호화 후 다시 세션 키로 암호화해 클라이언트에 전송한다. 클라이언트가 전달받은 암호화된 문자열을 성공적으로 복호화하면 HTTPS 연결이 성립된다.
HTTPS 사설 인증서 발급
HTTPS 서버를 구현하기 위해서는 인증서를 발급받아야 한다. 로컬환경에서 신뢰할 수 있는 인증서를 발급받기 위해서 mkcert 프로그램을 사용한다.
mkcert Ubuntu Install
$ sudo apt install libnss3-tools
$ wget -O mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-amd64
mksert를 설치하면 소유자와 소유그룹은 read와 write 권한이 주어진다. 공개유저는 read 권한만 주어진다. mkcert를 실행해야 하기 때문에 실행권한을 일괄적으로 부여한다.
$ chmod +x mkcert
현재 디렉토리에 위치한 mkcert를 /usr/local/bin에 등록해준다.
$ sudo cp mkcert /usr/local/bin
인증서 생성
로컬을 인증된 발급기관으로 추가한다.
$ mkcert -install
로컬 환경에 대한 인증서를 생성한다.
$ mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
localhost, 127.0.0.1(IPv4), ::1(IPv6)에서 사용가능한 인증서를 생성한다. key.pem, cert.pem이 생성되었고, 만기기한은 24년 9월 7일 까지로 지정되었다.(발급일로부터 3개월) 참고로 pem(Privacy Enhanced Mail)은 Base64 인코딩된 ASCII text File이다.
- key : 개인 혹은 공개 PKCS#8
- cert : 인증서를 나타내는 확장자
※ 여기서 주의해야 할 점은 인증서는 공개키와 인증기관 서명을 포함하고 있어 공개되어도 무방하지만 key.pem의 경우 개인 비밀키 이기 때문에 github에 커밋할 때 절대로 올려서는 안된다. pem이 공개되어 AWS에서 1000만원 이상 과금되는 사례가 적지않게 일어난다.
발급된 key.pem을 보면 장문의 암호화된 문자열이 기록되어 있다.
key.pem
cert.pem
HTTPS 서버에 인증서 적용
발급된 인증서를 서버에 적용하는 방법은 서버를 생성하고 key와 cert에 생성한 파일을 할당해주면 된다. Node.js 환경에서 HTTPS 서버를 생성하는 방법은 아래와 같다. 주의할 것은 미리 생성한 key.pem과 cert.pem을 프로젝트 디렉토리에 옮기고 사용권한을 644로 변경해줘야 한다.
프로젝트를 시작한다. package.json을 작성하고 Node.js 프로젝트를 시작한다. express를 설치해주고, 변경사항이 있을 때 서버가 자동으로 업데이트 되도록 nodemon을 설치해준다.
$ npm init
$ npm i express
$ npm i -D nodemon
Node.js server
const https = require('https');
const fs = require('fs');
https.createServer({
key : fs.readFileSync(__dirname + '/key.pem', 'utf-8'),
cert : fs.readFileSync(__dirname + '/cert.pem', 'utf-8'),
},
function(req, res){
res.write('Welcome HTTPS SERVER');
res.end();
}
).listen(4998);
express.js server
express를 사용할 경우 createServer 메서드 두번째 callback 인수에 미들웨어를 작성한다.
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
https.createServer({
key : fs.readFileSync(__dirname + '/key.pem', 'utf-8'),
cert : fs.readFileSync(__dirname + '/cert.pem', 'utf-8'),
},
app.use('/', (req, res)=>{
res.send("Welcome HTTPS Server");
})
).listen(4998);
Reference
'Programming' 카테고리의 다른 글
[Security] HTTP session이란 ? (session cookie 차이) (0) | 2022.06.07 |
---|---|
[Security] HTTP Cookie란? (0) | 2022.06.07 |
[회고록] 코드스테이츠 블록체인 부트캠프 국비 후기 (Digital Training 과정) (9) | 2022.06.07 |
[MongoDB] mongoexport / mongoimport / mongodump / mongorestore 사용법 (0) | 2022.06.03 |
[Redux] 리덕스 CRUD ! (0) | 2022.06.01 |
댓글