[인증/보안] 기초

해피데빙·2022년 3월 16일
0

TIL

목록 보기
37/45

목표
1. 회원 가입 및 로그인, 로그아웃과 같은 기능
2. 이르 통해 인증(authentication) 이해

  • 클라이언트, 서버, 데이터베이스 모두를 다루면서,
    Full Stack 개발 환경에서의 전체적 흐름 및 작동을 직접 확인

📌 암호화, hashing, salting
📌 HTTP vs HTTPS
📌 권한 부여(Authorization)와 인증(Authentication)
📌 쿠키의 작동 원리를 이해
📌 (1)세션 (2)쿠키 (3)토큰 (4)OAuth
-> 인증 구현
📌 클라이언트, 서버, 데이터베이스의 전체 동작을 이해
📌 회원가입 및 로그인 등의 유저 인증 구현, 이해
📌 서비스의 보안과 관련된 방법 이해 + 원리 및 장점 및 단점 이해

HTTPS

  • http란?
    : 인터넷에서 데이터를 주고 받을 수 있는 프로토콜
    : 누구나 중간에 데이터를 볼 수 있어버림

  • https
    : http + secure
    : http 프로토콜 내용을 암호화
    : 키가 없으면 함부로 내용을 볼 수 없음

HTTPS의 특징 3가지

-인증서

  • CA
    -비대칭 키 암호화

인증서

데이터를 제공하는 서버가 정말로 데이터를 보내주는 서버인지 인증, 확인
인증서에 서버 도메인 관련 정보가 있어서 확인 용이
요청을 받은 서버는 인증서와 함께 응답 전송 (응답 속 도메인 === 인증서 속 도메인 이면 서버 신뢰, 데이터 신뢰)

하지만 중간에 해커가 제3자 공격으로 인한 도메인 변경이 일어나면 (인증서 도메인과 응답객체의 도메인이 다를 수 있다 : 이땐 데이터를 신뢰하지 않는다)

CA

공인 인증서 발급 기관
각 브라우저는 신뢰하는 CA가 각각 다르고 그마저도 자격이 박탈될 수 있다

비대칭 키 암호화

전혀 다른 키 한쌍으로 암호화 및 복호화 진행 가능
어느 하나의 키로 암호화를 했다면 복호화 시 다른 키가 필요
암호화 : 키 A
복호화 : 키 B
A와 B는 한쌍 그러므로 하나는 비밀로 숨겨두고 하나는 클라에 공개해 데이터 안전하게 보호

다만 모든 키에 대해 공개키 방식을 사용하면 알고리즘 너무 복잡
그러므로 통신 최초에 비밀키를 만들기 위해서만 공개키 사용

통신 과정
1)hand shake

  • 서로 확인하고
  • 서버가 클라에게 공개키, 인증서 정보 전달
  • 클라에서 인증서에 있는 도메인과 응답에 있는 도메인이 같은지 확인

2)비밀 키 생성

  • 클라는 전달받은 키를 이용해서 서버와 키를 만들어낼 임의의 정보를 암호화해서 전송
  • 서버는 마찬가지로 임의의 정보를 암호화해서 전송

3)상호 키 검증

  • 클라, 서버는 서로 만들고 교환한 임의의 데이터를 바탕으로 비밀 키 생성
  • 각자 생성한 키를 바탕으로 클라가 테스트용 데이터를 만든 비밀키로 암호화해서 전달
  • 서버가 만들어진 비밀키로 복호화하고 다시 암호화해서 클라에 전송
  • 만약 클라가 같은 내용의 데이터를 복호화하는데 성공하면 https 연결 성립

HTTPS 프로토콜

HTTPS란?
Hyper Text Transfer Protocol Secure Socket layer

HTTP 요청을 SSL 혹은 TLS라는 알고리즘을 이용해 HTTP 통신을 하는 과정에서 내용을 암호화해서 데이터를 전송하는 방법

  • SSL, TLS, CA에 대해 더 알아보기

