ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Express Cookie 옵션과 cookie-parser 옵션으로 쿠키 signed하기
    Express 2024. 4. 27. 17:32
    728x90

    Reference

    https://expressjs.com/en/api.html#res.cookie

     

    Express 4.x - API Reference

    Express 4.x API express() Creates an Express application. The express() function is a top-level function exported by the express module. var express = require('express') var app = express() Methods express.json([options]) This middleware is available in Ex

    expressjs.com

     

    PropertyTypeDescription

    domain String Domain name for the cookie. Defaults to the domain name of the app.
    encode Function A synchronous function used for cookie value encoding. Defaults to encodeURIComponent.
    expires Date Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie.
    httpOnly Boolean Flags the cookie to be accessible only by the web server.
    maxAge Number Convenient option for setting the expiry time relative to the current time in milliseconds.
    path String Path for the cookie. Defaults to “/”.
    partitioned Boolean Indicates that the cookie should be stored using partitioned storage. See Cookies Having Independent Partitioned State (CHIPS) for more details.
    priority String Value of the “Priority” Set-Cookie attribute.
    secure Boolean Marks the cookie to be used with HTTPS only.
    signed Boolean Indicates if the cookie should be signed.
    sameSite Boolean or String Value of the “SameSite” Set-Cookie attribute. More information at https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00#section-4.1.1.

     

    Response cookie를 사용시에 해당 옵션들을 잘 활용해서 보안을 설정 해주어야 한다. 쿠키는 보안에 취약하기 때문이다.

     

    현재 만들고 있는 프로젝트에서는 AccessToken과 RefreshToken을 cookie로 response 해주고 있다.

    여기서 RefreshToken에 대해서 생각을 해보았는데 해당 토큰은 유효기간이 길기 때문에 탈취 되었을때 위험성을 초래한다.

    그전에 위의 response cookie 설정들을해서 httpOnly라던지 domain path 등등 옵션들을 이용하여 보안을 신경 쓰더라도 아쉽다.

    그러다 CookieParser쪽에 secret이란 옵션이 있었다.

     

    declare function cookieParser(secret?: string | string[], options?: cookieParser.CookieParseOptions): express.RequestHandler;

     

    찾아보니 내가 의도한대로 쿠키를 SecretKey를 이용하여 암호화해서 전달하고 전달 받는 기능이다.
    내가 찾던 찰떡 같은 기능이다.

     

    해당 기능을 사용시에 Cookie-parser가 동작하는 refreshToken에만 해당 옵션을 주어야했다. accessToken에도 주었다가 엉뚱한 cookie-paser 옵션들을 까보는 멍청한 삽질을 하게 되었다.

     

    그리고 해당 기능을 사용하게 되면 exrpess에서 req.cookie에 쿠키가 존재하는게 아니라 req.signedCookies에 쿠키가 존재한다 주의할것

     

    let cookieOptions: CookieOptions = {
        maxAge: Number(this.configService.get<number>(ENV_COOKIE_MAX_AGE)),
        secure: true,
    };
    
    if (type === 'refreshToken') {
        cookieOptions = {
            ...cookieOptions,
            httpOnly: true,
            signed: true, // 사용시 해당 옵션을 꼭 넣어주어야 한다.
        };
    }
    cookie를 response 해주는 곳에서 cookie opton중에 signed:true를 꼭 주어야 한다.

     

    // cookie parser
    app.use(cookieParser(process.env[ENV_SECRET_COOKIE_KEY]));

     

    그리고 cookieParser에 쿠키 Secret key를 넣어주면 된다.

     

    // refreshToken.strategy.ts
    validate(req: Request, payload: TokenPayload) {
        if (!req.signedCookies.Authentication)
            throw UnAuthOrizedException(ERROR_TOKEN_EXPIRED);
    
        const refreshToken = req.signedCookies.Authentication;
        return { ...payload, refreshToken };
    }
    
    private static extractJWT(req: Request): string | null {
        if (req.signedCookies && 'Authentication' in req.signedCookies) {
            return req.signedCookies.Authentication;
        }
        return null;
    }
    나같은 경우에는 RefreshToken을 검증하는 곳에 req.signedCookies 라고 수정 해주었다.

     

     

    보너스

    cookies: {
       Authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MTBiNzIwMi02NjBhLTQ0MjMtYTZjMy02Mzc3ODU3MjQxY2MiLCJ1c2VybmFtZSI6IuuEpOyKpO2KuOqwseydtCIsImlhdCI6MTcxNDIwNTkyMiwiZXhwIjoxNzE0MjA1OTgyfQ.t12kJGdZVDJT6xLDgTOlJc1nQPSWD6T7Il8njzRFM2o'
    },
    signedCookies: [Object: null prototype] {
       Authentication: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MTBiNzIwMi02NjBhLTQ0MjMtYTZjMy02Mzc3ODU3MjQxY2MiLCJ1c2VybmFtZSI6IuuEpOyKpO2KuOqwseydtCIsImlhdCI6MTcxNDIwNTkyMiwiZXhwIjoxNzE0ODEwNzIyfQ.H5md5gOMJ7TQIj07VcdZ4_6ny5D8aHSJ-8wBfsveyEQ'
    },

     

    이런식으로 req객체에 담겨져 오는데 자세히 보면 response cookie의 옵션을 signed: true를 주었던 Authentication만 signedCookies에 담겨져 오는걸 알 수 있다. 즉 signed: true 주지 않는 쿠키들은 기존대로 cookies에 담겨져 온다.
    728x90
Designed by Tistory.