180 lines
26 KiB
Markdown
180 lines
26 KiB
Markdown
# 2026-06-16 프로젝트 전면 분석
|
|
|
|
## 범위
|
|
|
|
- 목적: 현재 프로젝트의 아키텍처, 보안, 품질, 도메인 상태를 읽기 전용으로 분석하고 후속 보안 개선 항목을 정리한다.
|
|
- 변경 원칙: 이 분석 세션은 문서와 프로젝트 지침만 추가/수정한다. `src/`와 `pom.xml`은 수정하지 않는다.
|
|
- 조사 방식: 파일 목록, 컨트롤러, 매퍼, JSP, 설정 파일을 `rg`와 라인 번호 기준으로 확인했다.
|
|
|
|
## 요약
|
|
|
|
- 보안 기초는 비교적 견고하다. MyBatis 매퍼는 동적 `${}` 조립 없이 `#{}` 바인딩을 쓰고, 비밀번호는 PBKDF2-SHA256 210,000회 반복으로 저장한다.
|
|
- 주요 보안 갭은 `POST /login`, `POST /signup`에 CSRF 검증이 없는 점이다. 다른 주요 상태 변경 API는 `CsrfTokens.isValid`를 적용하고 있다.
|
|
- 파일 업로드와 WebGL asset 제공 경로는 normalize/startsWith 검사를 반복 적용하고, zip-slip 및 XSS 방어도 일관된 편이다.
|
|
- 구조적 부채는 서비스 레이어 부재, fat controller, 프로토타입 잔재(`abstracts`, `header.jspf`, `GameCatalog`), 실질 테스트 부족이다.
|
|
- 좋아요/댓글은 DB 매퍼와 삭제 연계는 있으나, 상세 화면은 `localStorage`만 사용해 서버 영속화가 미완성이다.
|
|
|
|
## 1. 아키텍처 분석
|
|
|
|
### A1. 현재 구조는 Controller + Mapper 중심이다
|
|
|
|
- Spring MVC JSP 뷰 구조는 `spring.mvc.view.prefix`와 suffix 설정에 고정되어 있다. 근거: `src/main/resources/application.properties:5`, `src/main/resources/application.properties:6`
|
|
- 홈/로그인/회원가입/프로필 라우팅은 `WebMvcController`가 담당한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/WebMvcController.java:57`, `src/main/java/com/pandoli365/bibimbap/controller/WebMvcController.java:64`, `src/main/java/com/pandoli365/bibimbap/controller/WebMvcController.java:75`, `src/main/java/com/pandoli365/bibimbap/controller/WebMvcController.java:88`
|
|
- 회원가입, 로그인, 프로필 변경은 `UserController`가 요청 검증, DB 접근, 세션 저장, 응답 생성을 함께 수행한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:65`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:118`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:173`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:209`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:494`
|
|
- 게임 등록/수정/삭제도 컨트롤러가 검증, 권한 확인, 매퍼 호출을 직접 수행한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:41`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:158`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:222`
|
|
- 모집글 등록도 동일 패턴이다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:49`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:73`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:116`
|
|
|
|
영향: 단기 구현 속도는 빠르지만, 보안 검증과 도메인 규칙이 컨트롤러마다 흩어진다. CSRF 누락처럼 특정 엔드포인트만 빠지는 회귀가 발생하기 쉽다.
|
|
|
|
### A2. 정적 리소스 제공은 프로필과 게임 asset이 분리되어 있다
|
|
|
|
- 프로필 이미지는 `UploadResourceConfig`에서 `/profile/**`로 노출한다. 근거: `src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java:19`, `src/main/java/com/pandoli365/bibimbap/config/UploadResourceConfig.java:22`
|
|
- WebGL 게임 asset은 별도 컨트롤러가 `/game/{gameUuid}/**`를 직접 처리한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:31`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:43`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:50`
|
|
- WebGL 응답에는 `X-Content-Type-Options`와 CSP가 설정된다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:59`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:60`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:65`
|
|
|
|
영향: 업로드 asset을 일반 정적 리소스와 분리한 점은 좋다. 단, 사용자가 만든 WebGL을 같은 사이트 origin에서 iframe으로 실행하므로 장기적으로 별도 asset origin 정책을 결정해야 한다.
|
|
|
|
### A3. 프로토타입 잔재가 남아 있다
|
|
|
|
- `GameController`는 DB에 게임이 없으면 `GameCatalog`로 fallback한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:103`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:111`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:116`
|
|
- `GameCatalog`는 빈 배열만 가진다. 근거: `src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java:8`, `src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java:12`, `src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java:18`
|
|
- `header.jspf`는 Spring Security taglib와 `${_csrf}`를 전제로 하지만, 실제 화면은 `/WEB-INF/views/header.jsp`를 include한다. 근거: `src/main/webapp/WEB-INF/jsp/fragments/header.jspf:1`, `src/main/webapp/WEB-INF/jsp/fragments/header.jspf:2`, `src/main/webapp/WEB-INF/jsp/fragments/header.jspf:14`, `src/main/webapp/WEB-INF/views/login.jsp:203`, `src/main/webapp/WEB-INF/views/signup.jsp:201`
|
|
- `abstracts.Service`는 현재 컨트롤러 흐름과 별개인 수동 인증/요청 검증 추상화다. 근거: `src/main/java/com/pandoli365/bibimbap/abstracts/Service.java:5`, `src/main/java/com/pandoli365/bibimbap/abstracts/Service.java:7`, `src/main/java/com/pandoli365/bibimbap/abstracts/Service.java:11`, `src/main/java/com/pandoli365/bibimbap/abstracts/Service.java:12`
|
|
|
|
영향: 죽은 코드가 보안 로직처럼 보이는 상태로 남아 있으면 새 구현자가 잘못 재사용할 수 있다. 삭제 전 참조 검색과 동작 확인이 필요하다.
|
|
|
|
## 2. 보안 분석
|
|
|
|
### S1. SQL injection 표면은 현재 스캔 범위에서 발견되지 않았다
|
|
|
|
- `src/main/java/com/pandoli365/bibimbap/mapper`와 controller 패키지에서 MyBatis 동적 치환 `${}` 사용은 발견되지 않았다.
|
|
- 검색 쿼리도 `ILIKE CONCAT('%', #{query}, '%')`로 바인딩한다. 근거: `src/main/java/com/pandoli365/bibimbap/mapper/GamesMapper.java:85`, `src/main/java/com/pandoli365/bibimbap/mapper/GamesMapper.java:86`, `src/main/java/com/pandoli365/bibimbap/mapper/GamesMapper.java:87`
|
|
- 주요 insert/update/select는 `#{}` 바인딩을 사용한다. 근거: `src/main/java/com/pandoli365/bibimbap/mapper/UsersMapper.java:25`, `src/main/java/com/pandoli365/bibimbap/mapper/UsersMapper.java:39`, `src/main/java/com/pandoli365/bibimbap/mapper/UserAuthIdentitiesMapper.java:47`, `src/main/java/com/pandoli365/bibimbap/mapper/UserAuthIdentitiesMapper.java:67`, `src/main/java/com/pandoli365/bibimbap/mapper/GamesMapper.java:128`, `src/main/java/com/pandoli365/bibimbap/mapper/RecruitPostsMapper.java:91`
|
|
|
|
판정: 현재 코드 스캔 기준 SQLi 직접 표면은 0이다. 동적 정렬/테이블명 기능을 추가할 때도 `${}`를 금지하는 규칙을 유지해야 한다.
|
|
|
|
### S2. 비밀번호 저장 방식은 강한 편이다
|
|
|
|
- 최소 비밀번호 길이와 PBKDF2 파라미터가 상수로 정의되어 있다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:45`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:46`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:47`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:48`
|
|
- 신규 비밀번호는 salt 생성 후 `pbkdf2_sha256$iterations$salt$hash` 형식으로 저장된다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:542`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:543`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:546`
|
|
- 검증은 저장된 iteration/salt를 읽고 `MessageDigest.isEqual`로 비교한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:551`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:558`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:561`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:562`
|
|
- 알고리즘은 `PBKDF2WithHmacSHA256`이다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:568`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:571`
|
|
|
|
판정: 현재 구현은 기본 수준 이상이다. 향후에는 로그인 실패 제한, 비밀번호 재해시 정책, 계정 잠금 정책을 별도 개선으로 다루면 된다.
|
|
|
|
### S3. CSRF 방어는 전반적으로 있으나 login/signup에 구멍이 있다
|
|
|
|
- CSRF 토큰은 세션에 저장되고 32바이트 난수로 생성된다. 근거: `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:20`, `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:28`, `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:31`
|
|
- 검증은 `X-CSRF-Token` 헤더 또는 `_csrf` 파라미터를 허용한다. 근거: `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:35`, `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:44`, `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:46`, `src/main/java/com/pandoli365/bibimbap/security/CsrfTokens.java:48`
|
|
- JSP 공통 초기화는 meta token과 JS header helper를 제공한다. 근거: `src/main/webapp/WEB-INF/views/theme-init.jsp:5`, `src/main/webapp/WEB-INF/views/theme-init.jsp:7`, `src/main/webapp/WEB-INF/views/theme-init.jsp:19`, `src/main/webapp/WEB-INF/views/theme-init.jsp:27`
|
|
- 로그아웃, 프로필 변경, 게임 업로드, 게임 등록/수정/삭제, 모집글 등록은 CSRF 검증을 한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:164`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:179`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:215`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:59`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:106`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:170`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:53`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:171`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:227`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:65`
|
|
- `POST /signup`은 컨트롤러 진입 후 CSRF 검증 없이 입력 검증과 DB 조회를 시작한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:65`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:75`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:87`
|
|
- `POST /login`도 CSRF 검증 없이 인증 로직과 세션 갱신으로 이어진다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:118`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:126`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:151`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:152`
|
|
- 로그인/회원가입 fetch 요청은 현재 CSRF header helper를 쓰지 않는다. 근거: `src/main/webapp/WEB-INF/views/login.jsp:277`, `src/main/webapp/WEB-INF/views/login.jsp:279`, `src/main/webapp/WEB-INF/views/login.jsp:284`, `src/main/webapp/WEB-INF/views/signup.jsp:291`, `src/main/webapp/WEB-INF/views/signup.jsp:293`, `src/main/webapp/WEB-INF/views/signup.jsp:297`
|
|
|
|
판정: MED. 공격자가 피해자의 브라우저에서 원치 않는 로그인 상태 전환 또는 회원가입 요청을 유도할 수 있다. 기존 CSRF 헬퍼가 있어 수정 범위는 작다.
|
|
|
|
### S4. 업로드와 파일 경로 방어는 일관되어 있다
|
|
|
|
- 게임 파일 업로드는 CSRF와 로그인 세션을 먼저 확인한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:59`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:62`
|
|
- WebGL zip 업로드는 zip 여부, 로그인, target path boundary를 확인한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:106`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:113`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:121`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:127`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:128`
|
|
- zip entry 개수와 압축 해제 총량 제한이 있다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:40`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:41`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:261`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:297`
|
|
- zip-slip 방어는 `targetDir.resolve(entry.getName()).normalize()` 후 `startsWith(targetDir)`로 수행된다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:266`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:267`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:268`
|
|
- 썸네일/프로필 이미지는 크기와 확장자/Content-Type 검사를 한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:181`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:186`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:228`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:233`
|
|
- 프로필 저장 경로도 root boundary를 검사한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:246`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:248`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:254`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:256`
|
|
- 게임 asset 조회도 URI decode 후 normalize/startsWith를 수행한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:91`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:92`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:101`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameAssetController.java:102`
|
|
|
|
판정: 현재 방어는 좋다. 다만 운영 설정에서 multipart 상한이 1GB로 높아 실제 서버 메모리/디스크 정책과 맞는지 재검토해야 한다. 근거: `src/main/resources/application.properties:15`, `src/main/resources/application.properties:16`, `src/main/resources/application.properties:17`, `src/main/resources/application.properties:18`
|
|
|
|
### S5. XSS 방어는 서버 렌더와 클라이언트 렌더 모두 대체로 안전하다
|
|
|
|
- 게임 상세 주요 출력값은 `HtmlUtils.htmlEscape`로 이스케이프한다. 근거: `src/main/webapp/WEB-INF/views/game-detail.jsp:6`, `src/main/webapp/WEB-INF/views/game-detail.jsp:7`, `src/main/webapp/WEB-INF/views/game-detail.jsp:10`, `src/main/webapp/WEB-INF/views/game-detail.jsp:21`
|
|
- 홈 검색어와 게임 카드 출력도 escape를 적용한다. 근거: `src/main/webapp/WEB-INF/views/index.jsp:21`, `src/main/webapp/WEB-INF/views/index.jsp:466`, `src/main/webapp/WEB-INF/views/index.jsp:506`, `src/main/webapp/WEB-INF/views/index.jsp:507`, `src/main/webapp/WEB-INF/views/index.jsp:514`
|
|
- 댓글 localStorage 렌더링은 `textContent`를 사용한다. 근거: `src/main/webapp/WEB-INF/views/game-detail.jsp:951`, `src/main/webapp/WEB-INF/views/game-detail.jsp:958`, `src/main/webapp/WEB-INF/views/game-detail.jsp:969`
|
|
- 프로필 아바타 URL은 출력 전에 escape한다. 근거: `src/main/webapp/WEB-INF/views/header.jsp:8`, `src/main/webapp/WEB-INF/views/header.jsp:11`, `src/main/webapp/WEB-INF/views/header.jsp:219`
|
|
- 외부 Git URL은 `http://` 또는 `https://`만 허용한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:282`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:287`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:288`
|
|
|
|
판정: 현재 XSS 방어는 일관된 편이다. 서버 댓글 영속화를 붙일 때도 JSP 직접 출력 대신 escape/textContent 원칙을 유지해야 한다.
|
|
|
|
### S6. 세션 보안은 기본은 있으나 쿠키 하드닝 설정이 없다
|
|
|
|
- 로그인 성공 시 `request.changeSessionId()`로 세션 고정 공격을 줄인다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:151`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:152`
|
|
- 로그인 유지 옵션은 세션 만료 시간을 조정한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:49`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:50`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:317`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:318`
|
|
- `application.properties`에는 session cookie `HttpOnly`, `Secure`, `SameSite` 설정이 없다. 근거: `src/main/resources/application.properties:1`, `src/main/resources/application.properties:27`
|
|
|
|
판정: B4에서 운영 프로필 기준 쿠키 하드닝을 추가한다.
|
|
|
|
### S7. 의존성/로깅 운영 리스크가 있다
|
|
|
|
- Spring Boot 버전이 SNAPSHOT이다. 근거: `pom.xml:29`
|
|
- snapshot repository와 pluginRepository가 활성화되어 있다. 근거: `pom.xml:200`, `pom.xml:202`, `pom.xml:210`, `pom.xml:212`
|
|
- MyBatis TRACE 로그가 켜져 있다. 근거: `src/main/resources/application.properties:25`, `src/main/resources/application.properties:26`, `src/main/resources/application.properties:27`
|
|
|
|
판정: 배포 안정성과 보안 재현성을 위해 release 버전 고정, CVE 스캔, 운영 로깅 레벨 분리가 필요하다.
|
|
|
|
## 3. 품질 분석
|
|
|
|
### Q1. 테스트가 실질 보안/도메인 동작을 검증하지 않는다
|
|
|
|
- 기본 테스트는 context load뿐이다. 근거: `src/test/java/com/pandoli365/bibimbap/BibimbapApplicationTests.java:6`, `src/test/java/com/pandoli365/bibimbap/BibimbapApplicationTests.java:9`, `src/test/java/com/pandoli365/bibimbap/BibimbapApplicationTests.java:10`
|
|
- DB 업데이트 쿼리 생성 테스트는 surefire에서 제외되어 일반 테스트로 돌지 않는다. 근거: `pom.xml:127`, `pom.xml:130`, `pom.xml:131`
|
|
- CSRF, 로그인, 업로드 zip-slip, XSS 렌더링 회귀 테스트가 없다. 근거: 현재 `src/test/java/com/pandoli365/bibimbap/BibimbapApplicationTests.java:9` 외 애플리케이션 동작 테스트가 확인되지 않는다.
|
|
|
|
영향: 보안 개선 PR마다 최소 MockMvc 테스트를 붙여 회귀를 잡아야 한다.
|
|
|
|
### Q2. 컨트롤러에 중복 helper가 많다
|
|
|
|
- 세션 사용자 ID 추출이 여러 컨트롤러에 반복된다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:325`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:222`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:291`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:155`
|
|
- trim helper도 반복된다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:317`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:173`
|
|
|
|
영향: 정책 변경 시 수정 누락 위험이 높다. 서비스/유틸 레이어 도입은 보안 변경 뒤 별도 PR로 다루는 편이 안전하다.
|
|
|
|
### Q3. 설정 상한과 실제 검증 상한이 어긋난다
|
|
|
|
- Spring multipart 상한은 1GB다. 근거: `src/main/resources/application.properties:15`, `src/main/resources/application.properties:16`
|
|
- WebGL zip 압축 해제 총량 제한은 512MB다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:40`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameUploadController.java:297`
|
|
|
|
영향: 애플리케이션 레벨에서 거절하기 전 서버가 큰 요청을 받아야 한다. 운영 인프라 제한과 함께 조정해야 한다.
|
|
|
|
## 4. 도메인 분석
|
|
|
|
### D1. 회원가입 문서는 다중 provider를 설명하지만 구현은 email provider 중심이다
|
|
|
|
- 문서는 `guest`, `google`, `email`, `kakao`, `naver`, `github`, `apple`를 설명한다. 근거: `docs/user-signup-schema.md:32`
|
|
- 현재 컨트롤러는 `PROVIDER_EMAIL` 상수로 email provider를 사용한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:42`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:87`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:100`
|
|
- 회원가입 JSP에는 `provider` hidden input이 있지만 컨트롤러는 해당 파라미터를 받지 않는다. 근거: `src/main/webapp/WEB-INF/views/signup.jsp:216`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:67`, `src/main/java/com/pandoli365/bibimbap/controller/api/UserController.java:72`
|
|
|
|
영향: 문서와 구현 간 목표 차이가 있다. 소셜/게스트 가입을 실제 기능으로 만들지, 문서를 email-only로 조정할지 결정해야 한다.
|
|
|
|
### D2. 게임 등록/수정/삭제는 서버 영속화되어 있다
|
|
|
|
- 게임 생성은 `gamesMapper.addGame`으로 저장한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:80`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:90`, `src/main/java/com/pandoli365/bibimbap/mapper/GamesMapper.java:117`
|
|
- 게임 수정은 작성자 확인 후 `gamesMapper.updateGame`을 호출한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:179`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:183`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:212`
|
|
- 게임 삭제는 댓글 soft delete와 좋아요 삭제를 함께 수행한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:243`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:244`, `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java:245`
|
|
|
|
영향: 게임 CRUD는 서버 중심으로 동작한다. 좋아요/댓글만 연결되지 않은 상태다.
|
|
|
|
### D3. 좋아요/댓글은 DB 모델은 있으나 상세 화면은 localStorage 전용이다
|
|
|
|
- 좋아요 매퍼는 존재한다. 근거: `src/main/java/com/pandoli365/bibimbap/mapper/GameLikesMapper.java:10`, `src/main/java/com/pandoli365/bibimbap/mapper/GameLikesMapper.java:24`, `src/main/java/com/pandoli365/bibimbap/mapper/GameLikesMapper.java:36`
|
|
- 댓글 매퍼는 존재한다. 근거: `src/main/java/com/pandoli365/bibimbap/mapper/GameCommentsMapper.java:10`, `src/main/java/com/pandoli365/bibimbap/mapper/GameCommentsMapper.java:27`, `src/main/java/com/pandoli365/bibimbap/mapper/GameCommentsMapper.java:41`
|
|
- 상세 화면 좋아요는 `localStorage` map만 갱신한다. 근거: `src/main/webapp/WEB-INF/views/game-detail.jsp:811`, `src/main/webapp/WEB-INF/views/game-detail.jsp:812`, `src/main/webapp/WEB-INF/views/game-detail.jsp:817`, `src/main/webapp/WEB-INF/views/game-detail.jsp:830`, `src/main/webapp/WEB-INF/views/game-detail.jsp:904`, `src/main/webapp/WEB-INF/views/game-detail.jsp:906`
|
|
- 상세 화면 댓글도 `localStorage`에 저장하고 DOM으로 렌더링한다. 근거: `src/main/webapp/WEB-INF/views/game-detail.jsp:813`, `src/main/webapp/WEB-INF/views/game-detail.jsp:913`, `src/main/webapp/WEB-INF/views/game-detail.jsp:928`, `src/main/webapp/WEB-INF/views/game-detail.jsp:994`, `src/main/webapp/WEB-INF/views/game-detail.jsp:1002`
|
|
|
|
영향: 사용자는 브라우저를 바꾸면 좋아요/댓글을 잃는다. 서버 연결 시 익명 허용 여부, 남용 방지, 삭제 권한, CSRF 정책을 먼저 확정해야 한다.
|
|
|
|
### D4. 모집글은 서버 영속화되어 있다
|
|
|
|
- 목록, 작성, 상세 라우트가 존재한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:35`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:49`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:145`
|
|
- 작성 시 enum-like set과 길이 검증을 수행한다. 근거: `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:25`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:26`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:27`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:80`, `src/main/java/com/pandoli365/bibimbap/controller/RecruitController.java:112`
|
|
- 매퍼는 visible/not-deleted 조건으로 조회한다. 근거: `src/main/java/com/pandoli365/bibimbap/mapper/RecruitPostsMapper.java:67`, `src/main/java/com/pandoli365/bibimbap/mapper/RecruitPostsMapper.java:68`, `src/main/java/com/pandoli365/bibimbap/mapper/RecruitPostsMapper.java:74`
|
|
|
|
영향: 모집글 쪽은 최소 CRUD 흐름이 게임 CRUD와 비슷한 수준으로 정리되어 있다.
|
|
|
|
## 후속 작업 후보
|
|
|
|
- B1: `login`/`signup` CSRF 검증 추가. 자세한 실행 항목은 [보안 개선 체크리스트](../security/security-remediation-checklist.md#b1-loginsignup-csrf-검증-추가-med)를 따른다.
|
|
- B2: 프로토타입 dead code 제거. 자세한 실행 항목은 [보안 개선 체크리스트](../security/security-remediation-checklist.md#b2-프로토타입-dead-code-제거)를 따른다.
|
|
- B3: 좋아요/댓글 서버 영속화 연결. 자세한 실행 항목은 [보안 개선 체크리스트](../security/security-remediation-checklist.md#b3-좋아요댓글-서버-영속화-연결)를 따른다.
|
|
- B4: Spring Boot SNAPSHOT 고정, 세션 쿠키 하드닝, 의존성 CVE 스캔. 자세한 실행 항목은 [보안 개선 체크리스트](../security/security-remediation-checklist.md#b4-의존성세션운영-하드닝)를 따른다.
|