안전, 데이터 제공자의 신원 보장 : HTTPS > HTTP

데이터 제공자의 신원 확인/보장이 인증에서 왜 중요한데?

  • 클라이언트는 데이터 제공자가 준 데이터 사용할 수 밖에
    서버에 데이터 요청을 하고 이후 받은 데이터를 이용해서 화면을 렌더링하는 등의 작업을 해야 한다

  • 그렇게 때문에 요청 및 응답을 중간에 가로채는 중간자 공격에 취약

cf. '중간자 공격'이란?
: 클라이언트와 서버 사이에서 공격자가 서로의 요청, 응답의 데이터를 탈취 및 변조하여 다시 전송하는 공격

데이터가 중간에 다른 도메인을 거쳐서 전달되기 때문에
서버가" 해당 데이터는 https://example.com 도메인에서 제공되었습니다."라는 추가 데이터를 응답 객체에 실어 보낸다면
'중간자 공격'으로 인해 다른 도메인에서 데이터를 받은 클라이언트는 데이터를 제공한 도메인과 전달받은 내용의 도메인을 비교하여 '중간자 공격'이 존재하는지 아닌지 확인할 수 있습니다.

물론 중간자 공격으로 인해 이런 추가 데이터 또한 변조할 수 있습니다.
따라서 해당 데이터를 암호화시키는 작업이 필요합니다.

암호화

HTTPS 프로토콜의 특징 중 하나는 암호화된 데이터를 주고받기 때문에, 중간에 인터넷 요청이 탈취되더라도 그 내용을 알아볼 수 없습니다. 그러므로 복호화 전까지는 어떤 내용인지 알 수 없다.

인증서

HTTPS 프로토콜의 또 다른 특징 중 하나
: 브라우저가 응답과 함께 전달된 인증서 정보를 확인할 수 있다

브라우저는 인증서에서 해당 인증서를 발급한 CA 정보를 확인하고
인증된 CA가 발급한 인증서가 아니라면 화면에 경고창을 띄워 서버와 연결이 안전하지 않다는 화면을 보여줍니다

인증서의 도메인과 서버의 응답 객체의 도메인이 같으면 safe
다르면 중간자 공격에 의해 다른 도메인을 거치면서 달라진 것
브라우저들은 인증된 CA가 발급한 인증서를 이용하여 데이터를 제공하는 안전한 서버를 사용할 수 있게 사용자를 유도!

실습

로컬 환경에서 인증서를 생성

1)mkcert라는 프로그램을 이용해서 로컬 환경에서 신뢰할 수 있는 인증서 만들기

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

$ brew install mkcert

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

$ mkcert -install

3)로컬 환경에 대한 인증서 생성
: localhost로 대표되는 로컬 환경에 대한 인증서를 만들려면 다음 명령어를 입력해야 합니다.

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

-> localhost, 127.0.0.1, ::1 에서 사용할 수 있는 인증서 완성
-> cert.pem, key.pem 파일 생성

계속 사용해야 하니까 저장 경로 확인
인증서는 공개키, 인증기관의 서명 포함 (공개되어도 무관)
key.pem은 개인 키이므로 git에 커밋하지 않고 암호처럼 다뤄야!

인증서 이용 https 서버 만들기

1.http 내장 모듈 사용하는 방법
2.express 사용하는 방법

먼저 인증서를 https 서버에 적용하기

Node.js https 모듈 이용


key.pem, cert.pem 파일을 읽어서 createServer의 첫번째 인자로 넣는다
확인하는 방법 : 브라우저의 url창 왼쪽에 자물쇠가 잠겨있다

express.js 이용

위의 코드 중 createServer의 두번째 파라미터에 들어갈 callback 함수를 express 미들웨어로 교체

ngrok

기존에 작성한 HTTP 서버를 https://ngrok.com/를 이용해서 HTTPS로 터널링 가능

Hashing

