개발/파이썬

[TIL] JWT 토큰 쿠키에 저장하기 (Flask)

seonu._.jang 2019. 5. 5. 15:47
반응형
  • JWT 토큰은 JS에서 접근할 수 있는 Localstorage보다 JS에서 접근할 수 없는 httponly cookie에 저장하는 것이 XSS 공격에 안전하다. ( JS를 페이지에서 쓸 수 없게 escaping을 잘 해두면 LocalStorage에 저장하더라도 XSS 공격을 막을 수 있다. )
  • 단, CSRF 공격에 취약하기 때문에, CSRF 토큰을 만들어서 double checking을 통해 보안에 신경 쓸 필요가 있다.
  • httponly cookie는 프론트가 아닌 서버에서 Response해줄 때 붙여준다.
  • Flask 앱에 아래와 같은 옵션을 지정해주면 flask-jwt-extended라이브러리를 통해 cookie에 jwt를 지정할 수 있다.
JWT_COOKIE_SECURE = False # https를 통해서만 cookie가 갈 수 있는지 (production 에선 True)
JWT_TOKEN_LOCATION = ['cookies']
JWT_ACCESS_COOKIE_PATH = '/' # access cookie를 보관할 url (Frontend 기준)
JWT_REFRESH_COOKIE_PATH = '/' # refresh cookie를 보관할 url (Frontend 기준)
# CSRF 토큰 역시 생성해서 쿠키에 저장할지 
# (이 경우엔 프론트에서 접근해야하기 때문에 httponly가 아님)
JWT_COOKIE_CSRF_PROTECT = True 

아래와 같이 flask-jwt-extended라이브러리의 set_access_cookiesset_refresh_cookies를 사용하면 쿠키를 브라우저에 저장할 수 있다.

@app.route('/token/auth', methods=['POST'])
def login():
    username = request.json.get('username', None)
    password = request.json.get('password', None)
    if username != 'test' or password != 'test':
        return jsonify({'login': False}), 401

    # Create the tokens we will be sending back to the user
    access_token = create_access_token(identity=username)
    refresh_token = create_refresh_token(identity=username)

    # Set the JWTs and the CSRF double submit protection cookies
    # in this response
    resp = jsonify({'login': True})
    set_access_cookies(resp, access_token)
    set_refresh_cookies(resp, refresh_token)
    return resp, 200
  • 그런데 아무리 해도 브라우저에 cookie가 저장되지 않았다.
  • 해결책:
    • 브라우저가 localhost로 되어있으면 cookie를 저장하지 않는거 같다. http://127.0.0.1로 접속하자.
    • axioswithCredentials: true라는 문구를 추가하자.
import axios from "axios";

export default axios.create({
  baseURL: process.env.BASEURL,
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json"
  },
  withCredentials: true
});
  • Flask-Cors에서 supports_credentials=True를 추가하자.
CORS(app, origins=ALLOW_ORIGINS, supports_credentials=True)
  • 이렇게 하니 정상적으로 잘 저장됐다.

  • 이제 localstorage에서 token을 빼서 Authorization 헤더를 보낼 필요가 없어졌다.

  • 단 csrf 보안을 설정해뒀으므로, 프론트에서 csrf-token을 빼서 보내주어야 백엔드에서 더블 체킹이 된다.

  • 쿠키를 쓰려면 도메인이 같아야한다. (*.alphaquant.co.kr에서 *.abcdef.co.kr의 쿠키를 지정할 수 없다는 말)
반응형