30.[Backend] 인증 / 보안

문도연·2022년 7월 14일
1
  • HTTPS의 작동방식과 여러 인증방식을 중점으로 학습한다.
  • HTTP의 무상태성을 유지하면서 각각의 유저에 대한 인증 및 권한을 확인할 수 있는 여러 인증 방식에 대해 학습한다.

Chapter1. 웹 인증/보안
Chapter1-1. HTTPS
Chapter1-2. Hashing
Chapter2. Cookie / Session
Chapter2-1. Cookie
Chapter2-2. Session
과제1 - Auth Basic
Chapter3. 웹 공격의 종류
Chapter4. Token / OAuth
Chapter4-1. Token
Chapter4-2. OAuth
과제2 - Auth Token
과제3 - Auth OAuth 2.0


Chapter1. 웹 인증/보안

  • 왜 HTTPS가 HTTP보다 안전한 지 이해한다.
  • HTTPS의 암호화 방식에 대해 이해한다.
  • HTTPS에서 사용하는 대칭키, 비대칭키 방식에 대해 이해한다.
  • 직접 로컬에서 HTTPS 인증서를 발급할 수 있다.
  • Hashing이 필요한 이유에 대해 이해한다.
  • 데이터베이스에 유저의 비밀번호와 같이 민감한 정보를 평문으로 저장하지 않는 이유에 대해 이해한다.
  • Salt가 필요한 이유에 대해 이해한다.

Chapter1-1. HTTPS

HTTP = 인터넷에서 데이터를 주고 받을 수 있는 통신 프로토콜
HTTP + Secure = 프로토콜 내용을 암호화

Hyper Text Transfer Protocol Secure Socket layer의 약자로 HTTP over SSL(TLS), HTTP over Secure라고 부르기도 함

  • HTTPS는 HTTP 요청을 SSL 혹은 TLS라는 알고리즘을 이용해, HTTP 통신을 하는 과정에서 데이터를 암호화하여 전송하는 방법임
    즉, HTTPS는 요청의 내용을 암호화 시키기 때문에 개인정보 등 중요한 정보가 유출이 되더라도 정확한 키가 없다면 어떤 내용인지 알 수 없음

HTTPS 프로토콜 특징

  • 인증서
  • CA
  • 비대칭 키 암호화 방식

HTTPS는 다음을 목적으로 사용

비대칭 키 암호화

전혀 다른 키 한 쌍으로 암호화 및 복호화를 진행한다.

HTTPS 프로토콜을 이용하는 서버는 한 쌍의 키 중에서 키 하나는 비밀키로, 다른 키 하나는 클라에게 공개를 해서 데이터를 안전하게 전송하도록 함

다만, 모든 통신에 대해서 공개키방식을 사용하는 것은 아님
공개키 방식은 많은 클라를 대상으로 매번 사용하기에는 연산이 복잡한 알고리즘이기에, 통신의 초창기에서만 비밀키를 만들어내기 위한 목적으로 사용한다.

HTTPS 통신과정(이해못함!)

1. HandShake

  • 서로를 확인 후, 서버는 클라에게 공개키 하나를 준다.
    (비대칭키방식: 공개키 한쌍, 비밀키 한쌍, 세션키 1개 -> 총 5개의 키)

2. 비밀 키 생성

  • 클라는 전달받은 공개키를 이용해서 서버와 키를 제작하기 위한 임의의 정보를 암호화해서 전송한다
  • 서버는 클라처럼 임의의 정보를 암호화해서 전송한다
  • 둘은 서로 만들고 교환한 정보를 바탕으로 비밀키를 생성한다.

3. 상호 키 검증

  • 각자 생성한 키를 바탕으로, 클라가 테스트용 데이터를 만들어낸 비밀키로 암호화를 해서 전달한다.
  • 서버역시 만들어진 비밀키로 복호화를 한뒤, 다시 암호화를 해서 클라로 전달한다.
  • 만약 클라가 같은 내용의 데이터를 복호화하는데 성공했다면 성공적으로 비밀키가 만들어진 상태이다. 동시에, 이는 HTTPS 연결이 성립한 상태이다.
  • 이후에 이 비밀키를 바탕으로, 정말로 데이터 송수신에 필요한 동일키 암호화 및 복호화를 진행한다.

암호화

제 3자가 서버와 클라이언트가 주고받는 정보를 탈취할 수 없도록 하는 것

  • 이를 위해 서버와 클라이언트는 서로가 합의한 방법으로 데이터를 암호화하여 주고받음.
  • 따라서 중간에 제 3자에게 데이터가 탈취되더라도 그 내용을 알아볼 수 없음
  • 기존에 배웠던 HTTP 는 요청 및 응답이 탈취된다면 아래와 같이 전달되는 데이터의 내용을 제 3자가 그대로 확인할 수 있음

    하지만 데이터를 암호화하여 전송하는 HTTPS를 사용한다면 비밀번호와 같은 중요한 데이터가 유출될 가능성이 HTTP보다 현저히 적어짐
  • 아래 사진은 위 사진과 동일한 요청을 프로토콜만 HTTPS로 변경했을 때의 데이터를 캡처한 사진임
  • 이처럼 내용이 암호화되어 전송되기 때문에 정확한 키로 복호화하기 전까지는 어떤 내용인지 알 수 없음

HTTPS에서는 클라이언트와 서버가 데이터를 암호화하여 주고받기 위해 비대칭키 방식과 대칭키 방식을 혼용하여 사용함

  • 서버와 클라이언트가 통신할 때, 대칭키 방식은 양쪽이 공통의 비밀 키를 공유하여 데이터를 암호화 및 복호화하는 것을 의미
  • 비대칭키 방식은 각각 공개키와 비밀키를 가지고 상대가 나의 공개키로 암호화한 데이터를 개인이 가진 비밀키로 복호화하는 것을 의미
  • 클라이언트와 서버가 데이터를 주고받을 때는 대칭키를 사용
    • 비대칭키 알고리즘은 대칭키 알고리즘보다 훨씬 복잡하기 때문에 대칭키를 사용하여 데이터를 암호화 및 복호화하는 것이 훨씬 컴퓨터에 부담을 덜 주기 때문
    • 그런데 대칭키를 서로 주고 받는 과정에서부터 정보가 탈취된다면??
  • 그래서 HTTPS는 이러한 대칭키를 주고받을 때는 비대칭키 방식으로 주고 받도록 함
    • 비대칭키의 경우, 공개키로 암호화한 정보는 개인이 가진 비밀키로만 풀 수 있기 때문에 중간에 대칭키가 탈취되더라도 개인키가 없이는 이를 복호화할 수 없기 때문

    💡 정리: HTTPS는 대칭키와 비대칭키 방식을 이용해 데이터를 암호화한다!

대칭키와 비대칭키를 이용한 철수와 영희의 편지 주고받기
대칭키와 비대칭키

