이슈
현재 클라이언트는 서버로부터 access 토큰 및 refresh 토큰을 발급 받고, 시간이 지나 토큰이 만료되면 서버에 저장된 토큰 데이터를 이용해 재발급 받는 방식이다. 개발을 하던 와중 창준이 계정의 토큰이 만료된 후 다시 접속하면 돈이나 경험치, 장비 등의 개수 등이 서버에 있는 값과 다르게 전달되고, 결제 등을 하면 창준이 계정의 인벤토리가 아닌 내 계정의 인벤토리 정보가 수정되는 것을 발견하였다. 테스트 결과 access token이 만료되어 재발급 하는 과정에서 refresh token 을 비워서 보내면 뜬금없이 내 계정에 대한 JWT 토큰이 발급되는 것을 확인하였다.
원인
async findByRefreshToken(refreshToken: string): Promise<RefreshToken | null> {
return await this.findOne({ where: { refresh_token: refreshToken } });
}
클라이언트가 refresh token을 전송하면 그 정보를 바탕으로 위 메서드를 이용해 해당 토큰이 어떤 유저의 토큰이고 언제 만료되어야 하는지에 대한 로우를 가져온다. 이때 만일 refreshToken에 undefined 값이 들어가면 해당 조건 절이 무시되어 테이블의 가장 첫번째 로우를 반환한다. 공교롭게도 해당 로우는 내 계정이었고, 이 때문에 서버를 개발하면서 내 계정으로 서버 api가 잘 작동하는지 테스트 했을 때는 문제를 찾을 수 없었다.
해결 과정
위 경우를 포함해 모든 findOne() 메서드에 대해 조건절이 undefined가 넘어갈 수 없도록 검사하도록 수정했다.
새로 알게 된 것
FineOne의 문제점
await this.userRepository.findOne(
{ where:
{ email: 'example@sam-meows.com' }
}
);
findOne() 메서드는 인자로 where 구문을 이용해 검색 조건을 설정할 수 있다.
이때 검색 조건 뒤에 오는 값이 undefined인 경우 해당 값이 null인 값 등을 찾는 것이 아닌 구문 자체가 무시된다.
즉 where절 자체가 무시되고, 단순히 테이블의 첫 번째 로우를 가져오는 함수로 바뀌게 된다.
따라서 조건이 undefined이 아닌지 체크 후 사용하거나 find() 메서드에 take: 1 인자를 주어 이용하여야 한다.
'back-end > 🐾 삼냥이즈 트러블슈팅' 카테고리의 다른 글
| [삼냥이즈 트러블슈팅] MySQL Deadlock 원인 분석과 해결 (0) | 2026.03.16 |
|---|