TIL 54일차

안광의·2021년 9월 6일
0

Today I Learned

목록 보기
54/64
post-thumbnail

시작하며

오늘은 지난주에 SQL 파트를 마치고 인증/보안 파트를 처음 시작하는 날이다. 이전에 학습했던 HTTP에 이어서 보안기능이 강화된 HTTPS를 학습하고 실제 서버와 클라이언트에서 HTTPS를 사용해서 Session 기능을 구현하는 스프린트를 진행하였다.

인증/보안

HTTPS

정의
HTTPS는 Hyper Text Transfer Protocol Secure Socket layer 의 약자로 HTTP 요청을 SSL 혹은 TLS라는 알고리즘을 이용해, HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송하는 방법이다.

인증에서 HTTPS 프로토콜을 사용해야만 하는 이유는 HTTP보다 상대적으로 안전한 방법이고, 데이터 제공자의 신원을 보장받을 수 있기 때문이다.

암호화
HTTPS 프로토콜의 특징 중 하나는 암호화된 데이터를 주고받기 때문에, 중간에 인터넷 요청이 탈취되더라도 그 내용을 알아볼 수 없다. HTTP 프로토콜은 요청 및 응답을 탈취한다면 프로그램을 이용하여 아래와 같이 해당 요청으로 전달되는 데이터의 내용을 확인할 수 있기 때문에 보안에 취약하다.

인증서
HTTPS 프로토콜의 또 다른 특징 중 하나는 브라우저가 응답과 함께 전달된 인증서 정보를 확인할 수 있다는 점이다. 브라우저는 인증서에서 해당 인증서를 발급한 CA 정보를 확인하고 인증된 CA가 발급한 인증서가 아니라면 화면에 경고창을 띄워 서버와 연결이 안전하지 않다는 화면을 보여준다.

이렇게 브라우저는 인증서의 도메인과 데이터를 제공한 제공자의 도메인을 비교할 수 있기 때문에 인증서의 도메인 정보와 데이터 제공자의 도메인 정보가 다른 '중간자 공격'을 감지하여 보안 위협으로부터 사용자 및 사용자의 데이터를 보호할 수 있다.

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

$ sudo apt install libnss3-tools
$ wget -O 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/

위 명령어로 mkcert을 설치한 후,

$ 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)에서 사용할 수 있는 인증서가 완성되고, cert.pem, key.pem 이라는 파일이 생성된 것을 확인할 수 있다.

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

위의 코드처럼 node.js의 https 모듈을 이용하여 인증서를 연결하여 서버를 실행하면 htps://localhost:3001로 접속했을때 브라우저의 url 창 왼쪽에 자물쇠가 잠겨있는 HTTPS 프로토콜을 이용한다는 것을 알 수 있다.



Hashing

정의
Hashing이란 어떠한 문자열에 임의의 연산을 적용하여 다른 문자열로 변환하는 것을 말하며, Client에서 Server로 전달한 데이터를 보안상의 이유로 원본 그대로 데이터베이스에 저장하지 않고 암호화하여 데이터베이스에 저장하는데 이때 hashing 과정을 거치게 된다.

Hashing의 조건

  • 해시 값을 계산하는데 오래걸리지 않아야 함
  • 모든 값은 고유한 해시 값을 가지며, 이 때 해시 값들은 최대한 서로 피해야 함
  • 아주 작은 단위의 변경이라도 완전히 다른 해시 값을 가져야 함

Salt
Salt란 암호화해야 하는 값에 어떤 별도의 값을 추가하여 변형하는 것을 말하며 원본 데이터를 그대로 해싱한다면 매번 동일한 결과가 반환되기 때문에 Salt를 추가하여 해싱을 진행함으로써 매번 전혀 다른 해시값을 반환하여 안전하게 해싱할 수 있다.

  • 기존 : (암호화 하려는 값) => (hash 값)
  • Salt 사용 : (암호화 하려는 값) + (Salt용 값) => (hash 값)

정의
쿠키는 서버에서 클라이언트에 데이터를 저장하는 방법의 하나로, 서버가 원한다면 서버는 클라이언트에서 쿠키를 이용하여 데이터를 가져올 수 있다. HTTP는 Stateless인데도 쇼핑사이트의 장바구니의 물건들이 유지되는 이유가 바로 Cookie를 사용하여 장바구니에 담은 아이템을 저장하기 때문이다.

