BEB 07 7-2,3

Donghun Seol·2022년 10월 25일
0

코드스테이츠 BEB 07

목록 보기
27/39

HTTPS

https 통신의 절차

  1. 클라이언트에서 서버에 최초의 요청을 랜덤문자1, 지원하는 암호화 방식을 담아 보낸다.
  2. 서버는 서버에서 생성한 랜덤문자 2와 서버에서 결정한 암호화방식, 인증서를 담아 클라이언트에 보낸다.
    (서버의 인증서는 CA의 비밀키로 암호화 되어 있다.)
  3. 클라이언트은 서버에서 받은 인증서를 브라우저에 내장된 CA의 공개키로 복호화 시도하고, 복호화 성공시 해당 인증서는 유효한 것이므로 HTTPS 연결이 성공한다. 클라이언트는 복호화 과정에서 인증서 내에 포함된 서버의 공개키를 획득한다.
  4. 클라이언트는 랜덤문자1,2를 함께 가공한 pre-master secret을 서버의 공개키로 암호화화여 서버로 전송한다.
  5. 서버와 클라이언트 각자 일련의 과정을 거쳐 pre-master secret을 master secret으로 변환시킨다. master secret은 session key를 생성하고 이를 통신시 대칭키로 활용한다. 키 분배 문제가 해결된다.
  6. 데이터의 전송이 끝나면 SSL통신이 끝났음을 클라이언트와 서버가 알게되고, 세션키를 폐기한다.

Hashing

특정값을 해시함수에 넣어 그 결과를 사용하는 것이다.
DB에 사용자의 비밀번호를 그대로 저장하는 것은 불법이며, 해시값만을 저장해야 한다.

해시함수는 비가역적 일방 함수로서 특정 값을 쪼개서 일정한 길이의 해시값으로 만들어 준다. 메시지의 무결성을 검증하기 위해 활용된다.

쿠키는 http 요청의 stateless를 극복하기위해 서버에서 전송받은 개인정보를 브라우저에서 저장하고 있는 것이다.

쿠키는 서버에서 만들고, 브라우저에서 보관한다.

키,밸류 쌍으로 이루어지며 유효기간이 있다.
브라우저에서 서버로 요청을 보낼때 조건이 맞다면 자동으로 보내진다.

