보안 감사 결과 CRITICAL 2건, HIGH 5건 발견 → 수정 완료 + 자동화 구축. [보안 수정] - issue-view.js: 하드코딩 비밀번호 → crypto.getRandomValues() 랜덤 생성 - pushSubscriptionController.js: ntfy 비밀번호 → process.env.NTFY_SUB_PASSWORD - DEPLOY-GUIDE.md/PROGRESS.md/migration SQL: 평문 비밀번호 → placeholder - docker-compose.yml/.env.example: NTFY_SUB_PASSWORD 환경변수 추가 [보안 강제 시스템 - 신규] - scripts/security-scan.sh: 8개 규칙 (CRITICAL 2, HIGH 4, MEDIUM 2) 3모드(staged/all/diff), severity, .securityignore, MEDIUM 임계값 - .githooks/pre-commit: 로컬 빠른 피드백 - .githooks/pre-receive-server.sh: Gitea 서버 최종 차단 bypass 거버넌스([SECURITY-BYPASS: 사유] + 사용자 제한 + 로그) - SECURITY-CHECKLIST.md: 10개 카테고리 자동/수동 구분 - docs/SECURITY-GUIDE.md: 운영자 가이드 (워크플로우, bypass, FAQ) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
158 lines
4.4 KiB
Markdown
158 lines
4.4 KiB
Markdown
# 보안 시스템 운영 가이드
|
|
|
|
## 개요
|
|
|
|
TK Factory Services에는 2계층 보안 검사 시스템이 적용되어 있습니다.
|
|
|
|
| 계층 | 위치 | 역할 | 우회 가능 |
|
|
|------|------|------|----------|
|
|
| pre-commit | 로컬 (개발자 PC) | 빠른 피드백 | `--no-verify` |
|
|
| pre-receive | Gitea 서버 | 최종 차단 | `[SECURITY-BYPASS: 사유]`만 |
|
|
|
|
## 개발 워크플로우
|
|
|
|
```
|
|
코드 작성 → git add → git commit
|
|
↓
|
|
pre-commit hook
|
|
(security-scan.sh --staged)
|
|
↓
|
|
위반 있으면 → 커밋 차단 + 상세 출력
|
|
위반 없으면 → 커밋 성공
|
|
↓
|
|
git push
|
|
↓
|
|
pre-receive hook (서버)
|
|
(diff 기반 검사)
|
|
↓
|
|
위반 있으면 → push 차단
|
|
위반 없으면 → push 성공
|
|
```
|
|
|
|
## 위반 발생 시 대처
|
|
|
|
### 에러 메시지 읽기
|
|
|
|
```
|
|
[SECURITY] 2 issue(s) found:
|
|
|
|
✗ [CRITICAL] #1 SECRET_HARDCODE — 비밀정보 하드코딩
|
|
→ src/controllers/auth.js:64
|
|
password: 'my-secret-123'
|
|
```
|
|
|
|
- `[CRITICAL]` / `[HIGH]` → 차단됨, 반드시 수정
|
|
- `[MEDIUM]` → 경고, 5개 초과 시 차단
|
|
- `→ 파일:라인번호` → 수정할 위치
|
|
- 아래 줄 → 문제가 된 코드
|
|
|
|
### 수정 방법 (규칙별)
|
|
|
|
| 규칙 | 수정 방법 |
|
|
|------|----------|
|
|
| SECRET_HARDCODE | `process.env.변수명`으로 이동, `.env`에 추가 |
|
|
| LOCALSTORAGE_AUTH | HttpOnly 쿠키 또는 Authorization 헤더 사용 |
|
|
| INNERHTML_XSS | `textContent` 사용 또는 DOMPurify 적용 |
|
|
| CORS_WILDCARD | 허용 도메인을 명시적으로 나열 |
|
|
| SQL_INTERPOLATION | 파라미터화 쿼리(`?` placeholder) 사용 |
|
|
| LOG_SECRET | 로그에서 비밀정보 제거 |
|
|
|
|
## bypass 사용법 (긴급 시)
|
|
|
|
### 형식
|
|
```
|
|
git commit -m "fix: 긴급 장애 대응 [SECURITY-BYPASS: prod 서비스 다운 긴급 핫픽스]"
|
|
```
|
|
|
|
### 규칙
|
|
- **사유 필수**: `[SECURITY-BYPASS]`만으로는 거부됨
|
|
- **허용 사용자만**: 운영담당자(ahn@hyungi.net)만 bypass 가능
|
|
- **24시간 내 수정**: bypass 후 반드시 보안 이슈 수정 PR 제출
|
|
- **로그 기록**: 모든 bypass는 서버에 자동 기록됨
|
|
|
|
### bypass 후 조치
|
|
1. bypass한 코드의 보안 이슈 파악
|
|
2. 24시간 내 수정 커밋
|
|
3. `security-scan.sh --all`로 전체 검증
|
|
|
|
## 규칙 추가/수정 방법
|
|
|
|
### 새 규칙 추가
|
|
`scripts/security-scan.sh`의 RULES 배열에 추가:
|
|
```bash
|
|
'RULE_NAME|SEVERITY|설명|REGEX_PATTERN'
|
|
```
|
|
|
|
예시:
|
|
```bash
|
|
'EVAL_USAGE|HIGH|eval 사용 위험|eval\s*\('
|
|
```
|
|
|
|
### 같은 규칙을 서버에도 반영
|
|
`.githooks/pre-receive-server.sh`의 RULES 배열에도 동일하게 추가.
|
|
Gitea 서버의 hook 파일도 업데이트 필요.
|
|
|
|
## false positive 등록
|
|
|
|
### 파일 단위 제외
|
|
`.securityignore`에 추가 (주석 필수):
|
|
```
|
|
path/to/file.js # 사유 설명 (날짜)
|
|
```
|
|
|
|
### 라인 단위 제외
|
|
소스 코드에 인라인 주석:
|
|
```javascript
|
|
const pattern = /password/; // security-ignore: SECRET_HARDCODE — regex 패턴 정의
|
|
```
|
|
|
|
### 주의
|
|
- 주석 없는 항목은 스캔 시 경고
|
|
- 월 1회 `.securityignore` 검토하여 불필요 항목 제거
|
|
|
|
## 수동 검사
|
|
|
|
### 전체 프로젝트 스캔
|
|
```bash
|
|
./scripts/security-scan.sh --all
|
|
```
|
|
|
|
### 엄격 모드 (MEDIUM도 차단)
|
|
```bash
|
|
./scripts/security-scan.sh --all --strict
|
|
```
|
|
|
|
### 두 커밋 간 비교
|
|
```bash
|
|
./scripts/security-scan.sh --diff HEAD~5 HEAD
|
|
```
|
|
|
|
## 초기 설정 (새 머신)
|
|
|
|
```bash
|
|
# 1. git hooks 경로 설정
|
|
git config core.hooksPath .githooks
|
|
|
|
# 2. 전체 스캔 확인
|
|
./scripts/security-scan.sh --all
|
|
|
|
# 3. 테스트 (선택)
|
|
echo "password: 'test'" >> /tmp/test.js
|
|
git add /tmp/test.js
|
|
git commit -m "test" # → 차단되어야 함
|
|
```
|
|
|
|
## FAQ
|
|
|
|
**Q: pre-commit이 너무 느리다**
|
|
A: staged 파일만 검사하므로 보통 1초 이내. 파일이 많으면 `--no-verify`로 우회 후 push 시 서버에서 검사.
|
|
|
|
**Q: false positive가 계속 뜬다**
|
|
A: `.securityignore`에 등록하거나 라인에 `// security-ignore: RULE_NAME` 추가.
|
|
|
|
**Q: 규칙을 비활성화하고 싶다**
|
|
A: RULES 배열에서 해당 규칙을 주석 처리. 단, CRITICAL 규칙 비활성화는 비권장.
|
|
|
|
**Q: 새 서비스 추가 시**
|
|
A: 추가 설정 불필요. `.securityignore`에 제외할 파일이 있으면 등록.
|