Security report · 점검 · 조치

보안점검보고서

2026-08-06 기준 Next.js API·Solana 주문/지갑 표면을 점검하고 Critical·High에 패치를 적용했습니다. 동시~1000명 가정으로 SSE/레이트리밋·호가 WS fan-out을 조정했습니다.

완화 8운영 조치 1갱신 2026-08-06
범위 · manifast-typescript-test (App Router API, Express 레거시 /api/orders, next.config 헤더)
제외 · manifast-platform 모노레포 서비스 분리본, Railway 인프라 WAF, git history 시크릿 purge(운영 작업), Cloudflare 엣지 DDoS

고전 웹 위협

위협판정메모
XSS낮음dangerouslySetInnerHTML·eval 미사용. React 텍스트 이스케이프. Spec 마크다운은 고정 파일
CSRF낮음*쿠키 세션 없음. 실질 이슈는 무인증 API였으며 INTERNAL_API_SECRET으로 잠금
SQL / NoSQL 인젝션해당 없음SQL·Mongo 쿼리 표면 없음. JSON 파일 스토어 + Solana PublicKey 파싱
DDoS / 남용완화IP 레이트리밋·SSE 연결 상한·tx 크기 제한 적용 (인메모리, 단일 인스턴스 기준)
SSRF / 오픈리다이렉트 / 업로드낮음유저 URL fetch·업로드 API 없음

적용한 통제

발견 사항 (11)

s0100POST /api/orders · load-test

무인증 서버 서명 주문 API

WALLET_SECRET_KEY로 누구나 온체인 주문을 넣을 수 있었음.

Critical완화됨

배경

executeOrder → getWallet() 경로. UI Trade(prepare+지갑 서명)와 별개. 공개 Railway URL에서 핫월렛 faucet과 동일.

조치

INTERNAL_API_SECRET + 헤더 x-internal-api-secret 필수. Express 동일. load-test 클라이언트가 시크릿 전달. 프로덕션에서 시크릿 미설정 시 403.

s0200POST /api/orders/load-test

공개 부하테스트 엔드포인트

count만큼 서버 서명 주문을 동시 호출 가능.

Critical완화됨

배경

MAX_CONCURRENT_ORDERS(10)만 있었고 인증 없음.

조치

HTTP load-test 서버 삭제. 부하는 scripts/load-orders.ts + Railway 원샷(공개 라우트 없음).

s0300POST /api/tx/send

tx 공개 릴레이 · skipPreflight

서명된 raw tx를 서버 RPC로 무제한 중계 → RPC 비용 남용.

High완화됨

배경

자금 탈취는 서명 위조 없이는 불가. DDoS·과금 위험.

조치

IP당 분당 한도 · raw 바이트 상한(기본 2048) · 기본 preflight 사용(TX_SEND_SKIP_PREFLIGHT=true로만 이전 동작).

s0400price/fills/open stream

SSE 무제한 연결

장기 연결 + RPC subscribe로 연결·RPC 고갈 가능.

High완화됨

배경

presence·fill watcher가 연결 수에 비례해 부하.

조치

IP당 SSE 120 · 전역 4000(동시~1000×스트림3). tx/send·verify 분당 180(공유 IP 감안). 호가 WS는 마켓당 1구독 fan-out.

s0500POST /api/orders/verify

verify RPC 폴링 남용

요청당 다회 getSignatureStatuses.

Medium완화됨

배경

maxAttempts×interval로 RPC 증폭.

조치

IP 레이트리밋(기본 분당 20).

s0600GET /api/orders/history

서버 지갑 거래 히스토리 공개

서버 지갑 주문 이력·파일 경로 공개 조회.

Medium완화됨

배경

정보 노출.

조치

INTERNAL_API_SECRET 필수.

s0700next.config.ts

보안 헤더 부재

CSP·X-Frame-Options 등 없음.

Medium완화됨

배경

클릭재킹·일부 XSS 완화 헤더 부재.

조치

X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, CSP(Next 호환 완화안) 추가.

s0800운영

git history .env / 키 로테이션

과거 커밋에 .env가 포함됐을 수 있음.

Medium운영 조치

배경

코드 패치로 purge하지 않음. 운영자가 WALLET_SECRET_KEY·RPC 키를 재발급해야 함.

조치

Railway·로컬에서 키 로테이션. 필요 시 git filter/BFG로 히스토리 정리(별도 승인).

s0900스택 전반

XSS · SQL 인젝션 · 고전 CSRF

현재 코드 기준 낮음/해당 없음.

Low수용

배경

사용자 생성 HTML·SQL 표면 없음. 쿠키 세션 없음.

조치

현 상태 유지. 사용자 CMS/markdown raw HTML 도입 시 재검토.

s1100subscribeMarketPrice

호가 SSE마다 Solana accountSubscribe 개별 생성

동시 1000명이면 같은 마켓 WS 구독이 1000개로 늘어 RPC·연결이 먼저 한계에 달함.

High완화됨

배경

price/stream·open/stream이 연결마다 onAccountChange를 열었음. fill watcher는 원래 마켓별 공유.

조치

마켓당 구독 1개 + 리스너 fan-out으로 변경 (marketPrice.ts). 동시 접속 스케일은 SSE 상한·Railway 인스턴스·유료 RPC와 함께 봐야 함.

s1000prepare · cancel/prepare · balance/prepare

Trade prepare 경로 (사용자 서명)

임의 traderAddress로 unsigned tx 생성 가능하나 서명 없으면 이체 불가.

Info수용

배경

피싱(악성 사이트에서 서명 유도)은 UX·도메인 신뢰 문제.

조치

커스텀 도메인·Phantom 도메인 평판. 소유권 증명은 후속 검토.