SQL 인젝션 (SQL Injection)

SQL Injection

설명

SQL 인젝션은 사용자가 입력한 데이터가 쿼리에 직접 삽입될 때 발생하는 취약점입니다. 검증되지 않은 입력이 SQL 쿼리에 포함되면, 공격자는 악의적인 SQL 코드를 삽입하여 데이터베이스에 접근하거나 조작할 수 있습니다. 특히 Node.js의 knex와 같이 동적으로 쿼리를 작성하는 경우, 사용자 입력이 적절히 처리되지 않으면 SQL 인젝션에 취약해질 수 있습니다.

잠재적 영향

  • 데이터 유출 (데이터베이스 정보 노출): 공격자가 민감한 정보나 사용자 데이터를 탈취할 수 있습니다.
  • 데이터 훼손 (무단 수정 및 삭제): 공격자가 데이터베이스의 데이터를 임의로 수정하거나 삭제할 수 있습니다.
  • 인증·인가용 쿼리에 영향을 주면 접근 제어를 우회할 수 있습니다. 전체 피해 범위는 연결 계정의 권한에 따라 달라집니다.

해결 방법

  • 파라미터 바인딩: SQL 문자열에 사용자 입력을 연결하지 말고 값을 별도로 바인딩하세요.
  • 입력값 검증 및 정제: 쿼리에 사용되는 모든 입력값의 타입, 형식과 길이를 검증하세요.
  • 쿼리 빌더 사용: .insert()나 .where()의 값 바인딩 기능을 사용하세요. .raw()가 필요하면 아래처럼 고정 SQL과 바인딩 값을 분리하세요.

예시

변경 전

javascript
app.post('/user', async (req, res) => {
  const result = await knex.raw(
    `INSERT INTO users (name, email) VALUES ('${req.body.name}', '${req.body.email}')`
  );
  res.send('User added');
});

변경 후

javascript
app.post('/user', async (req, res) => {
  const result = await knex.raw(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    [req.body.name, req.body.email]
  );
  res.send('User added');
});

설명:

  • 변경 전: 위 예제는 사용자의 입력값을 직접 SQL 쿼리 문자열에 포함시켜, 공격자가 SQL 문을 조작할 수 있도록 허용합니다. 입력 형식과 길이, 요청자의 쓰기 권한은 바인딩과 별도로 확인해야 합니다.
  • 변경 후: 바인딩 변수(?, ?)를 사용하여 입력값을 별도로 처리하므로, 입력이 SQL 쿼리로 해석되지 않고 단순 데이터로만 전달되어 SQL 인젝션이 차단됩니다.

참조