Skip to content

sirsoft-board 정책 제한값 하드코딩 문제 #81

Description

@jiwonpapa

게시판부분만 점검해 봤습니다. 전체적으로 점검해봐야할 문제라 생각 됩니다.

sirsoft-board 정책 제한값 하드코딩 1차 감사 보고서

제안 이슈 제목: [sirsoft-board] 설정 제한값 하드코딩과 정책 불일치로 검증·서비스·UI 계약이 분리됨

결론

첨부파일 최대 20개 한 건의 문제가 아니라, 설정 가능한 정책값이 검증 요청, 서비스, JSON UI, 다국어 문구, API 문서에 중복 하드코딩되어 실제 계약이 분리된 구조적 결함입니다.

본 보고서는 확인된 제한값 관련 경로를 대상으로 한 일부 감사입니다. 이번 결과만으로 sirsoft-board 전체 또는 그누보드7 전체에 하드코딩 문제가 없다고 판단할 수 없으며, 정식 출시 전 별도의 전수 감사가 필요합니다.

중앙 설정이 일부 존재하지만 적용 범위가 일관되지 않아 다음 문제가 이미 발생하고 있습니다.

확인된 핵심 위험은 다음과 같습니다.

우선순위 문제 현재 영향
높음 대댓글 저장 깊이가 서비스에서 5로 고정됨 설정값 6~10에서 깊이 제한과 계층 표현이 깨짐
높음 중앙 길이 제한과 관리자 기본설정 API의 검증값이 다름 UI가 허용하는 0을 저장 API가 거부함
높음 비동기 첨부 연결 경로에 게시판별 개수 상한이 없음 max_file_count를 초과한 첨부 연결 가능
중간 자동 숨김 0=비활성 정책과 UI 최소값이 다름 API는 0을 허용하지만 관리자 UI는 입력을 막음
중간 답변 깊이 상한이 코드와 문서에서 105로 분리됨 관리자 안내와 API 계약이 실제 검증 규칙과 다름
낮음 표시용 깊이와 첨부 안내 문구가 숫자를 직접 보유함 정책 변경 시 화면과 번역 리소스가 다시 어긋날 수 있음

최대 첨부 개수 20이라는 정책 자체가 결함인 것은 아닙니다. 문제는 이 값을 한 곳에서 변경해도 모든 검증과 UI가 함께 변경되지 않으며, 일부 실제 처리 경로는 해당 정책을 강제하지 않는 구조입니다.

감사 범위와 추가 필요성

이번 감사는 sirsoft-board에서 제한값 불일치가 확인된 게시판 설정, 댓글·답변 깊이, 첨부파일, 신고·스팸 설정과 직접 연결된 코드만 우선 대조한 1차 표본 감사입니다.

다음 범위는 전수 확인하지 않았으므로 추가 감사가 필요합니다.

  • sirsoft-board 전체 Controller, Request, Service, Repository, Listener, Job, migration, JSON UI 및 문서
  • 숫자 제한 외 상태값, 문자열 Enum, 기본값, 캐시 TTL, 페이지 크기, 재시도 횟수와 배치 크기
  • 코어와 다른 번들 모듈·플러그인의 설정값 중복 및 모듈 간 계약 불일치
  • 환경설정 변경 시 API, 관리자 UI, 사용자 UI, CLI·Queue가 동일하게 반영되는지에 대한 경계값 테스트

따라서 본 보고서의 확인 항목을 수정하는 것과 별개로, 저장소 전체를 대상으로 정책값 출처와 소비 지점을 자동 대조하는 전수 감사 작업을 진행해야 합니다.

확인 기준

항목
그누보드 버전 7.0.4
원본 게시판 모듈 버전 sirsoft-board 1.1.3
확인 커밋 348efa2e98df22b00d30d3a4e267d0305f201758
확인일 2026-07-17
분석 범위 확인된 제한값 관련 config, defaults, FormRequest, Service/Rule, JSON UI, lang, API 문서의 일부 경로