인증서

  • 데이터 제공자 신원 보장
    • 데이터를 제공한 서버가 정말로 데이터를 보내준 서버인지 인증, 확인하는 용도
  • 도메인 종속
    • 인증서에는 서버의 도메인 관련 정보가 있어서 데이터 제공자의 인증을 용이하게 함

브라우저는 서버가 전송한 '응답 + 전달받은 인증서'를 확인할 수 있다.
클라는 인증서에 작성된 도메인과 응답객체에 작성된 도메인을 비교한다. 응답에서 확인한 도메인과, 인증서에 작성된 도메인이 같지 않은 경우, 클라이언트는 서버 제공자가 아닌 전혀 다른 데이터 제공자임을 알 수 있음! 아래 그림이 제 3자 공격이 발생한 경우임

정리하면,
인증서는 서버의 신원을 보증하여 우리가 접속한 Naver가 해커가 정교하게 따라한 가짜 Naver가 아님을 보장해주는 역할을 함

CA

CA는 인증서를 발급해주는 엄격하게 공인된 기관

  • 이렇게 보증할 수 있는 제 3자를 Certificate Authority, CA라고 부른다.
  • 각 브라우저는 각자 신뢰하는 CA의 정보를 가지고 있다.따라서, 그래서 각 브라우저마다 가지고 있는 인증서가 다르다.
  • 이러한 CA들은 서버의 공개키와 정보를 CA의 비밀키로 암호화하여 인증서를 발급함. (이 비밀키가 해커에게 유출되어 파산한 CA도 있다.)

코드스테이츠 웹사이트의 인증서를 살펴보면, 인증서를 발급한 CA, 서명에 사용한 알고리즘, 서명, 코드스테이츠의 공개 키 정보등이 들어있는 것을 확인할 수있음

💡 일단 이것만 이해: “인증서가 CA의 비밀키로 암호화되어 있기 때문에 CA의 개인키로 복호화 가능하다. 따라서 해당 CA에서 발급한 인증서라는 것을 보증할 수 있다.”

서버가 클라이언트에게 CA에서 발급받은 인증서를 전달하면 클라이언트는 OS 또는 브라우저에 미리 내장되어 있던 CA 리스트를 통해 브라우저에서 인증된 CA에서 발급받은 인증서인지 먼저 확인함
만약 인증된 CA에서 발급한 인증서가 아니라면 아래와 같이 화면에 경고창을 띄워 서버와 연결이 안전하지 않다는 화면을 보여줌

그 후 인증서가 확인되었다면 브라우저에 제공된 해당 CA 기관의 공개키로 서버 인증서를 복호화함

  • 앞서 말했듯 CA의 비밀키로 인증서를 암호화하였기 때문에 CA의 공개키로 복호화가 가능함
  • 이렇게 서명을 복호화해 얻은 공개키로 클라이언트는 서버를 믿을만한 대상인지 신뢰할 수 있음
  • 만약 인증서가 위조되었다면 CA의 공개키로 서버의 인증서를 복호화할 수 없을테니까

따라서 브라우저는 인증서의 도메인과 데이터를 제공하는 서버의 도메인을 비교할 수 있기 때문에 '중간자 공격'을 감지하여 보안 위협으로부터 사용자 및 사용자의 데이터를 보호할 수 있음
또한 위와 같은 경고를 직접 보여줌으로써 브라우저들은 인증된 CA가 발급한 인증서를 이용하여 데이터를 제공하는 안전한 서버를 사용자가 사용하도록 유도

이처럼 서버와 클라이언트간의 CA를 통해 서버를 인증하는 과정과 데이터를 암호화하는 과정을 아우른 프로토콜을 TLS 또는 SSL이라고 말함. (*SSL과 TLS는 사실상 동일한 규약을 뜻하며 SSL이 표준화되며 바뀐 이름이 TLS.)

Wikipedia - 중간자 공격 (Man In The Middle Attack)
https://en.wikipedia.org/wiki/Man-in-the-middle_attack

[실습] HTTPS 사설 인증서 발급 및 서버 구현

설치

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

macOS

macOS 사용자의 경우, Homebrew를 통해 mkcert를 설치할 수 있다.

$ brew install mkcert

인증서 생성

먼저 다음 명령어를 통해 로컬을 인증된 발급기관으로 추가해야한다.

$ mkcert -install

다음은 로컬 환경에 대한 인증서를 만들어야 한다. localhost로 대표되는 로컬 환경에 대한 인증서를 만들려면 다음 명령어를 입력해야 한다.

$ 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 이라는 파일이 생성된 것을 확인할 수 있다.

인증서는 공개키, 그리고 인증기관의 서명을 포함하고 있으므로 공개되어도 상관이 없지만, key.pem의 경우 개인 키이므로 git에 커밋하지 않고, 암호처럼 다루어야 한다.

HTTPS 서버 작성

Node.js 환경에서 HTTPS 서버를 작성하기 위해서는 https 내장 모듈을 이용할 수 있다. express.js를 이용해 https 서버를 만들 수도 있다.

먼저는 방금 생성한 인증서 파일들을 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 이용

만약 express.js 를 사용하는 경우, 다음과 같이 https.createServer의 두 번째 파라미터에 들어갈 callback 함수를 Express 미들웨어로 교체하면 됨!

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

Chapter1-2. Hashing

암호화(Encyrption)

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

암호화 예

Hashing

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

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

외부 알고리즘을 이용해서 해싱을 진행하면, 해시된 값('0g7s80a...')으로 DB에 저장이 됨.
-> 데이터 베이스가 털려도, 해시된 값(비밀번호)이 노출이 되어 해커가 이 비밀번호를 다른 사이트에 적용하더라도 안 뚫림

salt

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

  1. 암호화만 해놓는다면 해시된 결과가 늘 동일함
  • 해시된 값과 원래 값을 테이블(레인보우 테이블)로 만들어서 decoding 해버리는 경우가 생김
  1. 원본값에 임의로 약속된 '별도의 문자열(salt)'을 추가해 해시를 진행하면
  • 기존 해시값과 전혀 다른 해시값이 반환되어 알고리즘이 노출되더라도 원본값을 보호할 수 있도록 하는 안전 장치
  1. 기존 : (암호화하려는 값) => (hash 값)
    Salt사용: (암호화하려는 값) + (Salt 용 값) => (hash 값)

salt 사용시 주의점

  1. Salt는 유저와 패스워드 별로 유일한 값을 가져야 함
  2. 사용자 계정을 생성할 때, 비번 변경할 때마다 새로운 임의의 Salt를 사용해서 해싱해야 함
  3. Salt는 절대 재사용하지 말아야 함
  4. Salt는 DB의 유저 테이블에 같이 저장돼야 함
  • 유저가 비번을 입력했을 때, 이 유저만의 Salt와 합해서 다시 해싱을 해줄 수 있기 때문에 DB에 따로 같이 저장해줘야함

