설명
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 인젝션이 차단됩니다.