이번 글을 통해서 우리는 로그인, 로그아웃, 회원가입 같은 기능을 구현하게 된다.
더불어 인증에 관하여 알아보자.
개인적으로 나는 이부분이 좀 신기하고 어려웠기 때문에 확실하게 잡고 갈것이다.
인터넷에서 데이터를 주고받는 통신 프로토콜이다.
기존에 있는 http와 다르게 정보를 한번 암호화 하기 떄문에 키가 없다면 정보를 볼수가 없다.
인증서
- 데이터를 제공한 서버거 진짜 데이터를 전송한 서버인지 확인하는 데에 사용된다.
- 인증서의 내용에 서버의 도메인 관련 내용도 담겨 있다.
- 요청을 받게 된다면 서버는 인증서와 함께 응답을 전송하고 응답을 받은 클라이언트는 인증서에 작성된 도메인과 기존에 작성된 도메인을 확인하게 된다.
- 같다면 서버를 인식하지만 만약 다르다면 해커에 의해 해킹이 된것이기 떄문에 서버를 믿지 않게 된다.
CA
- 인증서를 발급하는 공인된 기관
- 자격이 항상 유지되는 것이 아니라 시간이 지남에 따라서 자격이 박탈 당할 수도 있다.
비대칭 키 암호화
- 전혀다른키 한쌍으로 암호화 및 복호화를 진행한다.
- A키로 암호화를 한다면 복호화 하는데에는 한 쌍인 B키로 복호화를 가능
- 그러기 떄문에 키 하나는 숨겨두고 하나는 공개를 하게 된다.
- 키 생성은 매우 복잡한 알고리즘이기 떄문에 모든곳에서 사용을 하게 되면 속도가 많이 저하된다.
- 그러기 떄문에 간의 통신의 초창기 에서만 사용하게 된다.
통신이 이루어 지는 순서
Hand Shake
비밀 키 생성
상호 키 검증
이후에 이러한 키를 바탕으로 데이터를 전송할떄 암호화, 복호화시킨다.
앞서 말했듯이 http를 보안화한 프로토콜이다.
클라이언트는 데이터 제공자가 제공해준 데이터를 사용할수 밖에 없다.
그러기 떄문에 서버에서 받아오는 과정에서 가로채는 중간자 공격에 매우 취약하게 된다.
그러기 떄문에 암호화라는 과정이 필요하다.
HTTPS 프로토콜의 특징
- 암호화된 데이터를 주고받기 떄문에 중간에 탈취가 일어나도 그 내용을 알아볼 수 없다.
- 서로 인증서를 비교해 가면서 CA의 정보를 확인한다.
ssl
tls
부가적인 인증 과정이 없이 요청을 하여 데이터를 받아오는 과정은 매우 간단하다.
하지만 보안을 생각해서 패스워드를 입력해야만 값을 가져온다고 해보자
이 방법은 보안의 역할을 할 수가 있다.
하지만 만약 우리가 패스워드가 유출된다면 해킹의 위협에 전면적으로 노출되게 된다.
그러기 떄문에 우리는 암호화를 사용해야 한다.
앞서 적은 예시를 암호화 하는 과정을 살펴보자
1234라는 비밀번호를 입력하여 서버에 데이터를 요청하고 서버에서는 1234라는 비밀번호를 확인한뒤 DB에 있는 비밀번호와 대조를 해본다.
그럼 서버측에서 값을 DB에 저장을 할떄 +2만큼 더한값을 저장한다고 생각을 해보자.
그럼 클라이언트가 1234라는 패스워드를 요청을 하면 서버에서는 3456으로 값을 DB에 저장을하고
3456에 맞는 값을 전해준다.
이떄 만약 해킹이 되어서 3456이라는 값이 노출된다고 해도 괜찮다.
이런 원리로 암호화를 적용시킬수가 있다.
1. 모든 값에 대해 해시값을 계산하는데에 오래걸리지 않아야 한다.
2. 최대한 해시 값을 피애햐 하며 모든 값을 고유한 해시값을 가진다
3. 아주 작은 단위의 변경이라도 완전히 다른 해시 값을 가져야 한다.
요즘에는 SHA256이라는 해시 알고리즘을 많이 사용한다.
암호화 해야하는 값에 어떤 별도의 값을 추가하여 결과를 변형 시키는것
앞서 말한것처럼 암호화를 하면 안전해 보이지만 해커가 만약 해쉬된 값을 디코딩하여서 패스워드를 알아올수도 있다.
그러기 떄문에 기존의 패스워드 값에 약속된 별도의 문자열(Salt)를 추가하여 해쉬를 진행한다면
좀더 안전한 암호화를 이루어 낼수가 있다.
기존 : 패스워드 => 해시값
변형 : 패스워드 + Salt => 해시값
1. 유저와 패스워드 별로 유일한 값을 가져야 한다.
2. 계정 생성, 계정 변경 할떄마다 새로운 임의의 Salt를 사용해야한다.
3. Salt는 절대 재사용 되어서는 안된다.
4. Salt는 DB의 유저 테이블에 같이 저장되어야 한다.
인증에 필요한 기본 지식이다.
HTTP요청은 stateless하다.
그럼 우리가 장바구니를 생각해보자
쇼핑을 하면서 장바구니에 마음에 드는 물건을 담고 계속 인터넷 쇼핑을 한다.
하지만 http요청은 statelss한데 어떻게 이전에 있는 상태를 계속 유지 할까??
하지만 장바구니가 유지되고 이렇게 유지되는 이유는 모두 Cookie떄문이다.
Cookie : 어떤 사이트를 들어갔을떄 서버가 일반적으로 클라이언트에 전달하는 작은 데이터
서버가 웹에 정보를 저장하고 불러올 수 있는 수단이며 해당 도메인에 쿠키가 존재하면 클라이언트 상에서 요청을 할때마다 자동으로 쿠키를 포함해서 전송한다.
하지만 브라우저에 존재하기 떄문에 보안상으로 매우 위험하다.
1. Domain
2. Path
3. MaxAge or Expires
4. HttpOnly
5. Secure
6. SameSite
pc방에서 로그인을 한뒤 로그아웃을 하지 않고 나왔다고 생각을 해보자
쿠키는 웹에 저장이 되기 떄문에 로그아웃을 하지 않으면 쿠키가 계속 웹에 저장이 되어 있을 것이고 그러면 타 사용자가 웹에 있는 쿠키를 활용하여 나의 정보를 취득할수 있다.
이떄 사용하는 Option은
MaxAge or Expires
를 사용하여 일정 시간후 쿠키를 삭제시킨다.
쿠키는 js로 접근을 할수가 있다.
그러기 떄문에 js파일을 삽입해서 실행한 결과값을 확인할수 있는 XSS공격에 매우 취약하다.
이떄 사용하는 Option은
HttpOnly
를 사용하여 보안을 강화한다.
만약 csrf공격의 상황이 있다고 생각을 해보자.
내가 은행에 로그인하고 은행사이트에서 나에게 인증정보를 주게 되었을떄 공격자가 나에게 악의적인 링크를 보내 내가 해당 링크로 들어가게 되었다고 하자.
그렇게 공격자는 나의 인증정보를 가지고 은행에서 돈을 인출하게 된다.
이떄 사용하는 Option은
SameSite
이다. 이전에 내가 로그인했던 사이트 정보와 일치하지 않으면 쿠키를 허용하지 않는 옵션
쿠키는 쉽게 말하면 서버에서 클라이언트에 저장하는 데이터이다.
항상 쿠키를 담아서 보내는 것은 아니고 설정한 Option에 맞춰서 쿠기를 전송한다.
요청해야 할 url이 http://www.localhost.com:3000/users/login
이라면
여기에서 Domain은 localhost.com
이 되고
해당 Domain이 있는 요청만 쿠키를 담아서 전송한다.
세부 경로는 서버가 라우팅할 떄 사용하는 경로이다.
요청해야 할 url이 http://www.localhost.com:3000/users/login
이라면
여기에서 Path는 /users/login
이 되고
해당 Path가 있는 요청만 쿠키를 담아서 전송한다.
쿠키의 유효기간을 설정한다.
MaxAge
는 앞으로 몇 초 동안 쿠키가 유효한지 설정을 하고
Expires
는 언제까지 유효한지 날짜를 지정한다.
하지만 두 옵션이 모두 지정되지 안흔ㄴ다면 브라우저의 탭을 닫으면 쿠키가 제거될수 있다.
쿠키를 전송해야 할떄 사용하는 프로토콜에 따른 쿠키 전송 여부를 결정한다.
만약 true라면 HTTPS
프로토콜을 이용하여 통신하는 경우에는 쿠키를 전송한다.
js에서 쿠키에 접근 여부를 결정한다.
true라면 JS에서 쿠키게 접근이 불가능하다.
기본적으로 false로 지정되어 있으며 false인 경우에 JS를 통해 쿠키에 접근할수 있기 떄문에 'XSS공격'에 취약하다.
Cross-Origin요청을 받은 경우 요청에서 사용한 메소드와 해당 옵션의 조합으로 서버의 쿠키 전송 여부를 결정한다.
Lax
: Cross-Origin요청이면 GET메소드에 대해서만 쿠키를 전송
Strict
: same-site인 경우에만 쿠키를 전송(Cross-Origin = x)
None
: 모든 경우에 대해서 쿠키를 전송
이러한 옵션들을 지정한 뒤에 서버에서 클라이언트로 쿠키를 처음 전송하게 될떄 헤더에 Set-Cookie
라는 프로퍼티에 쿠키를 담아 쿠키를 저놋ㅇ한다.
이후 클라이언트 에서 쿠키를 전송해야 한다면 클라이언트는 헤더에Cookie
라는 프로퍼티에 쿠키를 담아 서버에 전송한다.
쿠키는 웹에서 사용하는 작은 DB라고 생각해도 좋다.
유도리있게 사용하면 Stateless한 인터넷에서 Stateful하게 이용을 할수 있지만
앞서 말했듯이 설정을 잘못하면 오랜시간 유지 가능하고 공격에 취약하기 떄문에 정확히 알고 사용을 해야한다.
여러가지 해킹의 공격기법중 하나이다.
주소가 다른 사이트에서 요청을 조작 하는것
요청만을 조작하는 해킹이기 떄문에 해커가 직접 응답에 접근할수는 없다.
a가 사이트에 로그인을 한뒤 get요청을 이용하여 은행에 100만원을 보냈다.
그러면 해커는 get요청 쿼리에 있는 계좌번호를 자신의 계좌번호르 바꾼다.
그러기 위해서 a가 특정 링크를 클릭하게 만들고 요청을 바꾸는 것이다.
쿠키 같은 경우에는 클라이언트에 저장을 한다.
하지만 Session은 서버에 저장을 하게 되고 쿠키 안에 세션id가 암호화된 데이터만을 제공한다.
즉 쿠키 안에 있는 Session의 id값을 이용해 서버에 있는 Session의 데이터를 가져올수 있다.
a라는 유저가 물품을 장바구니에 담으려고 한다.
그러면 서버에 요청을 하게 될것이고 서버는 해당 물품을 DB에 저장을 하게 된다.
- 처음에는 인증정보가 없기 떄문에 password를 통해서 인증을 한다.
그후 DB에서 Session_id를 반환하여 주고 그것을 쿠키안에 담아서 반환을해주게 된다.
- 쿠키는 경우에 따라서 JS로 변환이 가능하기 떄문에 Session은 반드시 암호화를 해주어야 한다.
이후 다시 a라는 유저가 또다른 물품을 장바구니에 담고자 한다면 이번에는 기존에 있는 Session_id를 이용한다.
- 처음에 쿠키를 받을떄에 Session_id를 받았기 떄문에 이 값을 가지고 같은 사용자임을 증명한다.
이렇게 데이터 인증이 이루어 지게 된다.
- 쿠키와 세션의 차이점을 간략하게 정리한 사진이다.
어떻게 보면 쿠키와 세션은 비슷하다.
사실 쿠키만으로도 인증을 할수는 있다.
하지만 Session을 사용함으로써 추가적으로 얻을수 있는 이점이 있다.
만약 동일한 Session_id를 가지고 있는 a,b가 있다고 해보자
a는 미국, b는 한국에 살고 있으면 서로 다른 사용자일 것이다.
하지만 Session_id가 동일하기 떄문에 두 사용자는 Session만을 이용한 증명에서는 반드시 통과하게 될것이다.
하지만 쿠키값이 다르기 떄문에 같은 사용자라고 인식을 하지 않을수 있다.
** 이처럼 두가지를 통해서 인증하는 방법은 좀더 안정적인 통신을 보장한다. **
우리는 사용자의 입장에서 생각해야 하기 떄문에 일단 속도가 빨라야 한다.
앞서 설명했듯이 Session은 서버에서 저장을 하게 된다.
만약 사용자가 많아지게 된다면 Session은 서버 메모리 영역에서 한 일부분을 차지하게 될것이다.
또한 Session은 한 서버에 하나의 Session만을 다룰수 있다.
또한 XSS위험에 노출될수가 있다.