쿠키 전송의 조건
1. Domain : 도메인이 설정된 쿠키의 경우 쿠키의 도메인과 서버의 도메인이 일치해야만 쿠키를 해당 서버로 전송한다. 여기서 도메인은 www등을 제외한 google.com, naver.com 을 의미한다.
2. Path : 도메인 이후에 적용되는 옵션. /는 해당 도메인의 모든 URI에 대해 쿠키를 전송하고, /userlocalhost.com/users/* 등의 URI에 한해서 쿠키를 전송한다.
3. MaxAge : Expire보다 우선하여 적용된다. 해당 시간이 지나면 쿠키를 제거한다.
4. Expire : 만료기한이다. 기한 내 브라우저가 꺼지더라도 쿠키는 유지된다.
5. Secure : HTTPS 프로토콜 사용시에만 쿠키를 전송된다.
6. HttpOnly : 브라우저의 자바스크립트에서 쿠키에 접근 불가능해진다. XSS 공격 방지를 위해 적용한다. 리액트 등의 클라이언트앱에서 쿠키에 접근 불가하다.
7. SameSite : none, lax, strict의 옵션이 있다.

  • sameSite의 판별기준 : uri중 도메인을 기준으로 판별하는데, 도메인의 public suffix를 제외한 값이 동일하면 sameSite에 해당한다. 아래의 경우 모두 sameSite이다. public suffix를 제외한 dokydoky의 값이 모두 일치하기 때문이다.

    https://www.dokydoky.com
    http://dokydoky.net
    https://ww2.dokydoky.co.kr

  • 참고 : SOP, same origin policy 에서는
    scheme, host, port 모두 동일해야 same origin으로 판별한다 (Cors에서 사용되는 것)

  • none : 모든 사이트에 쿠키를 전송한다. 이 옵션을 적용하려면 secure가 적용되어야 한다. CSRF 공격에 취약해진다. 때문에 추가적인 CSRF 보호 기법이 적용되어야 한다.

  • strict : first-party context에서만 쿠키가 전송된다. first-party 쿠키란 third-party와 대비되는 뜻으로 쿠키를 발행한 해당 도메인에서만 사용되는 쿠키를 말한다.

  • lax : strict인 경우와a태그의 링크를 클릭하거나, 자바스크립트 최상위 엘리먼트(document)에서 location이 호출될때 쿠키가 third-party로 전송된다. GET 요청시에만 쿠키가 전송된다. 따라서 서버프로그래밍시 정보를 바꾸는 요청 메서드를 GET으로 받으면 안된다.

Session

세션은 서버에서 보관하고 있는 정보이다. 유저 정보를 보관한다. 세션을 식별하기위한 세션 ID는 쿠키를 통해 전달된다.

유저가 서버에 로그인하면 서버는 세션 DB에 유저 정보를 저장해놓고, 쿠키로 세션 ID를 클라인트로 보낸다.

유저는 요청을 보낼때마다 (자동으로) 쿠키에 있는 세션 ID를 서버로 보내고, 서버는 요청에 들어있는 세션 ID를 세션 DB와 대조하여 해당 요청이 어떤 유저로부터 들어왔는지 인식한다.

따라서 세션이 유지되는 한 해당 유저는 로그인된 상태를 유지하며 웹사이트를 이용할 수 있다.

세션의 장점 (기능이 많다)

세션을 통해서 서버사이드에서 로그인을 통제할 수 있다.

  1. 서버는 세션 DB를 통해 로그인된 기기가 몇개이고, 어디에서 로그인되어 있는지 알 수 있다.

  1. 강제로 로그인을 종료시킬 수 있다.

사진출처 - 노마드코더

세션의 단점 (비싸다)

  1. 세션 DB를 구성하고 유지보수해야한다.
  2. 요청마다 세션 DB와 쿠키에 담긴 세션ID를 대조해야 하므로 서버의 부담이 가중된다.

이러한 단점을 극복하려면, 통제가능성을 포기하는 대신 서버의 부담을 완화하는 JWT토큰을 활용할 수 도 있다.

CSRF

출처:인조이버그 유투브

  1. 공격자가 공격대상 사이트의 요청 및 파라미터를 파악하고 있음.
  2. 피해자는 공격대상 사이트에 쿠키를 활용해서 로그인되어 있는 상태.
  3. 공격자는 피해자를 사회공학적으로 피싱하여 제3의 사이트로 접속하도록 유인
  4. 제 3의 사이트는 쿠키로 피해자의 로그인정보를 전송받고, 특정한 스크립트를 활용하여 공격대상 사이트에 정당한 비밀번호 변경 요청을 보냄
  5. 공격자는 변경한 비밀번호로 대상 사이트에 피해자의 신분으로 로그인 가능.

CSRF 공격 성공의 요건

  • 세션 쿠키를 사용한 로그인, 해당 세션이 살아있어야 함
  • 예측할 수 있는 요청 및 파라미터를 가지고 있어야 됨.

CSRF 방지 방법

  • CSRF 토큰 사용
  • Same-site 쿠키 사용하기
  • 중요한 정보변경 요청을 GET 요청으로 받지 않기

Token

토큰의 작동방식

  1. 유저가 최초 로그인 요청시 서버는 세션DB에 특정 내용을 생성하지않고, 서명된 토큰을 클라이언트에 보낸다.
  2. 토큰은 헤더, 유저정보, 데이터무결성 검증을 위한 비밀키로 서명한 해시값을 포함한다.
  3. 이후 유저가 서버에 요할때마다시 토큰이 서버로 전송된다.
  4. 서버는 서버에만 저장된 비밀키로 유저정보를 해싱하고, 토큰에 첨부된 해시값을 비교해 일치하면 유효한 토큰으로 인식하여 유저를 식별하게 된다.

일반적으로 토큰은 AccessToken과 RefreshToken 두 가지를 발행하는데, AccessToken이 탈취되더라도 Expiration Time이 짧으므로 피해를 최소화 할 수있다. 만약 RefreshToken이 만료되면 다시 로그인을 해야한다.

토큰의 장점 (싸다)

  1. 토큰은 세션방식에 비해 서버의 stateless를 더욱 보장하여 서버의 수평적 확장을 쉽게 만든다.
  2. 토큰을 생성하는 인증서버와 서비스 서버를 분리가능하게 한다.
  3. 토큰의 payload에 인증관련 정보를 삽입할 수 있으므로 권한부여가 용이하다.
  4. 구현이 매우 간단하다.

토큰의 단점 (기능이 제한적)

  1. JWT의 경우 암호화되지 않았으므로 payload 안에 있는 내용을 누구나 확인할 수 있다.
  2. 토큰의 길이 때문에 네트웍 부하가 증가한다.
  3. 서버에서 로그인 정보에 대한 제어가 불가능하다.

관련 스프린트에서는 AcessToken은 response body에 실어 보내서 클라이언트 js에서 접근가능하게 했다. 전송받은 AcessToken은 state에 저장하여 요청마다 활용하는 방식이었다.

RefreshToken은 HttpOnly가 적용된 쿠키로 전송하여 클라이언트에서 접근 불가하게 전송하였다.

OAuth

구글 로그인 구현하는데 반나절이나 사용함...
리액트로 작성한 클라이언트에서 Oauth 로그인으로 리다이렉션시 기존의 상태가 날아가서 github로그인과 google 로그인을 구분하는 방법을 많이 고민했는데, localStorage를 활용해서 구현했다.다시 생각해보니 redirection url을 login provider별로 다르게 지정해주면 간단한 문제였네...

클래스 컴포넌트에서 상태나 컨텍스트에 접근 못하는 경우는 클래스 메서드를 binding해주지 않아서 생기는 사례가 많았다.
componentDidMount() 메서드에 대해서 이해했다.

구글 api는 깃헙처럼 친절하지가 않아서 여러 블로그를 참고하면서 구현해 나갔다. 왠지 모르게 redirection_uri가 잘 반영이 안되어 GCP에서 앱을 지웠다가 다시 등록하니 잘 작동되었다.

구글의 공식문서는 제공되는 라이브러리를 활용하는 것을 추천했지만, 스프린트의 의도대로 저수준에서 http콜을 직접하면서 구현했다.

이제 쿼리스트링, 파라미터, 바디로 클라이언트 서버간 통신을 하는 방법들이 많이 익숙해졌다. 쿠키와 세션도 개념적으로는 이해를 하고 있으니 redis와 같은 세션 db를 활용하는 코드를 작성해볼 필요가 있을것 같다.
덕분에 redirect_url, code, accessToken, api endpoint, 요청 정보 스코프 지정 등에 대해서 고민하면서 기능을 구현하니 많은 공부가 되었다고 생각한다.

profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글