flawopen.com/SQL 인젝션/Javascript

SQL 인젝션 in Javascript

심각 CWE-89 Draft — pending review
Language: English Português (Brasil) Español Français Deutsch Русский 简体中文 日本語 हिन्दी 한국어 Bahasa Indonesia
쉬운 설명 (ELI5)

티켓 번호만 입력해야 하는 창구에 데이터베이스를 조작하는 명령어를 입력하여 전체 회원 정보를 빼내는 공격입니다.

이 페이지의 주요 용어
템플릿 리터럴
백틱(`...`)으로 변수를 삽입하는 문법. SQL 생성 시 문자열 연결 취약점과 동일하게 동작합니다.

발생 원인

사용자 입력값이 쿼리 텍스트에 직접 결합될 때 발생하며, Node.js에서는 템플릿 리터럴로 인한 실수가 가장 빈번합니다.

실제 피해 사례

2015년 영국의 통신사 TalkTalk는 레거시 SQL 인젝션 취약점으로 15만 명의 개인정보가 유출되어 40만 파운드의 벌금을 부과받았습니다.

출처: 영국 정보위원회(ICO) 조사 결과, 2016년.

취약한 코드 vs 수정된 코드

VULNERABLE
// userId comes straight from request query
async function getUser(pool, userId) {
  const query = `SELECT * FROM users
    WHERE id = ${userId}`;
  const [rows] = await pool.query(query);
  return rows[0];
}
FIXED
// value is passed separately, never inlined
async function getUser(pool, userId) {
  const [rows] = await pool.query(
    'SELECT * FROM users WHERE id = ?',
    [userId]
  );
  return rows[0];
}

수정 방법이 동작하는 이유

매개변수화 쿼리는 DB 드라이버가 쿼리 구조를 먼저 확정한 후 값을 별도로 바인딩하여 안전합니다.

언어별 주요 주의사항

드라이버별 플레이스홀더 문법 차이

mysql2는 ?를 사용하고, pg(PostgreSQL)는 $1, $2를 사용합니다.

흔한 오해

"TypeScript를 쓰면 안전하다"

타입 검사는 컴파일 시점에만 작동하며 런타임의 문자열 결합 공격은 막지 못합니다.

취약점 확인 방법

grep -rn "query(\`.*\${" --include="*.js" --include="*.ts" . npx eslint --rule 'no-template-curly-in-string: error' .
Run Semgrep with p/javascript ruleset in CI to catch unparameterized database queries automatically.

예방 체크리스트

자주 묻는 질문 (FAQ)

ORM을 쓰면 항상 안전한가요?

기본 쿼리 빌더는 안전하지만, raw 쿼리 사용 시에는 반드시 바인딩 매개변수를 써야 합니다.

참고 자료

참고할 취약점: Cross-Site Scripting Command InjectionPath Traversal