
21세가 혼자 만든 일본 주식 AI 분석 서비스의 기술 스택과 공개 직전에 저지른 IDOR 취약성 이야기
요약
21세 대학생 개발자가 구축한 일본 주식 AI 분석 서비스의 기술 스택과 보안 취약점 해결 과정을 다룹니다. Groq를 활용한 빠른 AI 응답 구현과 서비스 공개 직전 발견한 IDOR 취약점 및 보안 대책을 상세히 공유합니다.
핵심 포인트
- Groq의 Llama 3.3 70B를 활용해 초고속 AI 분석 구현
- Rate Limit 대응을 위한 모델 폴백(Fallback) 전략 적용
- 클라이언트 측 userId 신뢰로 인한 IDOR 취약점 사례 및 해결
- Supabase RLS 무시 문제와 서버 측 인증 기반 보안 강화
서론
21세 대학생입니다.
일본 주식을 25개의 데이터 소스에서 AI가 횡단 분석하는 **「주식 AI 분석」**을 혼자서 만들어, 얼마 전 공개했습니다.
무료·등록 불필요·종목 코드 입력만 하면 됩니다.
이 기사는:
- 전체 기술 스택 및 월간 비용
- 공개 직전에 저지른 IDOR 취약성 이야기
- 실패담
을 작성합니다. 개인 개발로 Web 서비스를 만드는 분들에게 참고가 되길 바랍니다.
무엇을 만들었는가
「종목 코드 하나로 전부 알 수 있다」가 컨셉입니다.
7203
(도요타)를 입력하면, 약 20초 만에:
- 주가 차트·재무 지표
- AI에 의한 단기/중기/장기 예측 (신뢰도 포함)
- 16개 매체의 뉴스 횡단 요약
- Reddit / X / Hacker News의 SNS Buzz
- 매크로 환경 (Nikkei · USDJPY · S&P500 · VIX)
TDnet 적시공시 PDF의 AI 요약·Q&A
가 전부 나옵니다.
그 외에도 포트폴리오 AI 진단, 가격 알림, 투자 저널, AI 예측의 정답 공개, 아침 메일 발송 등을 구현했습니다.
기술 스택 (월간 ¥0~500)
| 영역 | 채택 | 월간 |
|---|---|---|
| Framework | Next.js 16 (App Router) | - |
| ... | ... | ... |
Groq가 압도적으로 빠릅니다. Llama 3.3 70B가 약 300 tokens/sec로 응답합니다. OpenAI gpt-4o-mini보다 체감상 3배 빠릅니다. 무료 할당량이 하루 14,400req나 있어서 개인 개발 수준에서는 초과하지 않습니다.
메인을 70B, 폴백(Fallback)을 8B로 설정하여, Rate Limit(속도 제한)에 걸리더라도 서비스가 중단되지 않도록 했습니다:
const models = ["llama-3.3-70b-versatile", "llama-3.1-8b-instant"];
for (const model of models) {
try {
...
공개 직전에 저지른 IDOR 취약성
공개 준비 중에 치명적인 취약성을 발견했습니다.
문제의 코드
// Before
export async function GET(req: NextRequest) {
const userId = req.nextUrl.searchParams.get("userId");
...
이것은 **IDOR (Insecure Direct Object Reference, 부적절한 직접 객체 참조)**의 전형적인 사례입니다.
?userId=타인의UUID
를 보내면 타인의 워치리스트·포트폴리오·투자 저널을 전부 볼 수 있습니다.
Supabase의 RLS(Row Level Security)를 활성화해 두었지만, Service Role Key로 호출하고 있었기 때문에 RLS가 무시되었습니다. 완전히 막막한 상황이었습니다.
대책
클라이언트로부터 전달된 userId를 신뢰하지 않고, 서버 측에서 Cookie를 통해 인증된 사용자를 가져오는 헬퍼(Helper)를 만들어 모든 API에 적용했습니다:
export async function resolveUserId(clientId?: string | null): Promise<string | null> {
const supa = await createSupabaseServer();
const { data: { user } } = await supa.auth.getUser();
...
덤으로 OWASP Top 10을 전부 점검했다
그랬더니 줄줄이 나오더군요:
| 종류 | 내용 |
|---|---|
| IDOR | userId를 신뢰하고 있었음 (13곳) |
| ... | /api/disclosures/summary가 임의의 PDF URL을 fetch (AWS 메타데이터 호출 가능) |
| Open Redirect | /auth/callback?next=//evil.com으로 외부로 리다이렉트 가능 |
| 인증 바이패스 (Authentication Bypass) | ADMIN_PASSWORD를 ===로 비교 (Timing Attack 위험) |
| Service Role Key 유출 | lib/supabase.ts를 클라이언트에서 import 하면 JS 번들에 포함됨 |
| Rate Limit 없음 | Groq API를 무한 호출 가능 (Cost DoS 위험) |
| Stripe Webhook 멱등성(Idempotency) 없음 | 리플레이 공격 시 결제 상태 불일치 |
이 모든 것을 X(구 Twitter) 공지 전 3시간 만에 해결했습니다.
특히 유용했던 팁
Service Role Key 유출 방지 — import "server-only" 한 줄:
import "server-only"; // 클라이언트에서 import 하면 빌드가 실패함
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(url, SERVICE_ROLE_KEY, ...);
JS 번들(Bundle)에 키가 혼입되는 사고를 물리적으로 방지할 수 있습니다.
SSRF: URL Allowlist + redirect: "error" 로 외부 fetch를 허용된 호스트로 고정하고, 리다이렉트(Redirect)를 통해 다른 호스트로 튕겨 나가는 경로도 차단합니다.
CSRF: Origin 헤더 검증 을 모든 상태 변경 라우트(State-changing route)의 최상단에서 호출하는 것만으로도 방지할 수 있습니다. 토큰 방식보다 압도적으로 간편합니다.
공개 전에 OWASP Top 10을 한 번 검토할 것을 강력히 권장합니다. 하루를 통째로 날리더라도 향후의 안심과 맞바꾼다면 저렴한 비용입니다.
실패담 · 빠지기 쉬운 함정
1. Apple Mail이 OTP 링크를 사전 소비함
Supabase의 Magic Link OTP를 사용하고 있었다면, Apple Mail Privacy Protection이 링크를 **사전에 프리페치(Prefetch)**하여 토큰을 소비해 버립니다.
사용자가 클릭하기도 전에 토큰이 사라져 인증에 실패합니다.
→ **숫자 코드 (6~10자리)**로 변경하고 Supabase 대시보드에서 이메일 템플릿을 수정하여 해결했습니다.
2. Stripe의 Price ID와 Product ID
Stripe에서 "Pro" 상품을 만들고 prod_XXX를 복사해서 붙여넣었더니, Checkout이 No such price: 'prod_XXX'라며 실패했습니다.
상품(prod_)이 아니라 가격(price_) ID를 사용해야 했습니다. 상품 페이지 하단의 "요금" 섹션에 price_XXX가 있습니다. 사소하지만 반드시 누군가는 겪게 되는 함정입니다.
3. EDINET API 신청은 개인에게 사실상 불가능
금융청의 EDINET API는 법인 정보가 필요하여 개인에게는 불가능한 게임입니다.
→ **Yahoo Finance JP의 TDnet 페이지를 HTML 스크레이핑(Scraping)**하는 방식으로 전환했습니다. pdf-parse로 본문을 추출한 뒤 Groq로 요약합니다. 이로써 EDINET 신청 없이도 적시 공시(Timely Disclosure) 정보를 모두 가져올 수 있습니다.
앞으로
- Free: 1일 10회 / 관심 목록 20개 / IR 요약 3회
- Pro (¥500/월): 전부 무제한 + 매일 아침 이메일 발송
50명이 결제해 주면 운영비를 회수할 수 있는 라인입니다.
사용자 0명부터 시작하여, 매출도 0부터 기록하겠습니다.
마치며
21세 대학생이라도 Groq의 고속 추론과 Supabase의 Auth + RLS 덕분에 이 정도까지 만들 수 있는 시대가 되었습니다.
직접 사용해 보시고 소감이나 버그 제보를 주시면 감사하겠습니다.
🔗 프로덕트: https://jp-stock-analyzer.onrender.com
🔗 X: https://x.com/tomato112924 (진척 상황, 매출, 실패를 모두 공개하겠습니다)
※ 투자 조언이 아닌 정보 제공 도구입니다. 투자 판단은 자기 책임하에 진행해 주시기 바랍니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기