인증 과정 없이 이메일 관련 정보를 얻으면
클라 -요청-> 서버 -> db
but 보안상의 issue (이메일만 알면 다 가능)

그럼 pw를 가지로 요청하면?
비교해보는 과정을 통해 맞으면 db에서 찾아서 응답으로 돌려주는 것
pw를 db에서 해킹 당할 수 있으니 위험
그러므로 암호화해서 저장

암호화란?

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

암호화 예시

클라 요청 중 pw -> 서버에서 암호화(알고리즘) -> db와 확인해서 맞으면 db의 암호화된 내용을 찾는다

Hashing이란?

임의의 연산을 적용하여 다른 문자열로 변환하는 것
1. 모든 값에 대해 해시 값을 계산하는데 오래 걸리지 않아야
2. 최대한 해시 값을 피해야 하며 모든 값은 고유한 해시 값을 가진다
-> 결과물이 같으면 안된다
3. 아주 작은 단위의 변경이라도 완전히 다른 해시 값을 가져야 한다

salt

암호화해야 하는 값에 어떤 별도의 값을 추가하여 결과를 변형하는 것
해싱만 하면 테이블을 만들어서 decoding을 해버릴 수 있으니까
그러므로 원본 값에 임의로 약속된 별도의 문자열을 추가하여 해시를 진행하면
기존 해시값과 전혀 다른 해시값이 전환되어 알고리즘이 노출되더라도 원본 값 보호 가능하게 하는 안전 장치

기존 : 암호화하려는 값 - 서버에 있는 알고리즘 -> hash값
salt 사용 : 암호화하려는 값 + salt용 값 -> hash값

salt 사용 시 주의점

Cookie

http 요청은 stateless
서버에서 브라우저에서 보내는 요청에 대한 정보를 저장하고 있지 않는다
그런데 장바구니 등 정보 저장할 수 있게 하는 방법: 쿠키

쿠키란?
어떤 웹사이트에 들어갔을 때 서버가 일방적으로 클라이언트에 전달하는 작은 데이터
서버가 웹 브라우저에 정보 저장 및 불러올 수 있는 수단
해당 도메인에 대해 쿠키가 존재하면, 웹 브라우저는 도메인에게 http 요청 시 쿠키와 함께 전달

cf. 브라우저가 도메인에게 http 요청을 한다 도메인도 서버인가 찾아보기

쿠키 이용법
서버는 쿠키를 통해 저장하려는 정보 (장기적으로 저장하기에 좋다, 삭제하지 않으면 계속 남아있음)
그러므로 사용자 선호, 로그인 상태 유지, 테마 등에 사용
쿠키 인증 정보는 해싱 처리가 되어 있다
하지만 쿠키는 자바스크립트로 접근 가능해서 불안불안

쿠키 전달방법

서버가 응답 헤더의 set-Cookie: 쿠키 이름, 경로, 옵션 등
클라는 받은 응답의 헤더의 set-Cookie 확인, 요청마다 쿠키의 이름과 값을 서버에 전달

서버가 쿠키를 저장하면 매요청마다 쿠키가 간다
그러므로 이를 통해 로그인 유지, 테마 유지 등 가능

cookie option

httpOnly : 자바스크립트는 접근 못하고 브라우저에서만 접근 가능하도록 할 수 있다
xss 공격에 취약하므로 (document.cookie로 접근 가능)
그러므로 민감한 내용 넣지 말기
sameSite : cors의 옵션에 대해서만 send
cors 요청에 대해 메소드에 따라 서버가 쿠키를 전송할지 말지
cross-origin 요청을 받은 경우 요청에서 사용한 메소드와 sameSite 옵션의 조합으로 서버의 쿠키 전소 ㅇ여부 결정하게 된다

원래 쿠키는 자바스크립트에서 접근 가능
그러므로 내가 로그아웃을 안 하고 나가버리면 누군가 접근 가능
그러므로 maxAge 혹은 Expires 옵션을 통해 기한을 정해주면 좋음