유저마다 다르게 salt 사용시

서버에서 salt를 공용으로 사용하는 것이 아니라 유저마다 salt를 다르게 했을 시, 데이터 베이스에서도 salt를 각자 다르게 가지고 있어야 함
서버는 password를 넘겨 받고 암호화를 진행하는데, DB에서 넘겨받은 salt값을 가지고 해싱을 해서 비교를 하게 된다. 알고리즘이 노출돼도 보다 안전하다.

퀴즈
1. 클라이언트가 서버에게 암호화된 사용자의 비밀번호를 보내면 서버가 이를 평문으로 복호화하여 데이터베이스에 저장한다.(x)

  • 비밀번호와 같은 사용자의 민감한 정보는 데이터베이스에 평문으로 저장하면 안됩니다. 보통 클라이언트에서 HTTPS를 이용해 사용자의 비밀번호가 중간에 탈취되지 않도록 주의하고 서버는 요청으로 받은 비밀번호를 그대로 데이터베이스에 저장하지 않고 해싱(암호화)과정을 거친 뒤 저장합니다.

2.Salt는 암호화해야 하는 값에 ( 별도의 값 )을 추가하여 결과를 변형하는 것을 뜻합니다.

  • SSL은 HTTPS에서 사용하는 보안 기능입니다.
  • 레인보우 테이블은 특정 입력값을 해싱한 결과를 대량으로 모아놓은 표를 뜻합니다. 이를 대비하기 위해선 개발자만이 아는 별도의 값, 즉 Salt를 추가하여 해싱한 값이 달라지도록 해야 합니다.

Chapter2. Cookie / Session

쿠키의 개념과 작동원리 및 이를 이용한 세션 인증 방식에 대해 학습한다.
무상태성을 가진 HTTP에서 사용자의 상태를 브라우저에 저장할 수 있는 쿠키를 학습한다
사용자의 정보를 서버에 저장하고 쿠키를 이용하여 이를 검증하는 세션 인증 방식에 대해 학습한다.

  • 쿠키의 작동 원리를 이해할 수 있다
  • 회원가입 및 로그인 등의 유저 인증에 대해 설명할 수 있다.
  • 세션의 개념을 이해할 수 있다.
  • 쿠키와 세션은 서로 어떤 관계이며, 각각이 인증에 있어서 어떤 목적으로 존재하는지 이해할 수 있다.
  • 세션의 한계를 이해할 수 있다.

Chapter2-1. Cookie

  • 어떤 웹사이트에 들어갔을때, 서버가 일방적으로 클라이언트에 전달하는 작은 데이터
  • 서버가 웹 브라우저에 정보를 저장하고, 불러올 수 있는 수단
  • 서버에서 클라이언트에 영속성있는 데이터를 저장하는 방법
    • 그러므로 서버가 원한다면 서버는 클라이언트의 쿠키를 이용하여 데이터를 가져올 수 있음
    • 그러므로 쿠키를 이용하는 것은 단순히 서버에서 클라이언트에 쿠키를 전송하는 것만 의미하지 않고 클라이언트에서 서버로 쿠키를 다시 전송하는 것도 포함됨
  • 해당 도메인에 대해 쿠키가 존재하면, 웹 브라우저는 도메인에게 http 요청 시 쿠키를 함께 전달함.
  • 삭제하지 않으면 사라지지 않는다.
  • 따라서, 장바구니에 담은 상품 유지, 로그인 상태 유지, 사용자 선호, 테마 등 장시간 보존해야하는 정보 저장에 적합
  • 쿠키가 클라이언트에 저장되고, 자동으로 요청되는 그림
  1. 서버가 응답헤더에 Set-Cookie라는 프로퍼티에 쿠키의 이름, 값, 경로 등의 옵션을 저장함.
  2. 쿠키가 담긴 응답을 받은 클라이언트는 응답헤더에 존재하는 셋쿠키를 확인한다
  3. 매 요청시마다 쿠키의 이름과 값을 서버에게 전달하게 됨
    -> 서버가 쿠키를 저장하면, 이후로는 해당 웹사이트를 방문할때, 내 요청에 자동으로 쿠키가 항상 함께 전송된다.
    -> 서버는 받은 쿠키 내용을 바탕으로 로그인을 유지한다던지,, 함

서버는 쿠키를 이용하여 데이터를 클라이언트에 저장하고 이 데이터를 다시 불러와 사용할 수 있음

  • 하지만 데이터를 저장한 이후 아무 때나 데이터를 가져올 수는 없음. 데이터를 저장한 이후 특정 조건들이 만족되어야 다시 가져올 수 있기 때문!
'Set-Cookie':[
            'cookie=yummy', 
            'Secure=Secure; Secure',
            'HttpOnly=HttpOnly; HttpOnly',
            'Path=Path; Path=/cookie',
            'Doamin=Domain; Domain=codestates.com'
        ]

특정 조건들은 위 코드처럼 쿠키 옵션으로 표현할 수 있음

1. Domain

도메인은 흔히 사용하는 www.google.com과 같은 서버에 접속할 수 있는 이름.
쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않음.
여기서 서브 도메인이란 www 같은 도메인 앞에 추가로 작성되는 부분을 말함

따라서 요청해야 할 URL이 http://www.localhost.com:3000/users/login 이라 하면 여기에서 Domain은 localhost.com이 됨.

만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션서버의 도메인이 일치해야만 쿠키를 전송할 수 있다. 이를 통해 naver.com에서 받은 쿠키를 google.com에 전송하는 일을 막을 수 있음

2. Path

Path는 세부 경로로써 서버가 라우팅할 때 사용하는 경로를 의미
http://www.localhost.com:3000/users/login 인 경우라면 여기에서 Path, 즉 세부 경로는 /users/login이 됩니다. 이를 명시하지 않으면 기본적으로 / 으로 설정되어 있음

Path 옵션의 특징은 설정된 경로를 포함하는 하위 경로로 요청을 하더라도 쿠키를 서버에 전송할 수 있음
Path가 /users로 설정되어 있고, 요청하는 세부 경로가 /users/codestates 인 경우라면 쿠키 전송이 가능

하지만 /posts/codestates로 전송되는 요청은 Path 옵션(/users)을 만족하지 못하기 때문에 서버로 쿠키를 전송할 수 없음

3. MaxAge or Expires

쿠키가 유효한 기간을 정하는 옵션. 만약 쿠키가 영원히 남아있다면 그만큼 탈취되기도 쉬워지기 때문에 이러한 유효기간을 설정하는 것이 보안 측면에서 중요함

MaxAge는 쿠키가 유효한 시간을 초 단위로 설정하는 옵션

