Open Donggeon0304 opened 1 month ago
문제: Spring Boot 애플리케이션에서 JWT 토큰을 쿠키에 저장한 후, 각 사용자의 역할(Role)에 따라 페이지를 리디렉션하는 과정에서 클라이언트가 JWT 토큰을 읽지 못해 리디렉션이 실패하는 문제가 발생. 증상: 로그인이 성공했음에도 불구하고 사용자가 계속해서 로그인 페이지에 머물렀고, 권한에 따른 페이지로 리디렉션되지 않음. 발생 조건: JWT 토큰을 쿠키에 HttpOnly 속성으로 저장하여 클라이언트에서 접근할 수 없었을 때 발생.
원인: HttpOnly 속성으로 인해 클라이언트 측에서 JWT 토큰을 읽을 수 없었음. 이로 인해 사용자의 역할(Role)을 판별하지 못하고, 적절한 권한에 따른 페이지 리디렉션이 불가능했음.
HttpOnly 속성은 보안을 강화하기 위해 클라이언트 측에서 쿠키에 직접 접근할 수 없도록 하는 속성으로, XSS 공격 등을 방지하기 위한 보안 설정임. 로그인 후 JWT 토큰은 서버 측에서 인증을 위해 필요하지만, 클라이언트는 이를 읽을 수 없기 때문에 페이지 리디렉션 로직에서 문제가 발생.
서버 측에서 JWT 토큰을 읽고 권한을 판별: 클라이언트에서 JWT 토큰을 사용할 수 없으므로, 서버에서 HttpServletRequest 객체를 사용해 쿠키에 저장된 JWT 토큰을 읽는 메서드를 구현. 서버가 토큰을 분석하여 사용자의 권한(Role)을 파악하고, 해당 권한에 맞는 페이지로 리디렉션을 처리하도록 로직 수정. Security Filter Chain에서의 권한 설정: Security Filter Chain에서 인증된 사용자의 역할을 확인하고, 해당 역할에 따라 요청을 필터링하여 적절한 페이지로 리디렉션되도록 설정. 클라이언트와 서버 간의 인증 흐름 재구성: JWT 토큰을 HttpOnly 쿠키에 저장하되, 클라이언트는 서버와의 요청에서만 JWT를 사용하고, 권한에 따른 리디렉션 처리는 서버가 담당하는 방식으로 개선.
서버가 HttpOnly JWT 토큰을 사용하여 사용자의 권한을 판별하고, 각 사용자에 맞는 페이지로 리디렉션하는 기능이 정상적으로 작동하게 됨. 이후 JWT 토큰 기반의 인증과 페이지 리디렉션이 안정적으로 구현되어, 로그인 후 각 권한(Role)에 따라 사용자가 올바른 페이지에 접근할 수 있게 됨.
교훈: 보안상의 이유로 JWT 토큰을 HttpOnly 쿠키에 저장하는 경우, 클라이언트가 토큰을 읽어 사용하지 못하므로 서버 측에서 이를 처리하는 로직이 필수적임. 향후 대책: HttpOnly 속성의 활용 시, 서버가 인증 및 권한 관리를 철저하게 처리하도록 하고, 클라이언트 측에서 JWT를 직접적으로 다루지 않도록 보안을 강화. 권한에 따른 페이지 리디렉션뿐만 아니라, 향후 인증 관련 로직을 재사용할 수 있도록 서비스 구조를 모듈화하는 것을 고려. 이 과정에서 JWT와 Spring Security의 통합적인 활용 방법과 보안성을 유지하면서도 사용자 경험을 향상시킬 수 있는 설계 방법에 대해 더 깊이 이해하게 되었음.
문제 1: 배포된 스프링 부트 JAR 애플리케이션에서 Thymeleaf 템플릿 경로로 지정된 HTML 파일을 찾지 못함. 문제 2: 정식 배포 전 테스트 환경에서 JWT 토큰이 생성되지 않음.
문제 1: Thymeleaf 경로 문제
HTML 파일을 찾는 경로가 /로 시작할 경우, 상대 경로가 아닌 절대 경로로 해석되어 서버의 루트 디렉토리를 참조하게 됨. 이로 인해 애플리케이션의 컨텍스트 경로가 포함되지 않아 템플릿을 찾지 못하는 문제가 발생. 문제 2: JWT 토큰 생성 문제
개발기간 중 테스트를 위한 배포 중 JWT 토큰을 설정할 때 setSecure(true)로 되어 있어, HTTPS 연결에서만 쿠키가 전송됨. 로컬 개발 환경에서는 HTTP로 요청하므로, 토큰이 발급되지 않는 문제가 발생.
문제 1: Thymeleaf 경로 수정
HTML 경로에서 /로 시작하는 부분을 제거하여 상대 경로로 변경:
변경 전: return "views/home"; // /views/home.html 변경 후: return "home"; // views/home.html Thymeleaf의 기본 템플릿 경로를 설정하여 모든 경로에서 HTML 파일을 올바르게 참조하도록 조정.
문제 2: JWT 토큰 생성 설정 수정
JWT 생성 로직에서 boolean isSecure = requet.isSecure(); cookie.setSecure(isSecure)을 추가:
변경 전: cookie.setSecure(true); // HTTPS에서만 쿠키 전송 변경 후: boolean isSecure = request.isSecure(); cookie.setSecure(isSecure); // HTTP이면 false, HTTPS이면 true 이후 보안을 위해 프로덕션 환경에서는 HTTPS를 사용하는 것이 권장됨.
문제 1: HTML 경로를 수정한 후, 서버에서 Thymeleaf 템플릿을 정상적으로 찾을 수 있게 되어 페이지가 올바르게 렌더링됨. 문제 2: JWT 토큰 생성 설정을 수정한 후, HTTP 요청에서도 쿠키가 정상적으로 발급되어 인증이 가능해짐.
경로 설정 시, 절대 경로와 상대 경로의 차이를 인지하고, 운영 환경에 맞게 적절히 설정하는 것이 중요함. JWT 토큰을 설정할 때는 개발 환경과 프로덕션 환경의 차이를 고려하여, 적절한 보안 설정을 미리 계획해야 함. HTTPS로 전환할 경우, 웹 서버 및 애플리케이션 설정을 점검하여 보안 설정을 적절히 구성하는 것을 잊지 말 것.
문제 정의 (Problem Definition) 문제: 출고 준비를 위해 상품에 선입고 순으로 Lot Number를 할당하기 위한 재귀 함수를 작성하는 과정에서 로직 오류가 발생함. 증상: 해당 Lot Number를 가진 상품의 재고가 0개인 경우에도 재고할당으로 간주하여 데이터베이스에 해당 데이터가 저장됨. 재고 오류로 인해 Lot Number에 해당하는 상품의 재고가 음수값 일 때, 음수 값을 유효한 수량으로 할당하는 문제가 발생함.
원인 분석 (Root Cause Analysis) 원인: 데이터베이스에서 가져온 Lot 수량이 0인 경우를 체크하지 않고, 선입고 순으로 존재하는 Lot Number를 무조건 유효한 Lot Number로 간주하여 할당 처리하였고 이로 인해 할당을 위한 남아있는 상품 수량이 0개 이하인 경우에도 조건문이 작동하게 되어, 음수로 설정된 수량에 대해서도 Lot Number를 할당하는 로직이 실행되게 되었음.
해결 방안 (Solution)
데이터가 존재하는 Lot Number 에 대해 발동되는 재귀함수의 return 자료형을 Lot Number를 할당한 데이터들의 리스트인 List
결과 (Result) Lot Number 에 해당하는 재고가 0개이거나 음수값일 경우 할당으로 처리하지 않고 다음 재귀를 호출함
교훈 및 향후 대책 (Lessons Learned and Future Prevention) 데이터베이스에서 가져온 값의 유효성을 항상 검증해야하는 것이 중요하고 입력값이 예상 범위에서 벗어났을 경우를 생각해야함. 재귀함수 설계시 종료조건을 명확히 하여 잘못된 데이터 처리로 이어지지 않도록 유의하도록 함. 재귀함수 설계시 boolean 변수를 활용하여 오류를 감지하고 대응할 수 있도록 함 다양한 데이터를 입력을 통해 로직의 유효성을 여러번 검토해보는 노력이 필요함.
1. 문제 정의 (Problem Definition)
PATCH
요청에서create_date
필드가 설정되지 않으면 서버에서 500 오류가 발생함.PATCH
요청을 보낼 때 서버에서500 Internal Server Error
가 발생하며, 서버 로그에는NullPointerException
이 기록됨.FormData
를 사용해create_date
필드를 설정하지 않고PATCH
요청을 전송했을 때 발생.2. 원인 분석 (Root Cause Analysis)
FormData
에서 필드가 설정되지 않으면 해당 필드가 서버로 전송되지 않음. 서버 측에서는create_date
필드가 필수인데, 해당 필드가 존재하지 않아 오류가 발생함.3. 해결 방안 (Solution)
FormData.set("create_date", null)
로 필드를 명시적으로 설정하여 전송.create_date
필드가null
인 경우 기본값을 적용하도록 로직을 수정.4. 결과 (Result)
null
을 설정하고 서버가 이를 처리하도록 수정한 후, 문제 해결됨.PATCH
요청에서도 오류 없이 동작 확인.5. 교훈 및 향후 대책 (Lessons Learned and Future Prevention)
PATCH
요청 시 필드가 선택적으로 전달되지 않을 수 있음을 고려하여 서버 로직을 구성해야 함.FormData
를 사용할 때, 선택적인 필드라도 명시적으로 설정하는 습관을 갖는 것이 좋음.