none만 쓰면 위험하니까!

https://kosaf04pyh.tistory.com/152
같은 오리진이라는 걸 보여주니까

Session

session 활성화, 연결 등
session은 서버와 클라이언트 간의 연결이 활성화된 것 의미

쿠키 : 클라에 정보 저장
세션 : 서버에 정보 저장
-> 쿠키에 있는 데이터에 대한 id만 암호화해서 전달

  • 서버가 client에 유일하고 암호화된 ID를 부여
  • 중요 데이터는 서버에서 관리

  • 세션도 쿠키에 유저의 정보를 넣는다
    클라의 요청 - 서버 - db - db에서 session_id반환 - 서버에서 암호화(set-Cookie헤더로) - 클라의 쿠키에 저장
    같은 유저의 클라의 요청 (위에서 받은 session_id를 가지고 요청) -> 서버 -> db에서 session_id가 같은지 확인하고 업데이트 후 서버에서 클라에게 업데이트되었다는 응답을 전송

쿠키 vs 세션

쿠키 : user가 삭제하거나 유효기간이 없으면 영원히 저장, 그러므로 인증 정보를 넣기에는 보안 별로
그저 http의 stateless 보완
세션 : 클라에게 인증 정보를 저장하지 않고 클라마다 id를 쿠키에 담아 클라에 전송
즉 클라의 중요한 정보는 서버에서 관리
클라는 전달받은 쿠키를 매 요청마다 자동으로 서버에 요청, 쿠키 안에 있는 session_id를 주기 때문에 db와 비교해서 돌려준다
브라우저에 쿠키를 저장하니까 서버 메모리에 부담 적음
신뢰할 수 있는 유저인지 서버에서 추가로 확인 가능( 요청 정보에서 더 검증 가능 )
하지만 하나의 서버에서만 접속 상태를 가지므로 분산에 불리

세션의 단점
1. 서버의 메모리에 세션 정보 저장
그러므로 서버의 이용자가 너무 많으면 서버의 일정 공간 가용 불가능
그러므로 서버의 성능 저하

  1. 쿠키의 단점
    : xss 공격에 취약 ( option이 따로 없으면 자바스크립트로 접근 가능)
    즉 개인 정보 탈취 위험 높음

express-session

세션을 대신 관리해주는 모듈
세션을 위한 미들웨어,

  • express에서 세션을 다룰 수 있는 공간을 보다 쉽게 만들어준다
  • 필요한 경우 세션 아이디를 쿠키에 저장
  • 해당 세션 아이디에 종속되는 고유한 세션 객체(req.session)를 서버 메모리에 저장
  • 세션 객체는 서로 독립적인 객체이므로 각각 다른 데이터 저장 가능
    =>세션 객체에 세션 데이터를 저장하거나 불러오기 위해 사용
    => 세션 객체에 값을 담거나, 조회하거나, 파괴하는 법
    참고 문서 : https://github.com/expressjs/session#reqsession

세션 Sprint

답지: https://velog.io/@bleach7/TIL-13%EC%A3%BC%EC%B0%A8-1%EC%9D%BC-Sprintauth-session

본격적으로 로그인을 통해 인증 정보가 저장되고,
인증된 사용자가 어떤 식으로 웹사이트를 이용하는지 간단하게 알아봅시다.

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

사용자가 만일 정확한 아이디와 비밀번호를 입력했다면, 서버는 인증(Authentication)에 성공했다고 판단할 것입니다. 그렇다면, 다음번에 인증을 필요로 하는 작업(그림에서와 같이, 장바구니에 물품 추가)을 요청할 경우, 또 로그인 과정을 거쳐야 할까요? 아닙니다. 서버는 아이디 및 비밀번호의 해시를 이미 알고 있기 때문에, "인증에 성공했음"을 서버가 알고 있다면, 매번 로그인할 필요가 없을 것입니다.

인증에 따라 리소스의 접근 권한(Authorization)이 달라집니다

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

