[FEAT] 비회원용 테이블정보 조회 메서드 추가#257
Conversation
Walkthrough비회원이 테이블 ID만으로 커스텀 토론 시간표를 조회할 수 있도록 Changes비회원용 커스텀 테이블 조회 API
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Test Results145 files 145 suites 20s ⏱️ Results for commit 1088eae. |
📝 Test Coverage Report
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new API endpoint /api/live/table/customize/{tableId} to allow non-members to retrieve customized debate tables, along with the necessary service, repository, and test updates. The review feedback highlights a critical security vulnerability (IDOR/BOLA) due to the use of sequential IDs for the public endpoint, recommending the use of non-sequential identifiers like UUIDs or sharing status validation. Additionally, there is an opportunity to reduce code duplication in CustomizeTableDomainRepository by extracting common time box retrieval logic into a private helper method.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| @GetMapping("/api/live/table/customize/{tableId}") | ||
| @ResponseStatus(HttpStatus.OK) | ||
| public CustomizeTableResponse getTable( | ||
| @PathVariable long tableId | ||
| ) { | ||
| return customizeService.findTable(tableId); | ||
| } |
There was a problem hiding this comment.
비회원용 토론 테이블 정보를 조회하기 위해 인증 없이 접근 가능한 /api/live/table/customize/{tableId} 엔드포인트를 추가하셨습니다.
하지만 tableId가 순차적인 long 타입(Sequential ID)이기 때문에, 악의적인 사용자가 ID를 1씩 증가시키며 API를 호출(IDOR/BOLA 공격)할 경우 시스템에 등록된 모든 회원의 커스텀 토론 테이블 정보를 무단으로 조회(Scraping)할 수 있는 심각한 보안 취약점이 존재합니다.
권장 해결 방안:
- 비순차적 식별자(UUID 등) 사용: 외부 공유용 API에서는 순차적인 DB PK 대신 예측 불가능한 UUID나 별도의 공유용 토큰(Share Token)을 식별자로 사용하도록 설계합니다.
- 공유 상태 검증: 테이블 엔티티에 공유 활성화 여부(예:
isShared또는status등)를 나타내는 필드를 추가하고, 비회원 조회 시 해당 테이블이 실제로 공유 가능한 상태인지 검증하는 로직을 추가합니다.
| public List<CustomizeTimeBox> getMemberCustomizeTimeBoxes(long tableId, Member member) { | ||
| CustomizeTableEntity tableEntity = tableRepository.getByIdAndMember(tableId, member); | ||
| List<CustomizeTimeBoxEntity> timeBoxEntityList = timeBoxRepository.findAllByCustomizeTable(tableEntity); | ||
| List<BellEntity> bellEntityList = bellRepository.findAllByCustomizeTimeBoxIn(timeBoxEntityList); | ||
| return toCustomizeTimeBoxes(timeBoxEntityList, bellEntityList); | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public List<CustomizeTimeBox> getCustomizeTimeBoxes(long tableId) { | ||
| CustomizeTableEntity tableEntity = tableRepository.getById(tableId); | ||
| List<CustomizeTimeBoxEntity> timeBoxEntityList = timeBoxRepository.findAllByCustomizeTable(tableEntity); | ||
| List<BellEntity> bellEntityList = bellRepository.findAllByCustomizeTimeBoxIn(timeBoxEntityList); | ||
| return toCustomizeTimeBoxes(timeBoxEntityList, bellEntityList); | ||
| } |
There was a problem hiding this comment.
두 메서드(getMemberCustomizeTimeBoxes와 getCustomizeTimeBoxes)에서 CustomizeTableEntity를 기반으로 CustomizeTimeBox 목록을 조회하고 변환하는 로직이 완전히 중복되고 있습니다. 공통 로직을 private 헬퍼 메서드로 분리하여 코드의 재사용성과 유지보수성을 높이는 것을 권장합니다.
@Transactional(readOnly = true)
public List<CustomizeTimeBox> getMemberCustomizeTimeBoxes(long tableId, Member member) {
CustomizeTableEntity tableEntity = tableRepository.getByIdAndMember(tableId, member);
return getCustomizeTimeBoxes(tableEntity);
}
@Transactional(readOnly = true)
public List<CustomizeTimeBox> getCustomizeTimeBoxes(long tableId) {
CustomizeTableEntity tableEntity = tableRepository.getById(tableId);
return getCustomizeTimeBoxes(tableEntity);
}
private List<CustomizeTimeBox> getCustomizeTimeBoxes(CustomizeTableEntity tableEntity) {
List<CustomizeTimeBoxEntity> timeBoxEntityList = timeBoxRepository.findAllByCustomizeTable(tableEntity);
List<BellEntity> bellEntityList = bellRepository.findAllByCustomizeTimeBoxIn(timeBoxEntityList);
return toCustomizeTimeBoxes(timeBoxEntityList, bellEntityList);
}There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/com/debatetimer/controller/sharing/SharingRestController.java`:
- Around line 33-39: The getTable endpoint in SharingRestController currently
exposes customizeService.findTable(tableId) using only tableId, which allows
unauthorized lookup; update this flow to require a valid access constraint such
as a share token, live-session verification, or another public identifier before
calling findTable. Keep the controller method and customizeService.findTable as
the main locations to adjust, and ensure the lookup is scoped so anonymous
access cannot fetch arbitrary table data.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 028117d7-2183-4013-8ca9-13dacdde2649
📒 Files selected for processing (10)
src/main/java/com/debatetimer/controller/customize/CustomizeController.javasrc/main/java/com/debatetimer/controller/sharing/SharingRestController.javasrc/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.javasrc/main/java/com/debatetimer/repository/customize/CustomizeTableRepository.javasrc/main/java/com/debatetimer/service/customize/CustomizeService.javasrc/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.javasrc/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.javasrc/test/java/com/debatetimer/controller/sharing/SharingRestControllerTest.javasrc/test/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepositoryTest.javasrc/test/java/com/debatetimer/service/customize/CustomizeServiceTest.java
| @GetMapping("/api/live/table/customize/{tableId}") | ||
| @ResponseStatus(HttpStatus.OK) | ||
| public CustomizeTableResponse getTable( | ||
| @PathVariable long tableId | ||
| ) { | ||
| return customizeService.findTable(tableId); | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
비회원 조회를 tableId 단독으로 열지 마세요.
Line 33-39는 인증·공유 토큰·라이브 세션 검증 없이 customizeService.findTable(tableId)를 호출합니다. 현재 이 경로는 서비스/도메인 레이어에서 getById(tableId)와 getCustomizeTimeBoxes(tableId)로 바로 이어지므로, 웹소켓 참가 맥락과 무관하게 tableId만 알면 임의의 사용자 지정 테이블 내용을 조회할 수 있습니다. 비회원 조회가 필요하더라도 공개용 식별자나 세션/공유 토큰 검증으로 범위를 제한하는 편이 안전합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/debatetimer/controller/sharing/SharingRestController.java`
around lines 33 - 39, The getTable endpoint in SharingRestController currently
exposes customizeService.findTable(tableId) using only tableId, which allows
unauthorized lookup; update this flow to require a valid access constraint such
as a share token, live-session verification, or another public identifier before
calling findTable. Keep the controller method and customizeService.findTable as
the main locations to adjust, and ensure the lookup is scoped so anonymous
access cannot fetch arbitrary table data.
🚩 연관 이슈
closed #256
🗣️ 리뷰 요구사항 (선택)
웹소켓 통신과정에서 비회원의 경우에도 토론 테이블 정보를 조회하기 위한 Rest API가 필요해져 이를 추가합니다.
Summary by CodeRabbit
New Features
Bug Fixes
Tests