Skip to content

인증 인가 전략 정하기

leegwae edited this page Nov 12, 2022 · 4 revisions

아스니티가 제공할 로그인 전략

  1. OAuth
  2. Local

어떻게 로그인 상태를 유지할까?

세션 방식을 쓸까 아니면 토큰 방식을 쓸까

세션 방식으로 유지하거나 토큰 방식으로 유지할 수 있다.

  1. 세션
  2. 토큰
`토큰`을 쓰도록 한다.
- 도입해보고 싶어서
- HTTP의 stateless를 유지하기 위해서
- 서버 부하를 줄이기 위해서

토큰 방식 - 리프레쉬 토큰을 사용할 것인가?

쓰기로 했다. 왜냐면
- 사용자 편의성을 위해서(매번 로그인하기 번거롭다)
- 서버 부하는 액세스 토큰만 쓸 때보다 좀 늘어난다.
- 리프레쉬 토큰을 어디에 저장하느냐에 따라 보안 문제가 있을 수 있다.

토큰을 어떻게 관리할까

토큰 포맷은 무엇을 사용할까?

토큰 포맷에는 bearer가 있다.

RFC 6750: OAuth 2.0 Bearer Token Usage [tools.ietf.org/html/rfc6750](http://tools.ietf.org/html/rfc6750)

Bearer Tokens are the predominant type of access token used with OAuth 2.0.

A Bearer Token is an opaque string, not intended to have any meaning to clients using it. Some servers will issue tokens that are a short string of hexadecimal characters, while others may use structured tokens such as [JSON Web Tokens](https://oauth.net/2/jwt/)

출처: https://oauth.net/2/bearer-tokens/

JWT가 뭘까

RFC 7519: JSON Web Token

[tools.ietf.org/html/rfc7519](https://tools.ietf.org/html/rfc7519)

JSON Web Token (JWT, [RFC 7519](https://tools.ietf.org/html/rfc7519)) is a way to encode claims in a JSON document that is then signed.

JWTs can be used as OAuth 2.0 [Bearer Tokens](https://oauth.net/2/bearer-tokens/) to encode all relevant parts of an access token into the access token itself instead of having to store them in a database.

JWT와 Bearer token은 무슨 관계일까?

Short answer

JWTs are a convenient way to encode and verify claims.

A Bearer token is just string, potentially arbitrary, that is used for authorization.

Context (story time)

A few years ago, before the JWT revolution, a <token> was just a string with no intrinsic meaning, e.g. 2pWS6RQmdZpE0TQ93X. That token was then looked-up in a database, which held the claims for that token. The downside of this approach is that DB access (or a cache) is required everytime the token is used.

JWTs encode and verify (via signing) their own claims. This allows folks to issue short-lived JWTs that are stateless (read: self-contained, don't depend on anybody else). They do not need to hit the DB. This reduces DB load and simplifies application architecture because only the service that issues the JWTs needs to worry about hitting the DB/persistence layer (the refresh_token you've probably come across).

출처: https://stackoverflow.com/questions/40375508/whats-the-difference-between-jwts-and-bearer-token

옛날에는 authorization을 하기 위해 Bearer 토큰을 사용했다. 서버는 토큰을 DB에 저장하여, 클라이언트가 보내는 토큰이 DB에 있는지 확인했다. 하지만 JWT는 서명을 할 수 있고, 생명주기를 가질 수 있다. 따라서 서버는 JWT에 생명주기를 짧게 주고 DB에 저장하지 않은 채 클라이언트에 보낸다.

결론

JWT를 사용한다.
JWT는 생명주기를 설정함과 동시에 자체에 정보들을 담을 수있다.
따라서 매번 DB에 접근하지 않고 JWT를 decoding 함으로 최소한의 사용자 정보를 확인할 수 있기 때문에, 다른 토큰보다 DB 접근 횟수가 적어 로직을 줄일 수 있다.

클라이언트는 토큰은 어디에 저장하는가?

클라이언트는 서버에게서 받은 토큰을 여러 방식으로 저장할 수 있다. 나열해보자.

  1. in-memory: 자바스크립트 변수에 저장, 휘발성
    1. 보안 좋다.
    2. 디버거에 찍으면 값 노출되지 않나요? 빌드 과정에서 소스코드 uglify하면 괜찮음.
  2. HTML5 모던 스토리지(로컬 스토리지): 비휘발성
    1. XSS 공격에 취약
  3. 브라우저 쿠키: 비휘발성
    1. CRSF 공격에 취약
    2. httpOnly 옵션 설정하여 쿠키 자바스크립트 접근 막기
    3. Secure 옵션 설정하여 쿠키 HTTPS로 암호화
    4. path, domain 옵션 설정하여 쿠키가 붙어갈 범위 지정

클라이언트는 액세스 토큰과 리프레쉬 토큰을 어디에 저장할까?

여러 가지 방법이 있다.

  1. 액세스 토큰은 로컬 변수에 저장, 리프레쉬 토큰은 쿠키에 저장(path, domain, httpOnly, Secure 옵션 설정).
    1. 액세스 토큰 만료시 리프레쉬 토큰을 보내 새로운 액세스 토큰과 리프레쉬 토큰 발급
    2. 액세스 토큰 만료시 리프레쉬 토큰을 보내 새로운 액세스 토큰만 발급
  2. 액세스 토큰과 리프레쉬 토큰을 로컬 스토리지에 저장

결론

액세스 토큰은 로컬 변수에 저장, 리프레쉬 토큰은 쿠키에 저장(path, httpOnly, domain, Secure 옵션 설정)하기로 한다.

왜 클라이언트가 토큰을 저장하나요? 왜 리프레쉬 토큰을 쿠키에 저장하나요?

액세스 토큰은 로컬 변수에 저장, 리프레쉬 토큰은 쿠키에 저장(path, httpOnly, domain, Secure 옵션 설정)

클라이언트가 위 방법처럼 액세스 토큰과 리프레쉬 토큰을 관리하는 경우 왜 리프레쉬 토큰을 쿠키에 저장하는가? = 왜 클라이언트가 토큰 정보를 유지할 수 있어야하는가?

액세스 토큰을 로컬 변수에 저장하면 휘발성이라 리로드할 때 날아가서 클라이언트는 서버에 자신을 인증할 수 있는 방법이 없다. 그래서
1. 클라이언트는 액세스 토큰이 날라가면 자신이 가지고 있는 리프레쉬 토큰을 서버에게 보내 자신이 신용을 인증한다.
2. 서버는 리프레쉬 토큰의 유효성을 검증하여 새로운 액세스 토큰을 발급받을 수 있다.

서버는 리프레쉬 토큰을 어디에 저장하는가?

여러가지 방법이 있다. 나열해보자.

  1. in-memory: 자바스크립트 변수, 휘발성
  2. 파일 시스템: 비휘발성
  3. DB
    1. redis
    2. mongoDB
    3. MySQL: 굳이?

결론

mongoDB로 결정하였다.
  - mongoDB를 프로젝트의 메인 DB로 사용하기 때문에 user collection에서 attribute를 추가만 하면될 것 같다.
  - 지금 수준의 서버에서 token 저장만을 위한 별도 redis 구축은 over engineering으로 보인다.
Clone this wiki locally