Expires언제까지 쿠키가 유효한지 심판의 날을 지정할 수 있음. 이때 옵션의 값은 클라이언트의 시간을 기준으로 함. 이후 지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴됨

쿠키는 위 옵션의 여부에 따라 세션 쿠키(Session Cookie)와 영속성 쿠키(Persistent Cookie)로 나뉨

  • 세션 쿠키: MaxAge 또는 Expires 옵션이 없는 쿠키로, 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키입니다. 브라우저를 종료하면 해당 쿠키는 삭제됨

  • 영속성 쿠키: 브라우저의 종료 여부와 상관없이 MaxAge 또는 Expires에 지정된 유효시간만큼 사용가능한 쿠키

4. Secure

사용하는 프로토콜에 따른 쿠키의 전송 여부를 결정하는 옵션. 만약 Secure 옵션이 true로 설정된 경우 HTTPS를 이용하는 경우에만 쿠키를 전송할 수 있음

즉, Secure 옵션이 없다면 프로토콜에 상관없이 http://www.codestates.com 또는 https://www.codestates.com에 모두 쿠키를 전송할 수 있음

5. HttpOnly

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

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

6. SameSite

Cross-Origin 요청을 받은 경우, 요청에서 사용한 메소드와 해당 옵션의 조합을 기준으로 서버의 쿠키 전송 여부를 결정하게 됨. 사용 가능한 옵션은 다음과 같음

  • Lax: Cross-Origin 요청이라면GET 메소드에 대해서만 쿠키를 전송할 수 있다.
    • 사이트가 서로 달라도, GET 요청이라면 쿠키 전송이 가능하다.
  • Strict: 단어 그대로 가장 엄격한 옵션으로, Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있음
    • 사이트가 서로 다르면, 쿠키 전송을 할 수 없다
  • None: Cross-Origin에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있음 다만 쿠키 옵션 중 Secure 옵션이 필요.
    • 사이트가 달라도, 모든(GET, POST, PUT 등등) 요청에 대해 쿠키 전송이 가능하다.

      💡 이때 same-site는 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말함. 이 중 하나라도 다르다면 Cross-Origin으로 구분됨


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

쿠키를 이용한 상태 유지

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

하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, HttpOnly 옵션을 사용하지 않았다면 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험하다!

이런 인증정보를 이용해 공격자가 유저인척 서버에 요청을 보낸다면 서버는 누가 요청을 보낸 건지 의심하지 않고 이를 인증된 유저의 요청으로 취급하게 됨. 이때 개인정보와 같은 민감한 정보를 공격자가 탈취한다면 2차 피해가 일어날 수 있음.

참고 MDN - Set-Cookie Attributes
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie

Chapter2-2. Session

세션기반 인증 (Session-based Authentication)

로그인

사용자가 웹사이트에서 아이디 및 비밀번호를 이용해서 로그인을 시도하면(그림에서 1번), 과연 어떤 일이 벌어질까?

  • 사용자가 만일 정확한 아이디와 비밀번호를 입력했다면, 서버는 인증(Authentication)에 성공했다고 판단할 것임
  • 그렇다면, 다음번에 인증을 필요로 하는 작업(e.g. 장바구니에 물품 추가)을 요청할 경우에 한번 더 로그인 과정을 거쳐야 할까?
    • NOPE. 서버가 "해당 유저는 인증에 성공했음"을 알고 있다면, 유저가 매번 로그인할 필요가 없쥐.

💡 인증에 따라 리소스의 접근 권한(Authorization)이 달라짐

이때 서버와 클라이언트에 각각 필요한 것은 다음과 같음

  • 서버: 사용자가 인증에 성공했음을 알고 있어야 함
  • 클라이언트: 인증 성공을 증명할 수단을 갖고 있어야 함
  • 사용자가 인증에 성공한 상태를 세션이라고 부름
    • 서버는 일종의 저장소에 세션을 저장함. (2번) 주로 in-memory(자바스크립트 객체를 생각하면 됨), 또는 세션 스토어(redis 등과 같은 트랜잭션이 빠른 DB)에 저장
    • 세션이 만들어지면, 각 세션을 구분할 수 있는 세션 아이디도 만들어지는데(3번), 보통 클라이언트에 세션 성공을 증명할 수단으로써 세션 아이디를 전달함. (4번)
    • 이때 웹사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용함. 쿠키에는 서버에서 발급한 세션 아이디를 저장

쿠키를 통해 유효한 세션 아이디가 서버에 전달되고, (5번) 세션 스토어에 해당 세션이 존재한다면 (6번) 서버는 해당 요청에 접근 가능하다고 판단함. (7,8번)

쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려줌

로그아웃

세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있음. 그리고 서버는 그저 세션 아이디로만 인증 여부를 판단함

💡 주의: 앞에서도 말했지만, 쿠키는 세션 아이디, 즉 인증 성공에 대한 증명을 갖고 있으므로, 탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단함. 이것이, 우리가 공공 PC에서 로그아웃해야 하는 이유

그러므로 로그아웃은 다음 두 가지 작업을 해야 함

  • 서버: 세션 정보를 삭제해야 함
  • 클라이언트: 쿠키를 갱신해야 함

서버는 클라이언트의 쿠키를 임의로 삭제할 수 없음. 대신, set-cookie로 클라이언트에게 쿠키를 전송할 때 세션 아이디의 키값을 무효한 값으로 갱신할 수 있음

express-session

Node.js에는 이런 세션을 대신 관리해 주는 express-session 이라는 모듈이 존재함

const express = require('express');
const session = require('express-session');

const app = express();

app.use(
  session({
    secret: '@codestates',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'localhost',
      path: '/',
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: 'none',
      httpOnly: false,
      secure: true,
    },
  })
);

언뜻 보면 쿠키 옵션과 비슷해 보임. 하지만 세션의 경우 secret 옵션의 비밀키를 이용해 암호화해 세션 id라는 것을 생성하고, 이것을 클라이언트에게 쿠키로 전송함

쿠키로 전송된 세션 id는 이에 종속되는 고유한 세션 객체를 가지며 이는 서버에 저장됨. 이때 세션 객체는 유저별로 독립적으로 생성된 객체이므로 유저별로 각각 다른 데이터를 저장할 수 있음

따라서 클라이언트에 유저의 개인정보를 담지않고도 서버가 클라이언트의 세션 id를 이용해 유저의 인증여부를 판단할 수 있음

세션 객체는 req.session으로 접근할 수 있으며 앞서 말했듯 이를 통해 세션에 임의의 데이터를 저장하거나 불러올 수 있음..
-> setAttribute, getAttribute 메서드

💡즉, 서버는 사용자가 인증에 성공하면 로그인 상태를 유지하기 위해 해당 사용자의 정보를 담은 세션 객체를 생성함. 그리고 이에 접근할 수 있는 id를 암호화하여 쿠키로서 사용자에게 전달함