현재 작업트리의 별도 첨부 개선 코드와 버전 변경은 원본 결함 근거에서 제외하고, 위 커밋의 원본 코드만 대조했습니다. 본 보고서는 정적 소스 감사 결과이며 원본 코드는 수정하지 않았습니다.

상세 결과

H-01. 대댓글 깊이가 서비스에서 5로 고정됨

중앙 설정은 대댓글 깊이를 0~10으로 정의하고 기본값도 10으로 지정합니다.

  • modules/_bundled/sirsoft-board/config/board.php:151
  • modules/_bundled/sirsoft-board/config/settings/defaults.json:18

검증 규칙도 게시판의 max_comment_depth를 사용합니다.

  • modules/_bundled/sirsoft-board/src/Rules/CommentValidationRule.php:114

그러나 실제 저장 깊이는 다음 서비스 코드에서 5로 잘립니다.

$data['depth'] = min(($parentComment->depth ?? 0) + 1, 5);
  • modules/_bundled/sirsoft-board/src/Services/CommentService.php:257

이 때문에 설정값이 6~10이면 검증은 더 깊은 대댓글을 허용해도 저장된 depth는 계속 5가 됩니다. 이후 검증 역시 부모의 저장 깊이 5를 기준으로 판단하므로 설정 상한이 사실상 무력화될 수 있습니다.

H-02. 중앙 길이 제한과 관리자 기본설정 API가 불일치함

중앙 제한값은 최소 제목 및 최소 댓글 길이에 0을 허용합니다.

'min_title_length_min' => 0,
'min_comment_length_min' => 0,
  • modules/_bundled/sirsoft-board/config/board.php:121
  • modules/_bundled/sirsoft-board/config/board.php:133

게시판 생성·수정 요청과 관리자 JSON UI는 이 중앙 값을 사용합니다.

  • modules/_bundled/sirsoft-board/src/Http/Requests/StoreBoardRequest.php:116
  • modules/_bundled/sirsoft-board/src/Http/Requests/UpdateBoardRequest.php:95
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_board_settings_post.json:120
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_board_settings_comment.json:372

반면 관리자 기본설정 저장 요청은 두 최소값을 직접 1로 고정합니다.

'basic_defaults.min_title_length' => ['nullable', 'integer', 'min:1', 'max:200'],
'basic_defaults.min_comment_length' => ['nullable', 'integer', 'min:1', 'max:1000'],
  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:151
  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:155

동일한 설정값이 화면에서는 유효하지만 저장 API에서는 422가 되는 계약 불일치입니다.

H-03. 첨부 개수 정책이 중복되고 비동기 연결 경로에서는 강제되지 않음

게시판 설정의 허용 범위는 중앙 config에 1~20으로 정의되어 있습니다.

  • modules/_bundled/sirsoft-board/config/board.php:141

게시판 생성·수정 요청은 중앙 상한을 사용하지만, 관리자 기본설정 저장 요청은 20을 다시 직접 보유합니다.

'basic_defaults.max_file_count' => ['nullable', 'integer', 'min:1', 'max:20'],
  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:159

더 큰 문제는 실제 게시글 저장 API의 비동기 첨부 경로입니다. 원본 요청 검증은 attachment_ids가 배열과 정수인지 확인할 뿐 게시판의 max_file_count를 적용하지 않습니다.

  • modules/_bundled/sirsoft-board/src/Http/Requests/StorePostRequest.php:89
  • modules/_bundled/sirsoft-board/src/Http/Requests/UpdatePostRequest.php:64
  • modules/_bundled/sirsoft-board/src/Http/Requests/User/StorePostRequest.php:109
  • modules/_bundled/sirsoft-board/src/Http/Requests/User/UpdatePostRequest.php:74