서버는 사용자가 인증에 성공했음을 알고 있어야 합니다.
클라이언트는 인증 성공을 증명할 수단을 갖고 있어야 합니다.
여기서 몇 가지 용어가 등장합니다.

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

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

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

로그아웃
그렇다면, 로그아웃은 어떻게 구현해야 할까요? 세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있습니다. 서버는 그저 세션 아이디로만 요청을 판단합니다.

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

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

서버의 세션 정보를 삭제해야 합니다.
클라이언트의 쿠키를 갱신해야 합니다.
서버가 클라이언트의 쿠키를 임의로 삭제할 수는 없습니다. 대신, set-cookie로 세션 아이디의 키값을 무효한 값으로 갱신해야 합니다.

express-session
이런 세션을 대신 관리해 주는 'express-session' 이라는 모듈이 존재합니다.

다만 코딩을 바로 시도하기보다 아래 설명을 참고하여 모듈의 역할 및 사용법을 공부해 보세요.

'express-session'은 세션을 위한 미들웨어로, 'Express'에서 세션을 다룰 수 있는 공간을 보다 쉽게 만들어줍니다.

또한 필요한 경우 세션 아이디를 쿠키에 저장하고, 해당 세션 아이디에 종속되는 고유한 세션 객체를 서버 메모리에 저장합니다.
이때 세션 객체는 서로 독립적인 객체이므로 각각 다른 데이터를 저장할 수 있습니다.

질문
세션에서 사용되는 세션 쿠키는 어떤 역할을 담당하고 있을까요?
쿠키만으로 인증을 구현할 때 왜 위험할까요?
전부 다 완성한 상태에서 로그아웃할 수 있는 방법은 쿠키를 삭제하는 방법, 또는 서버를 재시작하는 방법밖에는 없습니다. 로그아웃을 구현하려면 어떻게 해야 할까요?

CSRF

web application security란?
개발자들이 웹사이트, 모바일 어플, 웹 API 등을 만들 때 해커들의 공격을 막기 위한 보안

여러가지 공격들

  • SQL injection
  • XSS
  • CSRF

다른 오리진에서 유저가 보내는 요청을 조작하는 것

토큰 기반 인증

세션 기반 인증
: 서버(혹은 DB)에 유저 정보를 담는 인증 방식
-> 서버: 유저의 요청마다 세션 값과 db 조회해서 세션 값 일치하는지 확인
-> 부담되므로 토큰 기반 인증 중 대표적인 JWT (JSON Web Token) 사용

클라이언트에서 인증 정보 보관하기

토큰이란?
= 동전
"나는 돈을 지불했고, 이 시설을 사용할 수 있어!"
-> 클라이언트에서 인증 정보를 보관하는 방법

클라이언트가 토큰을 가지고 있다면
보통의 다른(돈을 내지 않은) 유저들과는 다르게 서버에서 제공하는 다양한, 더 프리미엄한 기능을 요청할 수 있을 것입니다.

BUT 클라는 xss, csrf 공격에 취약하지 않았나??
인증에 사용되는 걸 클라에 담는다고?

토큰을 클라에 저장해도 되는 이유
: 토큰은 유저 정보를 암호화한 상태로 담을 수 있고, 암호화했기 때문에 클라이언트에 담을 수 있습니다.

JWT의 종류
1. Access Token
2. Refresh Token

Access token
: 보호된 정보들(유저의 이메일, 연락처, 사진 등)에 접근할 수 있는 권한부여에 사용
: 클라이언트가 처음 인증을 받게 될 때(로그인 시)
access, refresh token 두 가지를 다 받는다
: 실제로 권한을 얻는 데 사용하는 토큰은 access token입니다.

그럼 access token만 있으면 되는 것 아닌가요?

하지만 access token이 해커에게 유출되면이 유저인 것 마냥 서버에 여러 가지 요청을 보낼 수 있다
그렇기 때문에 access token에는 비교적 짧은 유효 기간 을 주어 탈취되더라도 오랫동안 사용할 수 없도록 한다.