이 세션 객체에 값을 담거나, 값을 불러오는 법, 세션을 파괴하는 법은 다음 문서를 참고
https://github.com/expressjs/session#reqsession


과제1 - Auth Basic

  • 클라이언트 - 서버 간 쿠키의 작동 방식에 대해 이해할 수 있다.
    • set-cookie 헤더와 cookie 헤더의 차이를 이해할 수 있다.
    • Session Cookie와 Persistent Cookie의 차이에 대해 이해할 수 있다.
  • 클라이언트에서 서버에 로그인 요청을 보낼 수 있다.
    • 로그인 성공 여부에 따라 조건부 컴포넌트 렌더링을 할 수 있다.
    • 비동기 요청으로 받은 데이터를 컴포넌트의 상태로 업데이트할 수 있다.

Auth Session

  • 세션의 개념을 이해할 수 있다.
    • 세션 id와 세션 객체의 차이에 대해 이해할 수 있다.
    • 세션 시크릿이 왜 필요한지 이해할 수 있다.
  • 쿠키와 세션은 서로 어떤 관계이며, 각각이 인증에 있어서 어떤 목적으로 존재하는지 이해할 수 있다.
  • 세션의 한계를 이해할 수 있다.

Chapter3. 웹 공격의 종류

  • SQL injection 공격에 대해 이해할 수 있다.
    • 사용자의 입력값을 무조건 신뢰하면 안되는 이유에 대해 이해할 수 있다.
  • XSS 공격에 대해 이해할 수 있다.
    • Stored XSS와 Reflected XSS의 차이에 대해 설명할 수 있다.
  • CSRF 공격에 대해 이해할 수 있다.
  • Clickjacking 공격에 대해 이해할 수 있다.

OWASP

The Open Web Application Security Project의 약자로서, 전세계의 보안 전문가들이 웹의 보안에 대한 표준을 정의하고 이에 대해 기업과 개발자들에게 효율적인 정보를 제공하는 오픈소스 커뮤니티

OWASP는 주로 웹에 관한 정보노출, 악성 파일 및 스크립트, 보안 취약점 등을 주제로 연구하며, 3년 정도의 주기를 두고 웹의 10대 취약점들에 대한 OWASP TOP 10을 발표하고 있음

이번 챕터에서는 2017년과 2021년에 발표한 OWASP TOP 10을 기반으로 프론트엔드 개발자가 알아두면 좋을 웹 공격들에 대해 살펴봄

SQL Injection(삽입)

SQL: Structured Query Language (구조적 질의 언어)의 줄임말로, 관계형 데이터베이스 시스템(RDBMS)에서 데이터를 관리 및 처리하기 위해 설계된 선언형 프로그래밍 언어

데이터베이스에서 임의의 SQL문을 실행할 수 있도록 명령어를 삽입하는 공격 유형

  • 응용 프로그램의 보안상의 허점을 이용해 데이터베이스를 비정상적으로 조작하며, 이로 인해 기록이 삭제되거나 데이터가 유출될 수 있음

    공격시나리오

  • SQL 삽입 공격은 보통 사용자가 input form에 직접 무언가 작성하는 상황에서 발생함
    • 공격자는 input form에 일반 텍스트(아이디 및 패스워드)가 아닌 SQL문을 작성함
    • 입력받은 아이디와 패스워드를 통해 데이터베이스를 조회하는데, 패스워드에 ’OR ‘1’ = ‘1을 넣어 보낸다면, WHERE절에서 OR는 AND보다 연산 순위가 낮기 때문에 OR절인 ‘1’ = ‘1’ (항상 참)이 가장 나중에 실행되어 결국 로그인에 성공함
    • input form에 SQL문을 마무리하는 키워드인 ;와 함께 주요 테이블을 삭제하는 SQL문(e.g. '; DROP TABLES users;--')을 작성한다면 데이터가 모두 삭제되는 큰 피해를 입을 수도 있음

SQL injection 대응 방안

  1. 입력(요청) 값 검증
  • SQL문은 사람이 사용하는 자연어와 비슷하기 때문에 키워드를 막기엔 한계가 있다. 따라서 블랙리스트가 아닌 화이트리스트 방식으로 해당 키워드가 들어오면 다른 값으로 치환하여 SQL Injection에 대응할 수 있다.
  1. Prepared Statement 구문 사용
    Prepared Statement 구문을 사용하면 사용자의 입력이 SQL문으로부터 분리되어 SQL Injection을 방어할 수 있다.
  • 사용자의 입력 값이 전달 되기 전에 데이터베이스가 미리 컴파일하여 SQL을 바로 실행하지 않고 대기하며, 사용자의 입력값을 단순 텍스트로 인식한다. 따라서 입력 값이 SQL문이 아닌 단순 텍스트로 적용되며 공격에 실패하게 됨
  1. Error Message 노출 금지
  • 공격자는 데이터베이스의 Error Message를 통해 테이블이나 컬럼 등 데이터베이스의 정보를 얻을 수 있다. 에러가 발생한 SQL문과 에러 내용이 클라이언트에 노출되지 않도록 별도의 에러핸들링이 필요.

Cross-Site Scripting (XSS)

XSS(Cross-Site Scripting, 사이트 간 스크립팅)는 웹 사이트 관리자가 아닌 이(공격자)가 웹 사이트에 악의적인 스크립트를 심어놓는 행위를 말함. 주로 클릭을 유도하는 글을 작성한 후, 해당 글을 클릭하면 공격자가 심어놓은 스크립트가 실행되어 웹 사이트 이용자에게 피해를 줌

이 공격의 대상은 클라이언트로, 사용자가 의도하지 않은 행동을 하게하거나 사용자의 쿠키 등 민감한 정보를 탈취함. XSS로 탈취한 사용자의 민감한 정보를 이용해 권한을 획득한 후 이를 이용해 CSRF 등 다양한 공격에 활용함

XSS의 공격 유형

1. Stored XSS

Stored XSS는 스크립트가 서버에 저장되어 여러 사용자에게 피해를 줄 수 있는 유형으로, 지속적(Persistent)기법이라고도 함

  • 주로 게시판 형태의 웹 사이트에서 발생하며, 공격자가 악의적인 스크립트가 담긴 글을 작성한 후 서버에 저장된 글을 조회할 때마다 스크립트가 실행되는 형식

공격 시나리오

  1. 공격자가 게시판에 텍스트가 아닌 스크립트가 담긴 글을 작성한다. 작성된 글이 서버에 저장됨.
  2. 일반 사용자(피해자)가 해당 글을 조회할 때마다 HTML로 글의 내용이 화면에 그려지는 과정에서 해당 스크립트가 실행됨. 위의 예시처럼 브라우저가 단순히 어떤 실행을 하도록 할 수도 있지만 스크립트 내부에서 쿠키 등 민감한 개인 정보를 탈취할 수도 있음.
  3. 악성 스크립트가 작성된 글은 서버에 저장되어 있기 때문에 글을 조회할 때마다 스크립트가 실행되어 불특정 다수를 대상으로 공격하게 됨

