OWASP Top 10·프롬프트 인젝션·패스키
이 장을 읽기 전에: 백엔드(4장)의 기본 개념, 특히 인증·인가를 파악하고 있어야 한다.
보안은 "나중에 강화하는" 것이 아니라, 처음부터 설계에 포함해야 할 품질이다. 공개된 웹 애플리케이션이나 API는 규모에 관계없이 항상 스캔된다. AI 기능을 통합하는 경우에는 기존의 웹 보안에 더하여 프롬프트 인젝션이나 과도한 툴 실행과 같은 새로운 공격면도 증가한다.
� 한국 시장 맥락: 국내에서는 개인정보보호법(PIPA)·정보통신망법·금융보안원 가이드라인 등 별도 법규가 보안 설계에 직접 영향을 미친다. ISMS-P 인증은 연매출 100억 이상 또는 일평균 이용자 100만 이상인 사업자에게 의무화되어 있으며, 이 장의 보안 원칙 대부분이 ISMS-P 통제 항목과 연결된다.
이 섹션이 답하는 질문: 어떤 위협을 우선하여 생각해야 하는가. AI 기능을 넣으면 무엇이 늘어나는가.
취약점의 대부분은 "어려운 암호화의 실패"가 아니라, 인가 누락, 입력값 취급, 설정 실수, 오래된 의존 관계의 방치와 같은 구현 실수에서 생긴다.
OWASP Top 10 for LLM Applications 2025에서는 Prompt Injection이 LLM01로 취급된다.
⚠️ 프롬프트 인젝션은 "완전 방어"보다 "피해를 작게 하는 설계"가 중요하다. LLM을 신뢰 경계의 내측에 두지 않고, 오동작해도 치명적이 되지 않는 구조로 한다.
LLM에 강한 권한을 주지 않는다
고리스크 조작은 인간 승인으로 한다
외부 문서나 검색 결과를 미신뢰 입력으로 취급한다
툴 호출을 명시적인 허가제로 한다
입출력과 툴 실행을 감사 로그에 남긴다
� 국내 AI 서비스 보안: 개인정보가 포함된 입력을 LLM에 전달하는 경우, 글로벌 LLM API(Claude·GPT 등) 사용 시 개인정보 국외 이전 동의가 필요하다. 금융·의료·공공 데이터는 NCP CLOVA Studio 또는 온프레미스 LLM을 우선 검토한다.
먼저 기존의 웹 위협을 확실하게 잡는다. AI 기능을 넣는 경우는 "LLM이 틀려도 부서지지 않는 구조" 를 추가로 설계한다.
이 섹션이 답하는 질문: 인증과 인가를 어떻게 나누어 설계하는가. 패스키는 언제 사용해야 하는가.
침해 사고에서는 "인증 방식 그 자체"보다, 인가 누락이나 세션 관리의 불비가 원인이 되는 경우가 많다.
// 카카오·네이버 OAuth 서버 측 검증 — 클라이언트 토큰을 그대로 신뢰하지 않는다
async function verifyKakaoToken(accessToken: string): Promise<KakaoUser> {
// 클라이언트에서 받은 accessToken을 카카오 서버에서 직접 검증
const response = await fetch('https://kapi.kakao.com/v2/user/me', {
headers: { Authorization: `Bearer ${accessToken}` },
});
if (!response.ok) {
throw new AuthError('카카오 토큰 검증 실패');
}
const kakaoUser = await response.json();
// DB에서 기존 사용자 조회 또는 신규 생성
const user = await db.user.upsert({
where: { kakaoId: String(kakaoUser.id) },
create: {
kakaoId: String(kakaoUser.id),
email: kakaoUser.kakao_account?.email,
name: kakaoUser.properties?.nickname,
},
update: { lastLoginAt: new Date() },
});
return user;
}
패스키는 FIDO2 / WebAuthn을 사용한 인증 방식으로, 패스워드의 대체로 보급되고 있다.
등록된 패스키의 일람
각각의 이름이나 이용 단말의 단서
최종 이용 시각
백업 가능한지, 이미 백업됐는지
개별 삭제 도선
⚠️ 패스키에서는 "1계정에 1인증기"가 아니라, 복수 패스키를 가질 수 있는 설계가 자연스럽다. 1대의 단말에만 의존시키지 않는다.
최소한 다음을 준비한다.
복수 디바이스 또는 복수 인증기의 등록
이메일 확인이나 본인 확인을 동반하는 복구 플로 (국내: 휴대폰 본인인증 연동 권장)
관리 화면에서의 인증기 일람과 무효화 기능
UI에서 버튼을 숨겨도 인가가 되는 것은 아니다 (서버에서 반드시 체크)
API마다 서버 측에서 권한 판정한다
오브젝트 단위의 인가를 수행한다 (IDOR 방지)
관리자 권한은 역할명이 아닌 조작 단위로 재검토한다
// IDOR(Insecure Direct Object Reference) 방지 예시
// ❌ 잘못된 패턴 — 요청의 orderId를 그대로 신뢰
app.get('/orders/:orderId', async (req, res) => {
const order = await db.order.findById(req.params.orderId);
res.json(order);
});
// ✅ 올바른 패턴 — 인증된 사용자의 주문인지 서버에서 확인
app.get('/orders/:orderId', authenticate, async (req, res) => {
const order = await db.order.findFirst({
where: {
id: req.params.orderId,
userId: req.user.id, // 반드시 인증된 사용자의 것인지 확인
},
});
if (!order) {
지금 바로 작가의 멤버십 구독자가 되어
멤버십 특별 연재 콘텐츠를 모두 만나 보세요.
오직 멤버십 구독자만 볼 수 있는,
이 작가의 특별 연재 콘텐츠