Options

서버는 쿠키를 이용하여 데이터를 저장하고 원할 때 이 데이터를 다시 불러와 사용할 수 있지만 데이터를 저장한 이후 아무 때나 데이터를 가져올 수 없고, Cookie Options에 따라 특정 조건들이 만족하는 경우에만 다시 가져올 수 있다.

1. Domain
도메인은 서버에 접속할 수 있는 이름으로, 요청해야 할 URL이 http://www.localhost.com:3000/users/login이라 하면 Domain은 localhost.com이 됩다.

만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있다.

2. Path
세부 경로는 서버가 라우팅할 때 사용하는 경로로, 요청해야 하는 URL이 http://www.localhost.com:3000/users/login인 경우라면 여기에서 Path는 /users/login이 된다.

명시하지 않으면 기본으로 / 으로 설정되어 있고, Path 옵션의 특징은 설정된 path를 전부 만족하는 경우 요청하는 Path가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있다. 즉, path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/login인 경우라면 쿠키 전송이 가능하다.

3. MaxAge or Expires
쿠키가 유효한 기간을 정하는 옵션이다. MaxAge는 앞으로 몇 초 동안 쿠키가 유효한지 설정하는 옵션이고, Expires 은 MaxAge와 비슷하나, 언제까지 유효한지 Date를 지정한다.

클라이언트의 시간을 기준으로 하며, 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴된다.
하지만 두 옵션이 모두 지정되지 않는 경우에는 브라우저의 탭을 닫아야만 쿠키가 제거될 수 있다.

4. Secure
쿠키를 전송해야 할 때 사용하는 프로토콜에 따른 쿠키 전송 여부를 결정한다. 만약 해당 옵션이 true로 설정된 경우, 'HTTPS' 프로토콜을 이용하여 통신하는 경우에만 쿠키를 전송할 수 있다.

5. HttpOnly
자바스크립트에서 브라우저의 쿠키에 접근 여부를 결정한다. 만약 해당 옵션이 true로 설정된 경우, 자바스크립트에서는 쿠키에 접근이 불가능하다.

명시되지 않는 경우 기본으로 false로 지정되어 있으며, 만약 이 옵션이 false인 경우 자바스크립트에서 쿠키에 접근이 가능하므로 'XSS' 공격에 취약하다.

6. SameSite
Cross-Origin 요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정하게 된다.

  • Lax :Cross-Origin 요청이면 'GET' 메소드에 대해서만 쿠키를 전송할 수 있다.
  • Strict : Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있다.
  • None: 항상 쿠키를 보내줄 수 있으나, 쿠키 옵션 중 Secure 옵션이 필요하다.

이때 'same-site'는 요청을 보낸 Origin과 서버의 도메인이 같은 경우를 말한다.

이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티에 쿠키를 담아 쿠키를 전송하게 되며, 이후 클라이언트 혹은 서버에서 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송하게 된다.

Session

정의
Cookie와 비슷하게 Stateless한 HTTP를 Stateful하게 작동될 수 있게 해주는 기능으로, Cookie가 클라이언트에 데이터를 저장하는 방식이라면 Session은 실제 데이터를 데이터베이스에 저장하고 Client에는 Session의 id만 Cookie로 전달하는 방식이다.

Client에서 Session의 id를 전달받은 후 데이터베이스에서 해당하는 데이터를 관리하기 때문에 신뢰할 수 있는 유저인지 서버에서 추가로 확인이 가능하고 실제 데이터가 Client에게 전달되지도 않기 때문에 보안에 유리하다.

마치며

이전에 학습했던 내용은 기능 구현에 초점이 맞춰져 있어, 보안을 고려하면서 제 웹페이지가 작동하는지에 대해서 궁금했는데 오늘 챕터를 통해 어느정도 이해할 수 있었다. CSRF가 서버와 클라이언트 사이에 개입하여 위조된 요청을 보내게 하는 방식이라는 것을 알고 어떤 형태로 이를 대비할 수 있는지 https가 왜 생기게 되었고 왜 Session이란 방식으로 데이터를 관리하는 지 이해하는데 도움이 되었다. 스프린트로 서버와 클라이언트의 기능을 구현하면서 기존에 배웠던 fetch와 다르게 axios를 사용해서 요청, 응답을 구현하는 법도 배울 수 있었다.

profile
개발자로 성장하기

0개의 댓글