2. Reflected XSS

Reflected XSS는 URL 파라미터를 사용해 스크립트를 만드는 유형으로, 비 지속적(Non-persistent) 기법이라고도 함

  • 이 스크립트는 서버에 저장되지 않으며 웹 어플리케이션의 지정된 파라미터를 사용할 때 나타나는 취약점을 이용함

    주로 공격이 일어나는 곳은 검색엔진으로, 검색 결과가 없는 경우 입력 결과를 HTML 문서에 포함하여 응답하는 특성을 이용하기 때문에 반사(Reflected) XSS라고 부름

  • CSRF 공격과 비슷한 듯 하지만 CSRF는 공격자가 사용자의 권한을 탈취하여 서버에 가짜 요청을 보내는 반면, Reflected XSS의 경우 악성 스크립트가 실행되는 곳, 즉 공격 대상이 서버가 아닌 클라이언트라는 점에서 엄연히 다르다

공격 시나리오

  1. 공격자는 URL 파라미터에 스크립트가 작성된 링크로 사용자의 클릭을 유도. 주로 피싱(e.g. 배송현황 확인 문자)에 사용됨.
  2. 피해자가 URL을 클릭함. 피해자가 링크를 클릭하면 열리길 예상하는 웹 사이트가 아닌 다른 웹 사이트(e.g. 취약점이 있는 검색엔진)의 링크로 연결됨. 즉, 요청이 보내짐.
  3. 해당 웹 서버는 URL에 담긴 스크립트를 그대로 반사(reflect)하여 클라이언트(피해자)에 응답을 전송함
  4. 브라우저가 공격자가 심은 악성 스크립트를 그대로 실행함. alert(”Warning!”)과 같이 브라우저가 단순히 어떤 실행을 하도록 할 수도 있지만, 보통은 쿠키 등 민감한 개인 정보를 탈취하는 코드를 심어 놓음.

XSS 대응 방안

  1. 스크립트 태그의 입력을 막기
    Stored XSS의 경우 악성 스크립트가 있는 글을 그대로 저장하는 상황이 문제가 됨. 따라서 스크립트의 저장 자체를 막는 방법으로 해결할 수 있음. 스크립트의 실행을 막기 위해 태그(<>)가 글자 그대로 저장되지 않게 방지할 수 있음
  • 입력값 확인 혹은 필터링
    • 클라이언트와 서버 모두에서 할 수 있는 방법으로, 입력된 값에 태그(<>)와 같은 특수문자가 입력되지 않게 하거나, 저장 요청이 온 글에 태그(<>)와 같은 특수문자가 있는지 검증할 수 있음
    • 클라이언트 측에선 유저로부터 입력을 받는 곳에 innerHTML 대신 textContent 속성을 사용하여 필터링할 수 있음
  • 입력값 치환하기
    • 글 내용에 포함되어 있는 태그(<>)를 HTML 문자 참조로 치환 후 저장.
    • <는 < 로 치환하고, >는 >로 치환하고 저장하면 글을 조회할 때 글의 내용을 확인할 수는 있지만 HTML의 태그로 인식되지 않아 스크립트가 실행되지 않음
  1. 쿠키 설정 확인하기 (httpOnly)
    쿠키의 설정 중 httpOnly를 사용하는 것은 XSS 즉, 사이트에 스크립트가 저장 혹은 실행되는 일 자체를 방지하지는 않음. 하지만 스크립트가 쿠키를 탈취하는 경우를 방지해 쿠키에 저장된 민감한 개인 정보의 유출을 막을 수 있음

쿠키에 httpOnly 설정이 되어있지 않다면 document.cookie로 자바스크립트를 통해 쿠키에 접근할 수 있음. 해당 설정을 이용해 쿠키를 브라우저에서 조회할 수 없도록 할 수 있음

  1. 쿠키에 민감한 정보 담지 않기
  • 민감정보를 서버에서 관리하기
  • 암호화 사용하기
    이 역시 XSS 자체를 막을 수는 없지만, 쿠키가 탈취 되더라도 쿠키에 민감한 개인 정보를 담지 않았으므로 2차 피해를 막을 수 있음
    개인 정보를 유추할 수 있는 내용을 쿠키에 담지 않고 모두 서버에서 관리하도록 하자
    유저를 인증하고 조회하기 위해 유저 id가 필요하다면 id 값 자체가 아닌, 유추하기 힘들도록 uuid를 이용하는 등 단순한 정보값이어도 암호화한 후 전달하자

Cross-Site Request Forgery (CSRF)

Clickjacking

Clickjacking 대응 방안


Chapter4. Token / OAuth

세션 인증 방식을 보완한 토큰 인증 방식에 대해 학습한다.
그 중 대표적인 토큰 인증 방식인 JWT에 대해 학습하고 어떻게 JWT가 사용자의 정보를 암호화하여 토큰을 저장하는 지 이해한다.
더 나아가 직접 서버에서 인증과 관련된 로직을 처리할 필요없이 인증을 중개하는 외부 서버를 이용한 Oauth 기술에 대해서도 학습한다.
이를 통해 소셜 로그인의 작동 방식을 살펴본다.

  • 토큰의 개념을 이해할 수 있다.
    • Refresh Token과 Access Token의 차이를 이해한다.
  • 쿠키 / 세션 방식과 토큰 방식의 차이를 이해할 수 있다.
  • JWT의 작동원리에 대해 이해할 수 있다.
    • header, payload, signature가 각각 어떤 역할을 하는 지 이해할 수 있다.
    • JWT가 어떻게 토큰의 변조를 판별하는 지 이해할 수 있다.
  • 토큰 방식의 한계를 이해할 수 있다.
  • Authentication과 Authorization의 차이를 이해할 수 있다.
  • OAuth의 키워드를 설명할 수 있다.
    • Authorization Code와 Access Token의 차이에 대해 이해할 수 있다.
    • Authorization 서버와 Resource 서버의 차이에 대해 이해할 수 있다.

Chapter4-1. Token

토큰기반 인증(Token-based Authentication) 왜 쓸까?

세션 기반 인증은 서버(혹은 데이터베이스)에 유저 정보를 담는 인증 방식이었음. 서버에서는 유저가 민감하거나 제한된 정보를 요청할 때마다 "지금 요청을 보낸 유저에게 우리가 정보를 줘도 괜찮을까?를 확인하기 위해 클라가 보낸 세션 ID를 서버 본인이 가지고 있는 세션 객체와 비교했다. 매 요청마다 매 요청마다 데이터베이스를 살펴보는 부담과 "이 부담을 클라에게 넘겨줄순 없을까?"에서 고안된 것이 토큰 기반 인증 토큰기반 인증!

