[Server] HTTPS의 개념과 인증서 발급 및 서버 구현

somin·2021년 9월 6일
5

server

목록 보기
7/13

HTTPS

  • HTTP + Secure(보안 기능) : HTTP 프로토콜 내용을 암호화
  • Hyper Text Transfer Protocol Secure Socket layer 의 약자로, HTTP over SSL(TLS), HTTP over Secure라고 부르기도 함
  • 내가 접속한 서버가 의도된 서버임을 보장하며 암호화된 채널을 제공
    *암호화된 채널: 무결성과 기밀성을 지켜줌

    무결성과 기밀성

    • 무결성(integrity) : 메시지가 조작되지 않음
      *메시지가 원본 그대로 잘 도착함을 의미
    • 기밀성(privacy) : 메시지를 가로챌 수 없음
      *메시지를 읽을수 없다. 즉, 암호화되어 있다를 의미

1. 개념

  • HTTP 요청을 SSL 혹은 TLS라는 알고리즘을 이용해 HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송하는 방법
    *중간에 인터넷 요청이 탈취되더라도 그 내용을 알아볼 수 없음
  • SSL(Secure Socket Layer): 보안 소켓 레이어로 Netscape에서 서버와 브라우저 간 보안을 위해 만든 프로토콜
    *HTTP 요청과 응답 데이터의 암호화가 이루어지며, 클라이언트가 접속한 서버가 신뢰 할 수 있는 서버임을 보장
  • TLS : SSL이 점차 폭넓게 사용되다가 표준화 기구인 IETF의 관리로 변경되면서 TLS라는 이름으로 바뀜
    *가장 최신 기술로 더 강력한 버전의 SSL을 의미하지만 SSL이 더 일반적으로 사용되는 용어
  • HTTP보다 상대적으로 안전한 방법이고, 데이터 제공자의 신원을 보장받을 수 있기 때문에 인증에서 HTTPS 프로토콜을 사용해야 함

데이터 제공자의 신원을 확인하고 보장받는 게 인증에서 중요한 이유

  1. 클라이언트는 데이터 제공자가 제공해준 데이터를 사용할 수밖에 없음
    • 클라이언트는 서버에 데이터 요청을 하고 이후 받은 데이터를 이용해서 화면을 렌더링하는 등의 작업을 수행
  2. 위의 이유로 클라이언트는 요청 및 응답을 중간에서 가로채는 중간자 공격에 취약
    • 중간자 공격 : 클라이언트와 서버 사이에서 공격자가 서로의 요청, 응답의 데이터를 탈취 및 변조하여 다시 전송하는 공격
  3. 중간자 공격 시 데이터가 중간에 다른 도메인을 거쳐서 전달되기 때문에 서버가 해당 데이터가 제공된 도메인에 대한 추가데이터를 응답객체에 실어 보냄
    • 중간자 공격으로 인해 다른 도메인에서 데이터를 받은 클라이언트는 데이터를 제공한 도메인과 전달받은 내용의 도메인을 비교하여 중간자 공격이 존재하는지 아닌지 확인할 수 있음
    • 중간자 공격으로 인한 추가 데이터 또한 변조할 수 있기 때문에 해당 데이터를 암호화시키는 작업이 필요

2. 특징

1) 인증서(Certificate)

  • 인증서 : 브라우저와 서버가 통신할 때 암호화할 수 있도록 서버의 공개 키 제공
    *참고자료
  • 데이터 제공자 신원 보장 : 데이터를 제공한 서버가 정말로 데이터를 보내준 서버인지 인증 및 확인
    *https://google.com : 내가 접속한 사이트가 진짜 google임을 보장
  • 도메인 종속 : 인증서의 내용에 서버의 도메인 관련 정보가 있어 데이터 제공자의 인증을 용이하게 함
  • 브라우저는 응답과 함께 전달된 인증서 정보를 확인할 수 있음
    *인증서의 도메인 정보와 데이터 제공자의 도메인 정보가 다른 중간자 공격을 감지하여 보안 위협으로부터 사용자 및 사용자의 데이터를 보호
  • 중간자 공격 인지 시 경고를 보여줌으로써 브라우저들은 인증된 CA가 발급한 인증서를 이용하여 데이터를 제공하는 안전한 서버를 사용할 수 있게 사용자를 유도

인증 과정

  1. 요청을 받으면 서버는 인증서와 함께 요청의 응답을 전송
  2. 응답을 받은 클라이언트는 인증서에 작성된 도메인과 응답 객체에 작성된 도메인을 비교
  3. 응답에서 확인한 도메인과 인증서에 작성된 도메인이 같다면 데이터를 보내준 서버가 확실하다는 것을 인지
  4. 중간자가 요청을 탈취해 서버인척, 클라이언트인척 정보를 탈취한 경우, 응답에서 확인한 도메인과 인증서에 작성된 도메인이 같지 않아 데이터를 보내준 서버가 맞는지 확신할 수 없게 됨

