TIL [인증 / 보안] 기초

김은혁·2021년 8월 7일
0

HTTPS (HTTP + Secure)

HTTPS는 HTTP 프로토콜의 내용을 암호화하여 보완성을 추가했다. 기존 HTTP는 누군가 요청의 내용을 들여다보려 한다면 그대로 볼 수가 있었다. 그렇게 되면 중요한 정보가 쉽게 노출될 수 있을 것이다.

하지만 HTTPS는 요청의 내용을 암호화하기 때문에 정보가 유출되더라도 정확한 키가 없다면 어떤 내용인지 알 수 없고 데이터 제공자의 신원을 보장받을 수 있다.

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

  • 클라이언트는 데이터 제공자가 제공해준 데이터를 사용할 수밖에 없다.
  • 때문에 요청 및 응답을 중간에서 가로채는 중간자 공격에 취약

HTTPS 특징

  • 인증서 (Certificate)
    • 데이터 제공자 신원 보장
    • 도메인 종속
  1. 요청을 받으면 서버는 인증서와 함께 응답을 보냄.
  2. 응답을 받은 클라이언트는 인증서에 적힌 도메인과 응답 객체에 작성된 도메인을 비교.
  3. 같다면 ok
  • CA (Certificate Authority)

    • 공인 인증서 발급 기관
  • 비대칭 키 암호화 (공개키 암호화)

    • 키 A로 암호화 => 키 B로만 복호화 가능 !

  1. Hand Shake 에서는 서로를 확인하고 서버는 클라이언트의 공개키 한 쌍 중 하나를 전달.

  2. 클라이언트는 전달받은 키를 이용해서 서버와 키를 만들어낼 임의의 정보를 암호화해서 전달

  3. 서버는 클라이언트와 마찬가지로 임의의 정보를 암호화해서 전달

  4. 클라이언트와 서버는 서로 만들고 교환한 임의의 정보를 바탕으로 비밀 키 생성

  5. 각자 생성한 키를 바탕으로 클라이언트가 텍스트용 데이터를 만들어낸 비밀키로 암호화를 해서 전달

  6. 서버 역시 만들어진 비밀키로 복호화를 하고 다시 암호화해서 클라이언트로 전달

  7. 클라이언트가 같은 내용의 데이터를 복호화하는데 성공한다면 성공적으로 비밀키가 만들어진 상태. (HTTPS 연결 성립)

HTTPS 사설 인증서 발급

mkcert라는 프로그램을 이용하여 로컬 환경에서 신뢰할 수 있는 인증서 발급 가능.

Ubuntu
$ sudo apt install libnss3-tools
$ wget -0 mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-amd64
chmod +x mkcert
sudo cp mkcert /usr/local/bin/

macOS
$ brew install mkcert
$brew install nss

인증서 생성
$ mkcert -install
로컬을 인증된 발급기관으로 추가

$ mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
로컬 환경에 대한 인증서 만들기

=> cert.pem, key.pem 파일 생김.
(key.pem의 경우 개인 키이므로 git에 커밋하지 않고 암호처럼 다룸)

HTTPS 서버 작성

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

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

암호화 (Encryption)

일련의 정보를 임의의 방식을 사용하여 다른 형태로 변환하여 해당 방식에 대한 정보를 소유한 사람을 제외하고 이해할 수 없도록 '알고리즘'을 이용해 정보를 관리하는 과정

Hashing

어떠한 문자열에 '임의의 연산'을 적용하여 다른 문자열로 변환하는 것

철칙
1. 모든 값에 대해 해시 값을 계산하는데 오래 걸리지 않아야 한다.
2. 최대한 해시 값을 피해햐 하며, 모든 값은 고유한 해시 값을 가진다.
3. 아주 작은 단위의 변경이라도 완전히 다른 해시 값을 가져야 한다.

Salt

암호화해야 하는 값에 어떤 '별도의 값'을 추가하여 결과를 변형하는 것

  1. 암호화만 해놓는다면 해시된 결과가 동일
    (해시된 값과 원래 값을 테이블로 만들어서 디코딩하면 위험)
  2. 원본값에 임의로 약속된 '별도의 문자열'을 추가하여 해시를 진행한다면 기존 해시값과 전혀 다른 해시값이 반환되어 알고리즘이 노출되더라도 원본값 보호 가능
  3. 기존 : (암호화 하려는 값) => (hash 값)
    Salt 사용 : (암호화 하려는 값) + (Salt) => (hash 값)

Salt 사용 시 주의점
1. Salt는 유저와 패스워드 별로 유일한 값을 가져야 함
2. 사용자 계정을 생성할 때와 비밀번호를 변경할 때마다 새로운 임의의 Salt를 사용해서 해싱해야 함
3. 재사용하면 절대 안 됨.
4. DB의 유저 테이블에 같이 저장되어야 함.


HTTP는 stateless인데 어떻게 정보가 유지되는가? => 쿠키

어떤 웹사이트에 들어갔을 때, 서버가 일방적으로 클라이언트에 전달하는 작은 데이터

  • 서버가 웹 브라우저에 정보를 저장하고 불러올 수 있는 수단
  • 해당 도메인에 대해 쿠키가 존재하면, 웹 브라우저는 도메인에게 http 요청 시 쿠키를 함께 전달
  • 사용자 선호, 테마 등 장시간 보존해야하는 정보 저장에 적합 (로그인 상태 유지 등)

이러한 쿠키의 특성을 이용하여 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 요청과 같이 전송하여 Stateless한 인터넷 연결을 Stateful하게 유지할 수 있다.

하지만 쿠키는 오랜 시간 유지될 수 있고, JS를 통해 접근 가능하기 때문에 쿠키에 민감 정보를 담는 것은 위험

쿠키 전달 방법

쿠키 옵션

  • Domain : 서버와 요청의 도메인이 일치하는 경우 쿠키 전송
  • Path : 서버와 요청의 세부경로가 일치하는 경우 쿠키 전송
  • MaxAge of Expires : 쿠키의 유효기간 설정
  • HttpOnly : 스크립트의 쿠키 접근 가능 여부 결정
  • Secure : HTTPS 프로토콜에서만 쿠키 전송 여부 결정
  • SameSite : CORS 요청의 경우 옵션 및 메서드에 따라 쿠키 전송 여부 결정

0개의 댓글