Access token의 유효기간이 만료된다면 refresh token을 사용하여 새로운 access token을 발급.
이때, 유저는 다시 로그인할 필요가 없습니다.

refresh token도 탈취 당하면?

상당히 오랜 기간 동안 access token이 만료되면 다시 발급받으며 유저에게 피해를 입힐 수 있기 때문이죠. 그러므로 유저의 편의보다 정보를 지키는 것이 더 중요한 웹사이트들은 refresh token을 사용하지 않는 곳이 많다. 세상에 완벽한 보안은 없기 때문에 (있다면 쿠키, 세션, JWT, OAuth 등 다양한 방법들을 공부하지 않아도 되겠죠!) 각 방법들의 장단점을 참고하며 필요에 맞게 사용하는 것이 좋습니다.

JWT 구조
image

JWT는 위 그림과 같이 . 으로 나누어진 3부분이 존재합니다.

Header

이것이 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 sign할지가 적혀있습니다. JSON Web Token이라는 이름에 걸맞게 JSON 형태로 이런 형태를 보실 수 있습니다.

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

이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫 번째 부분이 완성됩니다.

Payload

정보가 담겨 있습니다.

  • 어떤 정보에 접근 가능한지에 대한 권한
  • 사용자의 유저 이름 등 필요한 데이터
    => 이곳에 담아 Sign 시킨다
    민감한 정보는 되도록 담지 않는 것이 좋습니다.
{
  "sub": "someInformation",
  "name": "phillip",
  "iat": 151623391
}

첫 번째 부분과 마찬가지로, 위 JSON 객체를 base64로 인코딩하면 JWT의 두 번째 블록이 완성됩니다.

Signature

base64로 인코딩된 첫 번째, 그리고 두 번째 부분이 완성되었다면, 원하는 비밀 키(암호화에 추가할 salt)를 사용하여 암호화합니다. base64 인코딩을 한 값은 누구나 쉽게 디코딩할 수 있지만, 서버에서 사용하고 있는 비밀키를 보유한 게 아니라면 해독해 내는데 엄청난 시간과 노력이 들어갈 겁니다!

예를 들어, 만약 HMAC SHA256 알고리즘(암호화 방법 중 하나)을 사용한다면 signature는 아래와 같은 방식으로 생성됩니다.

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

JWT 사용 예시

JWT는 권한 부여에 굉장히 유용합니다. 새로 다운받은 A라는 앱이 Gmail과 연동되어 이메일을 읽어와야 한다고 생각해 봅시다. 유저는 Gmail 인증서버에 로그인 정보(아이디, 비밀번호)를 제공한다
성공적으로 인증 시 JWT를 발급받는다
A 앱은 JWT를 사용해 해당 유저의 Gmail 이메일을 읽거나 사용할 수 있다

토큰기반 인증 절차
클라이언트가 서버에 아이디/비밀번호를 담아 로그인 요청을 보낸다.
아이디/비밀번호가 일치하는지 확인하고, 클라이언트에게 보낼 Signature 된 토큰을 생성한다.
access/refresh 토큰을 모두 생성한다.
토큰에 담길 정보(payload)는 유저를 식별할 정보, 권한이 부여된 카테고리(사진, 연락처, 기타 등등)이 될 수 있다.
두 종류의 토큰이 같은 정보를 담을 필요는 없다 (이 스프린트에서는 같은 정보를 담아줍시다).
토큰을 클라이언트에게 보내주면, 클라이언트는 토큰을 저장한다.
저장하는 위치는 local storage, cookie, react의 state 등 다양하다.
클라이언트가 HTTP 헤더(authorization 헤더)에 토큰을 담아 보낸다.
bearer authentication을 이용한다. 참고 링크1(요약), 링크2(상세)
서버는 토큰을 해독하여 "아 우리가 발급해 준 토큰이 맞네!"라는 판단이 될 경우, 클라이언트의 요청을 처리한 후 응답을 보내준다.
image