2) CA(Certificate Authority)

  • 인증서를 발급하는 공인된 기관
  • 각 브라우저는 각자 신뢰하는 CA의 정보를 가지고 있음
    *각 브라우저마다 인증서에 차이가 있음
  • CA의 자격은 계속 유지되는 것이 아니라, 자격을 박탈당할 수 도 있음
  • CA로부터 발급받은 인증서 : 공개 키는 브라우저에, 개인 키는 서버에 저장
    *CA는 몇군데 안되므로 리스트가 저장되어 있음
  • mkcert로 만든 임의의 인증서 : CA는 내 컴퓨터
    *CA 리스트에 없으므로 배포시 invalid 에러 발생

3) 비대칭 키 암호화

  • 암호화 : 복호화가 가능한 알고리즘을 사용
  • 비대칭 키 암호화 : 전혀 다른 키 한 쌍으로 암호화 및 복호화 가능
    *대칭 키 암호화 : 암호화와 복호화를 하는 키가 같음
  • HTTPS 프로토콜을 이용하는 서버는 한 쌍의 키 중에서 하나는 숨겨두고, 다른 하나는 클라이언트에 공개하여 데이터를 안전하게 전송할 수 있게 함
    *일반적으로 공개 키는 암호화, 비공개 키(개인 키)는 복호화에 사용
  • 모든 통신에 대해 공개 키 방식을 사용하지는 않음
    *공개 키 방식은 많은 클라이언트를 상대로 매번 사용하기에는 연산이 매우 복잡
  • 통신의 초창기에서만 비밀 키 생성을 목적으로 공개 키 방식 사용

통신 과정

  1. Hand Shake
    • 서로를 확인 후 서버는 클라이언트에게 한쌍의 키중 하나를 공개 키로 전달
  2. 비밀 키 생성
    • 클라이언트는 전달받은 키를 이용하여 서버와 키를 만들어낼 임의의 정보를 암호화하여 전송
    • 서버도 클라이언트와 마찬가지로 임의의 정보를 암호화하여 전송
    • 서로 만들고 교환한 임의의 정보를 마탕으로 비밀 키를 생성
  3. 상호 키 검증
    • 각자 생성한 키를 바탕으로 클라이언트가 테스트용 데이터를 만들어낸 비밀키로 암호화하여 전달
    • 서버도 만들어진 키를 바탕으로 복호화를 한 후 다시 암호화 하여 클라이언트로 전달
    • 클라이언트가 같은 내용의 데이터를 복호화하는 데 성공했다면 비밀 키 생성 성공
    • HTTPS 연결이 성립됨을 의미

사설 인증서 발급 및 HTTPS 서버 구현

mkcert라는 프로그램을 이용해서 로컬 환경(내 컴퓨터)에서 신뢰할 수 있는 인증서를 만들 수 있음

1. mkcert 설치

brew install mkcert

2. 인증서 생성

1) 로컬을 인증된 발급기관으로 추가

mkcert -install

2) 로컬 환경에 대한 인증서 만들기

mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1

  • localhost, 127.0.0.1(IPv4), ::1(IPv6)에서 사용할 수 있는 인증서가 완성
  • cert.pem, key.pem이라는 파일이 생성
  • cert.pem 파일의 경우 공개키와 인증기관의 서명을 포함하고 있는 인증서이기 때문에 공개되어도 상관이 없지만, key.pem의 경우 개인 키이므로 git에 커밋하지 않고 암호처럼 다루어야 함

3. HTTPS 서버 작성

  • 생성한 인증서 파일들을 HTTPS 서버에 적용해주는 작업이 필요
  • node.js 환경에서 HTTPS 서버를 작성하기 위해서는 https 내장 모듈을 이용하거나 express.js를 이용

1) node.js https 모듈 이용

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('Congrats! You made https server now :)');
      res.end();
    }
  )
  .listen(3001);
  • 서버를 실행한 후 https://localhost:3001로 접속
  • 브라우저의 url 창 왼쪽에 자물쇠가 잠겨있는 HTTPS 프로토콜을 이용한다는 것을 알 수 있음

2) express.js 이용

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('Congrats! You made https server now :)');
    })
  )
  .listen(3001);
  • express.js를 사용하는 경우, https.createServer의 두번째 파라미터에 들어갈 callback 함수를 Express 미들웨어로 교체

4. 기존에 구축한 서버를 HTTPS로 터널링 하기

  • ngrok 프로그램 이용

References

  1. SSL
profile
✏️

0개의 댓글