특정값을 해시함수에 넣어 그 결과를 사용하는 것이다.
DB에 사용자의 비밀번호를 그대로 저장하는 것은 불법이며, 해시값만을 저장해야 한다.
해시함수는 비가역적 일방 함수로서 특정 값을 쪼개서 일정한 길이의 해시값으로 만들어 준다. 메시지의 무결성을 검증하기 위해 활용된다.
쿠키는 http 요청의 stateless를 극복하기위해 서버에서 전송받은 개인정보를 브라우저에서 저장하고 있는 것이다.
쿠키는 서버에서 만들고, 브라우저에서 보관한다.
키,밸류 쌍으로 이루어지며 유효기간이 있다.
브라우저에서 서버로 요청을 보낼때 조건이 맞다면 자동으로 보내진다.
쿠키 전송의 조건
1. Domain : 도메인이 설정된 쿠키의 경우 쿠키의 도메인과 서버의 도메인이 일치해야만 쿠키를 해당 서버로 전송한다. 여기서 도메인은 www등을 제외한 google.com
, naver.com
을 의미한다.
2. Path : 도메인 이후에 적용되는 옵션. /
는 해당 도메인의 모든 URI에 대해 쿠키를 전송하고, /user
는 localhost.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으로 받으면 안된다.
세션은 서버에서 보관하고 있는 정보이다. 유저 정보를 보관한다. 세션을 식별하기위한 세션 ID는 쿠키를 통해 전달된다.
유저가 서버에 로그인하면 서버는 세션 DB에 유저 정보를 저장해놓고, 쿠키로 세션 ID를 클라인트로 보낸다.
유저는 요청을 보낼때마다 (자동으로) 쿠키에 있는 세션 ID를 서버로 보내고, 서버는 요청에 들어있는 세션 ID를 세션 DB와 대조하여 해당 요청이 어떤 유저로부터 들어왔는지 인식한다.
따라서 세션이 유지되는 한 해당 유저는 로그인된 상태를 유지하며 웹사이트를 이용할 수 있다.
세션을 통해서 서버사이드에서 로그인을 통제할 수 있다.
사진출처 - 노마드코더
이러한 단점을 극복하려면, 통제가능성을 포기하는 대신 서버의 부담을 완화하는 JWT토큰을 활용할 수 도 있다.
일반적으로 토큰은 AccessToken과 RefreshToken 두 가지를 발행하는데, AccessToken이 탈취되더라도 Expiration Time이 짧으므로 피해를 최소화 할 수있다. 만약 RefreshToken이 만료되면 다시 로그인을 해야한다.
관련 스프린트에서는 AcessToken은 response body에 실어 보내서 클라이언트 js에서 접근가능하게 했다. 전송받은 AcessToken은 state에 저장하여 요청마다 활용하는 방식이었다.
RefreshToken은 HttpOnly가 적용된 쿠키로 전송하여 클라이언트에서 접근 불가하게 전송하였다.
구글 로그인 구현하는데 반나절이나 사용함...
리액트로 작성한 클라이언트에서 Oauth 로그인으로 리다이렉션시 기존의 상태가 날아가서 github로그인과 google 로그인을 구분하는 방법을 많이 고민했는데, localStorage를 활용해서 구현했다.다시 생각해보니 redirection url을 login provider별로 다르게 지정해주면 간단한 문제였네...
클래스 컴포넌트에서 상태나 컨텍스트에 접근 못하는 경우는 클래스 메서드를 binding해주지 않아서 생기는 사례가 많았다.
componentDidMount() 메서드에 대해서 이해했다.
구글 api는 깃헙처럼 친절하지가 않아서 여러 블로그를 참고하면서 구현해 나갔다. 왠지 모르게 redirection_uri가 잘 반영이 안되어 GCP에서 앱을 지웠다가 다시 등록하니 잘 작동되었다.
구글의 공식문서는 제공되는 라이브러리를 활용하는 것을 추천했지만, 스프린트의 의도대로 저수준에서 http콜을 직접하면서 구현했다.
이제 쿼리스트링, 파라미터, 바디로 클라이언트 서버간 통신을 하는 방법들이 많이 익숙해졌다. 쿠키와 세션도 개념적으로는 이해를 하고 있으니 redis와 같은 세션 db를 활용하는 코드를 작성해볼 필요가 있을것 같다.
덕분에 redirect_url, code, accessToken, api endpoint, 요청 정보 스코프 지정 등에 대해서 고민하면서 기능을 구현하니 많은 공부가 되었다고 생각한다.