토큰기반 인증의 장점
Statelessness & Scalability (무상태성 & 확장성)
서버는 클라이언트에 대한 정보를 저장할 필요 없습니다 (토큰 해독이 되는지만 판단합니다)
클라이언트는 새로운 요청을 보낼 때마다 토큰을 헤더에 포함시키면 됩니다
서버를 여러 개 가지고 있는 서비스라면 더더욱 빛을 발휘합니다 (같은 토큰으로 여러 서버에서 인증 가능)
안전하다
signature을 받은 토큰을 사용하고, 암호화 키를 노출할 필요가 없기 때문에 안전합니다
어디서나 생성 가능하다
토큰을 확인하는 서버가 토큰을 만들어야 하는 법이 없습니다
토큰 생성용 서버를 만들거나, 다른 회사에서 토큰 관련 작업을 맡기는 것 등 다양한 활용이 가능합니다
권한 부여에 용이하다
토큰의 payload(내용물) 안에 어떤 정보에 접근 가능한지 정할 수 있습니다
ex) 서비스의 사진과 연락처 사용 권한만 부여

기존 HTTP 방식보다 더 안전한 통신 프로토콜
클라이언트와 서버가 연결된 통로(암호화된 채널)
기밀성 : 다른 사용자들이 전달되는 메시지를 가로챌 수 없다
무결성 : 다른 사용잗르이 전달되는 메시지를 조작할 수 없다

공개 키 암호화 방식을 사용한다
비대칭 키 암호화
공개 키로 암호화, 비공개 키(개인키)로 복호화

비대칭 키 암호화에 대한 설명은?
해싱 : 전달받은 해시값을 검사하여 데이터 변조가 없었는지 무결성을 확인하기 위함
암호화 : 허락하지 않은 사용ㅇ자에게 데이터 노출을 막는 것
암호화는 퍼블릭키, 복호화는 프라이빗키로

해싱과 암호화의 큰 차이
해싱 : 데이터 변조의 유무를 확인, 무결성을 확인하는 것이 주 목적
암호화 :
암호화와 복호화할 때 같은 키 사용 (대칭 키)

암호화한 데이터는 그에 맞는 private key로만이 복호화 가능
개인키로 암호화한 데이터는 public key로는 복호화가 불가능

해시 함수
해싱알고리즘은 거의 불가능하지만 가능은 함
해시 충돌(다른 입력값인데도 같은 출력값을 가질 때)
그러므로 output이 길수록 겹치지 않을 수 있어 더 강한 보안 가능
ex. SHA512

SHQ-256 알고리즘을 사용했을 경우 출력값의 길이는 언제나 동일
: 256bit
: 64개의 문자 출력

같은 해시값을 리턴한다면 민감한 정보를 암호화해서 돌려줄 수 없다
클라 -> 서버(암호화) -> 데이터베이스(암호화되어 저장)

해시 알고리즘도 순수함수
입력값이 다르면 해시된 출력값도 모두 다르다

해시 충돌
input이 output보다 길면 출력할 수 있는 조합이 한정적

쿠키에 대한 설명으로 올바른 답
삭제하지 않는 한 항상 쿠키는 영원히 보존되지 않는다
: maxAge, expiresAt

모든 쿠키는 자바스크립트를 이용해서 접근 가능하지 않음
: httpsOnly를 사용하면 막을 수 있다

이중 하나만 js로 볼 수 없다

httpOnly 옵션을 이용한 것

sameSite 옵션
-lax : 사이트가 서로 달라도, GET 요청이라면
-none
-strict


둘은 항상 같이 설정해줘야 한다

하나의 웹사이트에서 세가지 주소에 접근
이때 1st party cookie, 3rd party cookie
: 어디까지 허용을 할지를 보여주는 용도
: sameoriginpolicy - 동일 출처 정책과 sameSite를