클라이언트에 인증 정보를 보관할 수 있는 토큰

토큰은 유저정보를 암호화하기 때문에 클라이언트에 담을 수 있음

JWT(JSON Web Token)

대표적인 토큰기반 인증으로 Json 포맷으로 사용자에 대한 속성을 저장하는 웹 토큰

JWT 종류

JWT는 보통 다음의 두 가지 종류의 토큰을 이용해 인증을 구현함
1. 액세스 토큰(Access Token)
2. 리프레시 토큰(Refresh Token)

액세스 토큰: 보호된 정보들(유저의 이메일, 연락처, 사진 등)에 접근할 수 있는 권한부여에 사용함.

  • 클라이언트가 처음 인증을 받을때(로그인 시)액세스 토큰, 리프레시 토큰 두가지를 다 받지만, 실제로 권한을 얻는 데 사용하는 토큰은 액세스 토큰
  • 단, 액세스 토큰에는 비교적 짧은 유효기간을 줘서 악의적인 유저가 토큰을 탈취하더라도 오랫동안 사용할 수 없도록 한다.

액세스 토큰의 유효기간이 만료되면 리프레시 토큰을 사용해서 새 액세스 토큰을 발급받는다. 이때, 유저는 다시 로그인 할 필요가 없음

  • 다만, 유저의 편의보다 정보를 지키는 것이 더 중요한 웹사이트는 리프레시 토큰을 사용하지 않는 곳이 많음

JWT 구조

JWT는 .으로 나눠진 세 부분이 존재하며 각각을 Header, Payload, Signature 라고 부른다.

1.Header
Header는 이것이 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 시그니처를 sign(암호화)할지가 적혀있다. JSON 형태로 정보가 담겨있다.

{
	"alg":"HS256",
    "typ": "JWT"
}

이 JSON 객체를 base64 방식으로 인코딩하면 header 완성됨

2.Payload
서버에서 활용할 수 있는 유저의 정보가 담겨 있다.
여기에는 어떤 정보에 접근 가능한지에 대한 권한, 또는 유저의 이름과 같은 개인정보 등을 담을 수 있음

페이로드는 시그처를 통해 유효성이 검증될 정보이긴 하나 너무 민감한 정보는 담지 않는 것이 좋다. 디코딩이 쉬운 base64방식으로 인코딩 되기 때문이다.

{
	"sub": "someInfomation",
    "name": "doyeon",
    "iat": 151623391
}

마찬가지로, 이 JSON 객체를 base64 방식으로 인코딩하면 payloadr가 완성됨

3. Signature
base64로 인코딩된 header, payload가 완성이 되면, Signature는 이를 서버의 비밀키(암호화에 추가할 salt)와 헤더에서 지정한 알고리즘을 사용해 암호화한다.

base64 인코딩 자체는 누구나 쉽게 디코딩할 수 있어서 header와 payload 모두, 쉽게 확인 할 수 있다.
여기서 이제, 비밀키를 사용하면 이를 암호화한 값(시그니처)은 비밀키를 보유한게 아니라면 해독하는 데 엄청난 시간과 노력이 들어가게 됨

만약 HMAC SHA256 알고리즘을 사용한다면 시그니쳐는 다음과 같은 방식으로 생성된다.

HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);

누군가 권한을 속이기 위해 PAYload를 변조하여 Base64로 인코딩하더라도 원본 payload로 암호화한 시그니처값과 다르기 때문에 서버는 해당 토큰이 변조됐음을 알 수 있다.

JWT 사용 예시

JWT는 권한 부여에 굉장히 유용하다. 예를 들어, 새로 다운받은 A라는 앱이 Gmail과 연동되어 이메일을 읽어와야 한다고 생각해보자

유저는
1. Gmail 인증 서버에 로그인정보(아이디, 비번)을 제공한다.
2. 성공적으로 인증시 JWT를 발급받는다.
3. A앱은 JWT를 사용해 해당 유저의 Gmail 이메일을 읽거나 사용할 수 있다.

토큰기반 인증 절차

  1. 클라가 서버에 아이디/비번을 담아 로그인 요청을 보낸다.
  2. 서버는 아이디/비번이 일치하는지 확인하고, 클라에게 보낼 암호화된 토큰을 생성한다.
    • access/refresh 토큰을 모두 생성한다.
      • 토큰에 담길정보(payload)는 유저를 식별할 정보, 권한이 부여된 카테고리(사진, 연락처, 기타 등등)이 될 수 있다.
      • 두 종류의 토큰이 같은 정보를 담을 필요는 없다.
  3. 서버가 토큰을 클라에게 보내주면, 클라는 토큰을 저장한다.
    • 토큰 저장 위치는 Local Storage, Session Storage, Cookie 등 다양함
  4. 클라가 HTTP 헤더(Authorization 헤더) 또는 쿠키에 토큰을 담아 보낸다. 쿠키에는 리프레시 토큰을 담고, 헤더 or 바디에는 액세스 토큰을 담는 등 다양한 방법으로 구현할 수 있음
  5. 서버는 토큰을 해독하여 "아, 우리가 발급해준 토큰이 맞구만!"라는 판단이 들면 클라의 요청을 처리하고 응답을 보내 준다.

토큰기반 인증의 장점

1. Statelessness & Scalability(무상태성 & 확장성)

  • 서버는 클라에 대한 정보를 저장할 필요가 없어 부담이 덜함 (토큰이 해독되는지만 판단)
  • 클라는 새로운 요청을 보낼때마다 토큰을 헤더에 포함시키면 된다.
  • 서버를 여러개 가지고 있는 서비스라면 더더욱 빛을 발휘한다. 같은 토큰으로 여러 서버에서 인증이 가능하기 때문이다. 세션방식이라면 모든 서버가 해당 유저의 정보를 공유하고 있어야 함!

2. 안전하다

  • 암호화한 토큰을 사용하고, 암호화 키를 노출할 필요가 없어 안전하다.

3. 어디서나 생성가능하다.

  • 토큰을 해독하는 서버가 토큰을 만들지 않아도 됨
  • 토큰 생성용 서버를 만들거나, 다른 회사에 토큰 관련 작업을 맡기는 것등 다양한 활용이 가능하다.

4. 권한부여에 용이하다.

  • 토큰의 payload(내용물)안에는 어떤 정보에 접근 가능할지 권한을 부여할 수 있다.
    • e.g 사진과 연락처 사용 권한만 부여