단일 파일 업로드 요청도 파일 크기와 확장자만 검증하며 누적 개수는 확인하지 않습니다.

  • modules/_bundled/sirsoft-board/src/Http/Requests/UploadAttachmentRequest.php:42

서비스는 전달받은 ID 또는 같은 temp_key의 첨부를 개수 확인 없이 연결합니다.

  • modules/_bundled/sirsoft-board/src/Services/PostService.php:830
  • modules/_bundled/sirsoft-board/src/Services/PostService.php:844
  • modules/_bundled/sirsoft-board/src/Services/AttachmentService.php:184

따라서 UI의 FileUploader 제한을 우회한 API 요청에서는 게시판별 최대 첨부 개수가 서버의 최종 불변조건으로 보장되지 않습니다.

M-01. 자동 숨김 비활성 값이 UI와 백엔드에서 다름

백엔드 검증은 auto_hide_threshold0~100을 허용합니다.

  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:178

서비스와 테스트는 0을 자동 숨김 비활성 값으로 명시합니다.

  • modules/_bundled/sirsoft-board/src/Services/ReportService.php:732
  • modules/_bundled/sirsoft-board/tests/Feature/Admin/AutoHideTest.php:184

그러나 관리자 JSON UI는 최소값을 1로 고정합니다.

"min": 1,
"max": 100
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_report_policy.json:81

결과적으로 지원되는 비활성 설정을 관리자 화면에서 정상적으로 입력할 수 없습니다.

M-02. 답변 깊이 계약이 코드와 문서에서 10과 5로 분리됨

현재 검증 상한은 config 기준 10이며, 관련 회귀 테스트도 10을 기대합니다.

  • modules/_bundled/sirsoft-board/config/board.php:148
  • modules/_bundled/sirsoft-board/tests/Feature/Admin/BoardSettingsControllerTest.php:427
  • modules/_bundled/sirsoft-board/tests/Playwright/specs/admin/board-settings-range-hints.spec.ts:48

하지만 다음 원본 자료는 여전히 1~5로 안내합니다.

  • modules/_bundled/sirsoft-board/database/migrations/2026_04_01_000002_create_boards_table.php:32
  • modules/_bundled/sirsoft-board/resources/lang/partial/ko/admin.json:905
  • modules/_bundled/sirsoft-board/resources/lang/partial/ko/admin.json:977
  • modules/_bundled/sirsoft-board/resources/lang/partial/en/admin.json:977
  • modules/_bundled/sirsoft-board/docs/api/boards.md:60

API 문서 안에서도 요청 검증 상한과 응답 필드 설명이 서로 다를 수 있어 외부 클라이언트가 어느 값을 계약으로 따라야 하는지 불명확합니다.

M-03. 중앙 목록에 없는 운영 정책값이 백엔드와 JSON UI에 반복됨

new_display_hours, 신고 정책, 스팸 제한값은 운영자가 변경하는 설정이지만 config('sirsoft-board.limits')에 포함되지 않습니다. 같은 숫자가 FormRequest와 JSON UI에 각각 반복됩니다.

대표 사례:

설정 백엔드 JSON UI
신규 표시 시간 1~720 1~720
일일 신고 제한 0~100 0~100
신고 거절 횟수 0~50 0~50
신고 거절 기간 1~365 1~365
글·댓글·신고 쿨다운 0~3600 0~3600
조회수 캐시 TTL 60~604800 60~604800

근거:

  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:168
  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:178
  • modules/_bundled/sirsoft-board/src/Http/Requests/Admin/StoreBoardSettingsRequest.php:211
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_board_settings_post.json:581
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_report_policy.json:223
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_settings/_tab_spam_security.json:73

현재 값이 일치하더라도 어느 한쪽만 수정하면 즉시 계약이 분리됩니다. M-01은 이 구조가 이미 실제 오류로 이어진 사례입니다.

L-01. 표시 상한과 정적 안내 문구도 정책 숫자를 직접 보유함