쿠키에서 사용할 수 있느 옵션들 3가지 이상

sameSite 옵션의 설명
Lax
Strict
None

1st party cookie
3rd party cookie

한 사이트에 있는 수많은 이미지
: 모두 한 사이트에서 가지고 있는 게 아니다
: 외부의 다양한 도메인에서 가져오는 것
(이 안에는 http 요청)

클릭하면 네이버에 로그인 되어 있는 상황 (네이버의 인증 토큰 or 세션ID존재)에서 네이버에 해커가 요청을 보낼 수 있게 도니다
POST naver.com/comment
csrf를 차단할 수 있는 방법은?
인증서를 통해 도메인 확인
lax로 csrf를 원천 봉쇄

session 기반 인증 vs cookie 기반 인증
session : 서버에 저장
cookie : 브라우저에 저장 (서버와 함께 사용)

여러 개의 서버를 가지고 있을 때 유리하다

서버가 확장이 되어서 늘렸을 때 바로 서버에 요청을 하는 것이 아니라 load balancer라는 것을 통해 안 바쁜 서버에 요청을 보낸다
post/login -> load balancer -> 과부하되지 않은 서버에 보내 저장, session id를 포함한 응답을 클라이언트에 보낸다
get/myinfo를 할 때 다른 서버에 보내면 확인할 수 없음

=> 해결방법 : session storage (session id를 저장해주는 새로운 db를 만든다)

서버가 분산 되어 있는 시스템에서 세션은 굉장히 불리

토큰은 어떤 서버로 보내든 정보를 저장하지 않고 verify만 해서 돌려보내기 때문에 적합

세션 기반 인증 대신 토큰 기반 인증 사용을 고려한다면 그 이유는?
-서버의 부담을 덜어주기 위해
-앱의 확장 고려 중
-여러 개의 서버를 사용하는 서비스를 운영할 때

  • 더 안전한 건 아니다

세션 vs 토큰

세션 : 은행에서 많이 사용 ex. '세션이 만료되었습니다'
은행은 보안팀이 많다
그러므로 서버에서 확인하는 것이 낫다고 생각(서버 위주)

보안이 덜 중요하고 확장성이 높은 사이트는 토큰 사용
토큰에서의 보안은 signature덕분
signature는 서버만 가지고 있으므로 보안

header, payload 암호화 + secret key

token Sprint

답지: https://velog.io/@devjade/Token-based-Authentication-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B3%B4%EA%B8%B0server-client

  1. server라고 이름을 바꿔줘야 한다
    index.js파일에서 module.exports가 server로 되어 있음
    그러므로 httpServer를 server로 바꿔준다

  2. 인증서를 다운 받아서 연결
    login.js부터 작성

  3. package.json의 start에 fillmein 부분에 파일 이름을 넣으면 된다

  4. client -> server : 요청

  5. init까지 되어 있는 상태니까
    1)migration만 해주면 된다
    2)running seed
    npx sequelize db:seed:all;

  6. post/login 요청 -> id/pw 를 db에서 확인을 해야 한다 -> id/pw가 있으면 클라에 토큰을 날린다
    1)db에서 결과물을 받아올 때 await를 해야 한다
    let userInfo = await Users.findOne({where:
    { userId : req.body.userId, password : req.body.password } })

2)토큰 생성
const token = jwt.sign(payload, secret key, option)
ACCESS_SECRET, REFRESH_SECRET에 값을 넣는다
process.env.ACCESS_SECRET를 통해 값을 가져와서 쓴다
jwt npm 사이트가서 보면 옵션 확인 가능

TOKEN 발행해서 refresh token
access token을 가지고 있다가 유효기간이 끝나면 refresh token

access_secret : 우리가 부여해주는 것!
-> salt 개념

3)

profile
노션 : https://garrulous-gander-3f2.notion.site/c488d337791c4c4cb6d93cb9fcc26f17

0개의 댓글