SQL 인젝션 (SQL Injection)

SQL Injection

설명

SQL 인젝션은 개발자가 사용자 입력값을 직접 SQL 쿼리문에 연결하여 사용할 때 발생하는 취약점입니다. 이런 방식으로 쿼리를 작성하면, 공격자가 의도하지 않은 SQL 구문을 삽입해서 데이터베이스에 비정상적인 명령을 실행할 수 있습니다. 예를 들어, 인증 우회, 데이터 탈취, 데이터 삭제 등이 발생할 수 있습니다.

잠재적 영향

  • 인증 우회 (Authentication Bypass): 악의적인 입력을 통해 인증 로직을 우회할 수 있습니다.
  • 데이터 유출 (데이터 노출): 비인가자가 민감한 정보를 열람할 수 있습니다.
  • 데이터 변조/삭제 (데이터 변조 및 삭제): 공격자가 데이터베이스에 삽입, 수정, 삭제와 같은 명령을 내릴 수 있습니다.

해결 방법

  • 파라미터화된 쿼리(Parameter Query) 사용: 사용자 입력값을 직접 쿼리에 연결하지 말고, 항상 파라미터 바인딩 기능을 사용하세요.
  • 입력값 검증(Input Validation): 숫자, 이메일 등 예상되는 데이터 타입만 허용하세요.
  • 쿼리 빌더나 ORM에서도 값을 바인딩하는 API를 사용하세요. 테이블·열 이름처럼 값 파라미터로 바인딩할 수 없는 부분은 고정된 허용 목록에서 선택하세요.

예시

연결과 쿼리 부분만 발췌했습니다. CommonJS에서 이 코드는 비동기 함수 안에 두고, 오류 처리와 연결 정리를 추가하세요.

변경 전

javascript
const { Client } = require('pg')
const client = new Client()
await client.connect()
let query = 'SELECT * FROM users WHERE id = ' + userInput;
const res = await client.query(query);
await client.end();

변경 후

javascript
const { Client } = require('pg')
const client = new Client()
await client.connect()
const res = await client.query('SELECT * FROM users WHERE id = $1', [userInput]);
await client.end();

설명:

  • 변경 전: 위 예제는 사용자 입력값(userInput)을 직접 쿼리문에 연결하여 사용합니다. 이 경우, 공격자가 SQL 구문을 삽입하는 것이 가능해지기 때문에 SQL 인젝션 공격에 노출됩니다.
  • 변경 후: 파라미터화된 쿼리를 사용해 'userInput'을 바인딩하면, 입력값이 SQL 구문으로 해석되지 않고 값으로 처리됩니다. 이 방식은 SQL 인젝션 공격을 효과적으로 방지할 수 있습니다.

참조