퀴즈

  1. 토큰 인증 방식은 유저 정보를 암호화하여 클라이언트에 저장합니다(o)
  • 세션 인증 방식과 달리 토큰 인증 방식은 유저 정보를 서버에 저장하지 않고 클라이언트에 저장합니다.
  • 이때 서버의 비밀키로 암호화하여 데이터를 서명하기 때문에 중간에서 토큰이 조작되더라도 서버가 이를 감지할 수 있습니다.
  • 세션 인증 방식처럼 아이디를 매번 검증해, 대응하는 세션 객체를 찾을 필요가 없기 때문에 상대적으로 서버에 부담이 덜 가게 됩니다.
  1. Payload는 Header의 표시한 알고리즘으로 암호화된 유저의 정보이다.(x)
  • Payload는 단순한 Base64로만 인코딩된 값입니다. 따라서 브라우저에서도 이를 쉽게 디코딩하여 Payload의 값을 읽을 수 있습니다. 따라서 민감한 유저의 정보는 담지 않는 것이 좋습니다.

Chapter4-2. OAuth

우리가 웹이나 앱에서 흔히 볼 수 있는 소셜 로그인 인증 방식은 OAuth 2.0라는 기술 바탕으로 구현되는 것임!

전통적으로, 직접 작성한 서버에서 인증을 처리해주는 것과는 달리, OAuth는 인증을 중개해주는 메커니즘이다. 보안된 리소스에 액세스하기 위해 클라이언트에게 권한을 제공(Authorization)하는 프로세스를 단순화하는 프로토콜이다.

유저가 Facebook, Google, GitHub 같은 웹사이트 상의 보안된 자신의 리소스에 대해서, 다른 웹사이트 혹은 애플리케이션에게 해당 리소스에 대한 접근 권한을 부여하할 수 있는 개방형 프로토콜 중 한 종류이다.

즉, 이미 사용자 정보를 가지고 있는 웹서비스(Google, GitHub 등)에서 사용자의 인증을 대신해주고, 접근 권한에 대한 토큰을 발급한 후, 이를 이용해 내 서버에서 인증이 가능해짐

단, OAuth는 인증(Authentication)을 다른 서비스에 맡길 뿐, 접근권한 관리(Authorization)는 순전히 내 서버의 몫이다!

  • 따라서, OAuth 의 작동방식을 알기 위해서는 기존 인증방식에 대한 이해가 필수적임
  • Authentication과 Authorization의 차이 정확히 짚고 넘어가기

💡 OAuth 2.0은 인증을 위한 표준 프로토콜의 한 종류

OAuth 인증 절차

Case study - 페북으로 소셜로그인을 해서 유저의 페북 프로필 이미지 바다오고 싶은 경우

(이 예시에서 페북서버가 Resouce server, Authorization server 두 가지 모두 담당)

액세스토큰을 받았다면, 이제 복잡한 과정을 거치지 않고도 아래와 같이 바로 유저의 resource에 접근 가능하다!

OAuth에서 꼭 알아야할 용어

Resource Owner : 리소스 가진 유저~
김코딩이 구글계정을 이용해 App에 로그인할 꼉우, 이때 김코딩이 리소스오너가 된다.
Client: Resource owner를 대신하여 보호된 리소스에 액세스하는 응용프로그램(앱). 클라는 서버, 데스크탑, 모바일 또는 기타 장치에서 호스팅할 수 있다. 김코딩이 A라는 앱을 Google소셜로그인을 이용해 사용한다면 A가 클라이언트가 된다.
Resource server: client의 요청을 수락하고 응답할 수 있는 서버. 클라가 Google Photo에서 김코딩의 사진을 가져오는 경우 Google Photo가 리소스 서버가 된다. 리소스 서버는 내 앱(클라)가 보여준 액세스 토큰을 확인하고 내 앱(클라)에게 리소스를 응답해주는 서버이다.
Authorization server: Resource server가 액세스 토큰을 발급받는 서버. 리소스 오너를 성공적으로 인증한 후 클라에게 액세스 토큰을 발급하는 서버
Authorization grant: 클라가 액세스 토큰을 얻을 때 사용하는 자격 증명, 클라가 액세스 토큰을 얻는 방법. 다음과 같은 방법들이 주로 사용된다.

  • Authorization Code Grant Type
  • Refresh Token Grant Type
  • Client Credentials Grant Type
  • Implicit Grant Type
  • Resource owner Credentials Grant Type

Authorization code: Authorization grant의 한 타입으로, 액세스 토큰을 발급받기 전에 필요한 Code.
Client ID로 이 Code를 받아온 후, Code + Client Secret을 이용해 액세스 토큰을 받아올 수 있다.
즉, 액세스 토큰을 발급받기 위해 Client ID + Client Secret 이 필요한데, 이 두가지가 포함된 일종의 허가증이 Authorization code
Access token: 보호된 리소스에 액세스하는데 사용되는 Credentials. Authorization code와 Client Secret을 이용해 받아온 이 토큰으로 이제 리소스 서버에 접근할 수 있다.
클라에게 발급된 권한을 나타내고 문자열타입이다.
Scope: 토큰의 권한을 정의한다!. 주어진 액세스 토큰을 사용해서 액세스할 수 있는 리소스의 범위. 사진첩에는 접근할수 있어도 연락처 등 다른 리소스에는 접근할 수 없도록 접근 권한을 지정할 수 있다.

즉, 위 case study에서 각자의 역할을 나타내면

Grant type 종류

Grant type이란?

client가 액세스 토큰을 얻는 여러 방법

Authorization Code Grant Type

가장 일반적으로 쓰이는 방법으로, 액세스 토큰을 받아오기 위해서 먼저 Authorization Code를 받은 뒤, 액세스 토큰과 교환하는 방법

Authorization Code 절차를 거치는 이유? 보안성 강화 목적
client에서 client-secret을 공유하고 액세스 토큰을 가지고 오는 것은 탈취될 위험이 있기 때문에, client(내 앱)에서는 Authorization Code만 받아오고, 내 앱의 server가 access token 요청을 진행한다.

액세스 토큰을 발급받고 나면 더이상 client는 Authorization 서버를 통하지 않고, 리소스 서버와 직접적으로 소통한다!

Refresh Token Grant Type

일정 기간 유효 시간이 지나서 만료된 액세스 토큰을 편리하게 다시 받아오기 위해 사용하는 방법

  • 액세스 토큰이 만료될 때마다 사용자에게 인증 권한을 요구하면 유저 입장에서 번거롭기 때문에 클라가 알아서 액세스 토큰 발급해오는 방법
    액세스 토큰 보다 리프레시 토큰의 유효 시간을 대체로 조금 더 길게 설정하기에 가능한 방법이다. 서버마다 리프레시 토큰에 대한 정책이 다르기 때문에 리프레시 토큰을 사용하기 위해서는 사용하고자 하는 서버의 정책을 살펴봐야함.

과제2 - Auth Token

https://codestates.notion.site/codestates/Auth-Basic-fcb9de4219994a2c8cdfad45a328d49d

profile
중요한건 꺾이지 않는 마음이 맞는 것 같습니다

0개의 댓글