댓글과 답변글 들여쓰기는 화면에서 깊이를 10으로 직접 제한합니다.

  • templates/_bundled/sirsoft-basic/layouts/partials/board/show/_comment_item.json:11
  • templates/_bundled/sirsoft-basic/layouts/partials/board/types/basic/index.json:281
  • modules/_bundled/sirsoft-board/resources/layouts/admin/partials/admin_board_post_detail/_comments.json:72

현재 서버 상한과는 일치하지만 상한을 변경하면 데이터 깊이와 화면 표현이 분리됩니다. 표시 상한이 의도된 별도 UX 정책이라면 이름 있는 설정으로 분리해야 합니다.

또한 현재 레이아웃 사용처는 확인되지 않았지만 다국어 리소스에는 여전히 최대 5개, 10MB 문구가 남아 있습니다.

  • modules/_bundled/sirsoft-board/resources/lang/partial/ko/admin.json:723
  • modules/_bundled/sirsoft-board/resources/lang/partial/en/admin.json:722

사용되지 않는 문구라도 다시 참조되면 게시판별 설정과 다른 안내가 노출될 수 있으므로 제거하거나 동적 치환 방식으로 통일해야 합니다.

원인

근본 원인은 config/board.php가 제한값의 단일 진실 원천처럼 사용되지만 실제 적용 범위가 일부 설정에 한정된 점입니다.

  1. 같은 정책이 config, FormRequest, 서비스, JSON UI, 번역, 문서에 분산되어 있습니다.
  2. 기본값, 허용 범위, 실제 저장 불변조건이 별도 계층에서 관리됩니다.
  3. 경계값 테스트가 게시판 생성·수정 API 일부에 집중되어 관리자 기본설정 API와 비동기 첨부 경로를 함께 비교하지 않습니다.
  4. 문서와 번역이 실행 코드의 정책 메타데이터에서 생성되지 않습니다.

개선안

  1. 모든 운영 정책의 최소·최대값을 sirsoft-board.limits 또는 전용 BoardPolicyLimits 값 객체 한 곳으로 이동합니다.
  2. 게시판 생성, 수정, 관리자 기본설정 FormRequest가 동일한 Rule 생성기를 사용하도록 통합합니다.
  3. 댓글 깊이는 숫자 5를 제거하고 검증을 통과한 parent.depth + 1을 그대로 저장합니다.
  4. 첨부 개수는 UI가 아니라 서버에서 최종 불변조건으로 강제합니다. 직접 파일, attachment_ids, temp_key, 기존 첨부와 신규 첨부의 합계를 모두 포함해야 합니다.
  5. 관리자 API가 모든 제한값을 _meta.limits로 제공하고 JSON UI는 메타데이터 로드 전 입력을 비활성화합니다.
  6. 번역 문구의 숫자는 {{min}}, {{max}} 치환값으로 처리하고 API 문서는 동일 스키마에서 생성합니다.
  7. 중앙 설정값과 각 FormRequest 경계값을 자동 대조하는 계약 테스트를 추가합니다.

완료 조건

  • 중앙 제한값 한 곳을 변경하면 게시판 생성·수정, 관리자 기본설정, JSON UI, API 문서가 함께 변경됩니다.
  • max_comment_depth0, 5, 10 경계에서 검증값과 실제 저장 depth가 일치합니다.
  • 첨부 개수 N은 허용되고 N+1은 직접 파일, ID 연결, temp 연결 모든 경로에서 422 또는 도메인 예외로 차단됩니다.
  • 최소 제목·댓글 길이 0과 자동 숨김 기준 0이 UI와 API에서 동일하게 처리됩니다.
  • 설정 가능한 정책 숫자가 서비스와 JSON UI에 이름 없는 리터럴로 남지 않습니다.

관련 보고서

  • docs/bug-reports/sirsoft-board-comment-reply-integrity-issues-2026-07-17.md

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions