-
[Backend] 인증/보안경남_ABC_FE/Section_3 2023. 12. 6. 12:09
Https
Https는 Http와 달리 요청과 응답으로 오가는 내용을 암호화한다.
암호화 방식
대칭 키 암호화 방식
대칭 키 암호화 방식은 하나의 키만 사용한다. 암호화할 때 사용한 키로만 복호화가 가능하다.
두 개의 키를 사용해야 하는 공개 키 방식에 비해서 연산 속도가 빠르다는 장점이 있다.
공개 키(비대칭 키) 암호화 방식
누구든 공개 키를 사용해서 암호화한 데이터를 보내면, 비밀 키를 가진 사람만 그 내용을 복호화할 수 있다.
보통 요청을 보내는 사용자가 공개 키를, 요청을 받는 서버가 비밀 키를 가진다.
하지만 대칭 키 방식보다 더 복잡한 연산이 필요하여 더 많은 시간을 소모한다는 단점이 있다.
public key로 암호화하면 Data 보안에 중점을 두고, private key로 암호화하면 인증 과정에 중점을 둔다.
SSL/TLS 프로토콜
HTTPS는 HTTP 통신을 하는 소켓 부분에서 SSL 혹은 TLS라는 프로토콜을 사용하여 서버 인증과 데이터 암호화를 진행한다.
SSL이 표준화되며 바뀐 이름이 TLS이므로 사실상 같은 프로토콜이다.
- CA를 통한 인증서 사용
- 대칭 키, 공개 키 암호화 방식을 모두 사용
인증서와 CA(Certificate Authority)
HTTPS를 사용하면 브라우저가 서버의 응답과 함께 전달된 인증서를 확인할 수 있다.
인증서를 발급해주는 공인된 기관들을 CA라고 부른다.
- 서버는 인증서를 발급받기 위해 CA로 서버의 정보와 공개 키를 전달한다.
- CA는 공개키와 정보를 CA의 비밀키로 암호화하여 인증서를 발급한다.
- 서버는 클라이언트에게 요청을 받으면 CA에게 발급받은 인증서를 보내준다. (이때 사용자가 사용하는 브라우저는 CA들의 리스트와 공개 키를 내장하고 있다.)
- CA의 비밀 키로 암호화된 데이터(인증서)는 CA의 공개 키로만 복호화가 가능하므로, 정말로 CA에서 발급한 인증서가 맞다면 복호화가 성공적으로 진행되어야 한다.
대칭 키 전달
이제 공개 키는 클라이언트와 서버가 함께 사용하게 될 대칭 키를 주고받을 때 쓰인다.
- 클라이언트는 데이터를 암호화하여 주고받을 때 사용할 대칭 키를 생성한다.
- 클라이언트는 생성한 대칭 키를 서버의 공개 키로 암호화하여 전달한다.
- 서버는 전달받은 데이터를 비밀 키로 복호화하여 대칭 키를 확보한다.
-> 서버와 클라이언트 간의 CA를 통해 서버를 인증하는 과정과 데이터를 암호화하는 과정을 아우른 프로토콜을 SSL 또는 TLS이라고 말하고, HTTP에 SSL/TLS 프로토콜을 더한 것을 HTTPS라고 한다.
Cookie
쿠키는 서버에서 클라이언트에 영속성 있는 데이터를 저장하는 방법이다.
쿠키를 이용하는 것은 단순히 서버에서 클라이언트에 쿠키를 전송하는 것만 의미하지 않고 클라이언트에서 서버로 쿠키를 다시 전송하는 것도 포함된다.
특징 : 서버가 클라이언트에 특정한 데이터를 저장할 수 있다.
하지만 데이터를 저장한 이후 아무 때나 데이터를 가져올 수는 없다. 데이터를 저장한 이후 특정 조건들이 만족되어야 다시 가져올 수 있다.
Session
사용자가 인증에 성공한 상태는 세션이라고 부른다.
세션이 만들어지면, 각 세션을 구분할 수 있는 세션 아이디도 만들어지는데, 보통 클라이언트에 세션 성공을 증명할 수단으로써 세션 아이디를 전달한다.
이때 웹사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용한다. 쿠키에는 서버에서 발급한 세션 아이디를 저장한다.
클라이언트에서 세션 정보를 없애기 위해서는 res.cookie로 쿠키의 값을 무효한 값으로 변경하거나, res.clearCookie로 쿠키를 삭제해버리면 된다.
express-session
Node.js에는 이런 세션을 대신 관리해주는 express-session이라는 모듈이 존재한다.
express-session은 세션을 위한 미들웨어로, express 서버에서 쉽게 세션을 위한 공간을 다룰 수 있도록 만들어준다.
세션 객체는 req.session 으로 접근할 수 있으며 이를 통해 세션에 임의의 데이터를 저장하거나 불러올 수 있다.
Hashing
복호화가 가능한 다른 암호화 방식들과 달리, 해싱은 암호화만 가능하다.
해싱은 해시 함수를 사용하여 암호화를 진행하는데, 해시 함수는 다음과 같은 특징을 가진다.
- 항상 같은 길이의 문자열을 리턴한다.
- 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값이 나온다.
- 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나온다.
레인보우 테이블과 솔트
레인보우 테이블에 기록된 값의 경우에는 유출이 되었을 때 해싱을 했더라도 해싱 이전의 값을 알아낼 수 있으므로 보안상 위협이 될 수 있다.
이때 활용할 수 있는 것이 솔트이다.
솔트는 말 그대로 해싱 이전 값에 임의의 값을 더해 데이터가 유출되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 만드는 방법이다.
해싱의 목적
해싱의 목적은 데이터 그 자체를 사용하는 것이 아니라, 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적이다.
해싱은 민감한 데이터를 다루어야 하는 상황에서 데이터 유출의 위험성은 줄이면서 데이터의 유효성을 검증하기 위해서 사용되는 단방향 암호화 방식이다.
Token
토큰을 사용하면 사용자의 인증 정보를 서버가 아닌 클라이언트 측에 저장할 수 있다.
토큰 인증 방식의 등장 배경
토큰 기반 인증은 기존의 세션 기반 인증이 가지고 있던 한계를 극복하고자 고안되었다.
토큰은 유저의 인증 상태를 클라이언트에 저장할 수 있어서, 세션 인증 방식에 비교해 서버의 부하나 메모리 부족 문제를 줄일 수 있다.
웹 보안에서의 토큰은 인증과 권한 정보를 담고 있는 암호화된 문자열을 말한다.
토큰 인증 방식의 흐름
- 사용자가 인증 정보를 담아 서버에 로그인 요청을 보낸다.
- 서버는 데이터베이스에 저장된 사용자의 인증 정보를 확인한다.
- 인증에 성공했다면 해당 사용자의 인증 및 권한 정보를 서버의 비밀 키와 함께 토큰으로 암호화한다.
- 생성된 토큰을 클라이언트로 전달한다.
- 클라이언트는 전달받은 토큰을 저장한다.
- 클라이언트가 서버로 리소스를 요청할 때 토큰을 함께 전달한다.
- 서버는 전달받은 토큰을 서버의 비밀 키를 통해 검증한다.
- 토큰이 유효하다면 클라이언트의 요청에 대한 응답 데이터를 전송한다.
토큰 인증 방식의 장점
- 무상태성 : 서버가 유저의 인증 상태를 관리하지 않는다. 서버는 비밀 키를 통해 클라이언트에서 보낸 토큰의 유효성만 검증하면 되기 때문에 무상태적인 아키텍처를 구축할 수 있다.
- 확장성 : 다수의 서버가 공통된 세션 데이터를 가질 필요가 없다.
- 어디서나 토큰 생성 가능 : 토큰의 생성과 검증이 하나의 서버에서만 이루어지지 않아도 되기 때문에 토큰 생성만을 담당하는 서버를 구축할 수 있다.
- 권한 부여에 용이 : 토큰은 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있기 때문에 사용자 권한 부여에 용이하다.
JWT (JSON Web Token)
JWT는 JSON 객체에 정보를 담고 이를 토큰으로 암호화하여 전송할 수 있는 기술이다.
Header
Header에는 마치 HTTP의 헤더처럼 해당 토큰 자체를 설명하는 데이터가 담겨 있다.
이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫번째 부분인 Header가 완성된다.
Payload
Payload는 HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있는 부분이다.
이 JSON 객체를 base64 방식으로 인코딩하면 JWT의 두번째 부분인 Payload가 완성된다.
Signature
Signature는 토큰의 무결성을 확인할 수 있는 부분이다. Header와 Payload가 완성되었다면, Signature는 이를 서버의 비밀키(암호화에 추가할 salt)와 Header에서 지정한 알고리즘을 사용해서 해싱한다.
토큰 인증 방식의 한계
무상태성
인증 상태를 관리하는 주체가 서버가 아니므로, 토큰이 탈취되어도 해당 토큰을 강제로 만료시킬 수 없다.
유효 기간
토큰이 탈취되는 상황을 대비해서 유효 기간을 짧게 설정하면, 사용자는 토큰이 만료될 때마다 다시 로그인을 진행해야 하기 때문에 좋지 않은 사용자 경험을 제공한다. 그렇다고 유효 기간을 길게 설정하면 토큰이 탈취될 경우 더 치명적으로 작용할 수 있다.
토큰의 크기
토큰에 여러 정보를 담을 수 있는 만큼, 많은 데이터를 담으면 그만큼 암호화하는 과정도 길어지고 토큰의 크기도 커지기 때문에 네트워크 비용 문제가 생길 수 있다.
액세스 토큰과 리프레시 토큰
토큰 인증의 한계를 극복하기 위해 다양한 방법들이 고안되었지만 이 중 대표적인 구현 방법은 액세스 토큰과 리프레시 토큰을 함께 사용하는 것이다.
Access Token
액세스 토큰은 말 그대로 서버에 접근하기 위한 토큰으로 앞서 다룬 토큰과 비슷한 역할을 한다. 따라서 보안을 위해 보통 24시간 정도의 짧은 유효기간이 설정되어 있다.
Refresh Token
리프레시 토큰은 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급하기 위해 사용되는 토큰이다. 따라서 리프레시 토큰은 액세스 토큰보다 긴 유효기간을 설정한다.
-> 이렇게 두 가지의 각기 다른 토큰을 사용하는 경우, 액세스 토큰이 만료되더라도 리프레시 토큰의 유효기간이 남아있다면 사용자는 다시 로그인을 할 필요 없이 지속해서 인증 상태를 유지할 수 있다.
-> 물론 리프레시 토큰의 도입도 모든 문제를 해결해주진 않는다.
세션 토큰 인증 상태를 저장하는 곳 서버 클라이언트 장점 서버에서 인증 상태 관리 가능 서버의 무상태성으로 인한 확장성 한계 서버 간 세션 데이터 공유
혹은 Sticky Session 필요서버에서 인증 상태 관리 불가
ex) 강제 로그아웃 불가쿠키 vs 세션 vs 토큰
헷갈려서 노마드 코더 유투브 영상 보고 정리
https://www.youtube.com/watch?v=tosLBcAX1vk
쿠키는 도메인에 따라 제한됨
예를 들면, 유투브가 준 쿠키는, 유투브에만 보내지게 된다.
HTTP는 stateless
-> 서버에게 요청할 때마다 우리가 누군지 알려줘야 함
-> 이를 하는 방법 중 하나가 세션
세션에는 별도의 ID가 있다.
해당 세션 ID는 쿠키를 통해 브라우저로 돌아오고 저장된다.
브라우저가 쿠키를 가지고 서버에 요청을 보내면
서버는 해당 세션 ID를 가지고 세션 DB를 확인하고 서버는 우리가 누군지 알게 된다.
기억해야 할 것은 중요한 유저 정보가 모두 서버에 있다는 것!!!
유저가 가지고 있는 것은 세션 ID 뿐이다.
쿠키는 단지 세션 ID를 전달하기 위한 매개체이다!!!
쿠키는 브라우저에만 있기 때문에 네이티브 앱에서는 사용 불가하다.
-> 바로 이 경우, 토큰 사용!!!
세션에서 중요한 점은 모든 세션 ID를 DB에 저장해야 한다는 것
-> 요청을 읽을 때마다 DB를 찾고 해야한다는 것
-> 유저가 늘어남에 따라 DB 리소스가 더 필요하다!!!
-> JWT 등장
JWT를 사용하면 세션 DB를 가질 필요가 없고, 서버는 많은 일을 하지 않아도 됨!!!
JWT는 길이 제한이 없어서 (쿠키와 달리) 길이가 엄청 길어도 됨.
세션과 JWT의 가장 큰 차이점
-> 세션에선 그냥 세션 ID만 주면 됨 -> DB에서 해당 정보 검색
-> JWT에선 DB를 거칠 필요 없이 토큰이 유효한지만 검증하면 됨
세션은 DB에 저장된 정보를 이용해 기능을 추가할 수 있다.
예를 들면, 유저를 삭제하고 싶으면 세션을 삭제해버리기만 하면 된다.
등등 이 가능한 것은 서버가 누가 로그인 했는지 저장했고, 세션 DB가 있기 때문!!!
-> 이를 위해선 DB가 필요한데, 해당 목적을 수행하기 위한 빠르고 저렴한 DB가 바로 redis!
JWT에서 서버가 아는 것은 토큰이 유효한가 의 여부일 뿐!
하지만 DB가 필요하지 않음과 동시에 세션에서 사용할 수 있는 기능들 (예를 들어, 강제 로그아웃) 을 사용할 수 없다.
서비스가 더 커지고, 유저 계정을 좀 더 잘 관리하고 싶으면 세션을 고려...
'경남_ABC_FE > Section_3' 카테고리의 다른 글
Github와 Git Flow (0) 2023.12.15 [React] 심화 (0) 2023.12.12 [React] 상태 관리 (1) 2023.12.04 [React] Custom Component (0) 2023.11.30 [사용자 친화 웹] UI/UX (1) 2023.11.28