Injection 실전 가이드

Injection의 핵심 개념과 실무 활용

TypeScript중급
8시간
4개 항목
학습 진행률0 / 4 (0%)

학습 항목

1. JavaScript
SQL|Injection|방어|완벽|가이드
퀴즈튜토리얼
2. TypeScript
고급
Dependency|Injection|기초부터|심화까지
퀴즈튜토리얼
3. TypeScript
고급
Dependency|Injection|베스트|프랙티스
퀴즈튜토리얼
4. TypeScript
초급
Dependency|Injection|핵심|개념|완벽|정리
퀴즈튜토리얼
1 / 4

이미지 로딩 중...

SQL Injection 방어 완벽 가이드 - 슬라이드 1/13

SQL Injection 방어 완벽 가이드

웹 애플리케이션의 가장 위험한 보안 취약점 중 하나인 SQL Injection을 방어하는 다양한 기법을 학습합니다. Prepared Statement, ORM, 입력 검증 등 실전에서 바로 적용 가능한 방어 기법을 다룹니다.


카테고리:JavaScript
언어:JavaScript
메인 태그:#JavaScript
서브 태그:
#SQLInjection#Security#PreparedStatement#InputValidation

들어가며

이 글에서는 SQL Injection 방어 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. Prepared_Statement_기본
  2. Named_Parameters_사용
  3. ORM을_통한_안전한_쿼리
  4. 입력_검증_화이트리스트
  5. 입력_이스케이프_처리
  6. 저장_프로시저_활용
  7. 최소_권한_원칙_적용
  8. 에러_메시지_숨김
  9. WAF_활용
  10. 입력_타입_검증
  11. 쿼리_빌더_안전_사용
  12. 정기_보안_테스트

1. Prepared_Statement_기본

개요

Prepared Statement는 SQL 쿼리와 데이터를 분리하여 SQL Injection을 근본적으로 차단하는 가장 효과적인 방법입니다.

코드 예제

const mysql = require('mysql2/promise');

async function getUserById(userId) {
  const connection = await mysql.createConnection(config);
  const [rows] = await connection.execute(
    'SELECT * FROM users WHERE id = ?',
    [userId]
  );
  return rows;
}

설명

'?' 플레이스홀더를 사용하여 SQL 쿼리와 사용자 입력을 분리합니다. 데이터베이스 드라이버가 자동으로 입력값을 이스케이프 처리하여 악의적인 SQL 코드 실행을 방지합니다.


2. Named_Parameters_사용

개요

Named Parameter를 사용하면 복잡한 쿼리에서도 가독성을 유지하면서 안전하게 데이터를 바인딩할 수 있습니다.

코드 예제

async function searchUsers(username, email) {
  const [rows] = await connection.execute(
    'SELECT * FROM users WHERE username = :username AND email = :email',
    { username, email }
  );
  return rows;
}

설명

:username, :email과 같은 명명된 파라미터를 사용하여 여러 값을 안전하게 바인딩합니다. 쿼리의 가독성이 높아지고 파라미터 순서 오류를 방지할 수 있습니다.


3. ORM을_통한_안전한_쿼리

개요

Sequelize, TypeORM 같은 ORM을 사용하면 SQL을 직접 작성하지 않고도 안전한 데이터베이스 작업이 가능합니다.

코드 예제

const { Sequelize, DataTypes } = require('sequelize');

const User = sequelize.define('User', {
  username: DataTypes.STRING,
  email: DataTypes.STRING
});

async function findUser(username) {
  return await User.findOne({ where: { username } });
}

설명

ORM은 내부적으로 Prepared Statement를 사용하여 모든 쿼리를 자동으로 파라미터화합니다. 개발자가 SQL Injection을 신경 쓰지 않아도 안전한 코드를 작성할 수 있습니다.


4. 입력_검증_화이트리스트

개요

사용자 입력을 받을 때 허용된 값만 통과시키는 화이트리스트 방식으로 검증하여 공격 벡터를 원천 차단합니다.

코드 예제

function getSortColumn(userInput) {
  const allowedColumns = ['id', 'name', 'created_at'];

  if (!allowedColumns.includes(userInput)) {
    throw new Error('Invalid sort column');
  }
  return userInput;
}

설명

동적 테이블명, 컬럼명, ORDER BY 절 등 Prepared Statement로 처리할 수 없는 경우 화이트리스트로 검증합니다. 허용된 값만 통과시켜 공격 가능성을 완전히 제거합니다.


5. 입력_이스케이프_처리

개요

불가피하게 동적 SQL을 사용해야 할 때는 데이터베이스별 이스케이프 함수를 사용하여 특수문자를 무력화합니다.

코드 예제

const mysql = require('mysql2');

function searchByPattern(pattern) {
  const escaped = mysql.escapeId(pattern);
  const query = `SELECT * FROM ${escaped}`;
  return connection.query(query);
}

설명

mysql.escape()는 값을, mysql.escapeId()는 식별자(테이블명, 컬럼명)를 이스케이프합니다. 하지만 이 방법은 최후의 수단이며, 가능하면 Prepared Statement를 사용해야 합니다.


6. 저장_프로시저_활용

개요

저장 프로시저를 사용하면 SQL 로직을 데이터베이스 내부에 캡슐화하여 애플리케이션 레이어의 SQL Injection 위험을 줄일 수 있습니다.

코드 예제

async function registerUser(username, email) {
  await connection.execute(
    'CALL sp_register_user(?, ?)',
    [username, email]
  );
}

// DB: CREATE PROCEDURE sp_register_user(
//   IN p_username VARCHAR(50), IN p_email VARCHAR(100))

설명

저장 프로시저는 파라미터화된 방식으로 실행되며, 복잡한 비즈니스 로직을 안전하게 처리할 수 있습니다. 애플리케이션 코드에서는 프로시저를 호출만 하면 됩니다.


7. 최소_권한_원칙_적용

개요

데이터베이스 사용자 계정에 필요한 최소한의 권한만 부여하여 SQL Injection 공격의 피해 범위를 제한합니다.

코드 예제

// DB 사용자 권한 설정 예시
// CREATE USER 'app_user'@'localhost'
//   IDENTIFIED BY 'password';
// GRANT SELECT, INSERT, UPDATE ON mydb.users
//   TO 'app_user'@'localhost';

const config = {
  user: 'app_user',  // DROP, ALTER 권한 없음
  password: 'password',
  database: 'mydb'
};

설명

애플리케이션 DB 계정에 DROP, ALTER 등 위험한 권한을 부여하지 않습니다. SQL Injection이 발생해도 데이터 조회/수정만 가능하고 테이블 삭제 등은 불가능하게 만듭니다.


8. 에러_메시지_숨김

개요

데이터베이스 에러 메시지를 사용자에게 노출하지 않아 공격자가 데이터베이스 구조를 파악하지 못하도록 합니다.

코드 예제

async function handleQuery(userId) {
  try {
    const [rows] = await connection.execute(
      'SELECT * FROM users WHERE id = ?', [userId]
    );
    return rows;
  } catch (error) {
    console.error('DB Error:', error);
    throw new Error('Database operation failed');
  }
}

설명

상세한 SQL 에러 메시지는 로그에만 기록하고, 사용자에게는 일반적인 에러 메시지만 반환합니다. 공격자가 테이블명, 컬럼명 등의 정보를 얻지 못하게 합니다.


9. WAF_활용

개요

Web Application Firewall을 사용하여 SQL Injection 패턴을 자동으로 탐지하고 차단하는 추가 보안 계층을 구축합니다.

코드 예제

const helmet = require('helmet');
const expressSanitizer = require('express-sanitizer');

app.use(helmet());
app.use(expressSanitizer());

app.post('/search', (req, res) => {
  const sanitized = req.sanitize(req.body.query);
  // 추가 검증 및 처리
});

설명

미들웨어 레벨에서 위험한 패턴을 필터링합니다. UNION, OR 1=1, DROP TABLE 등의 SQL Injection 시도를 사전에 차단할 수 있습니다.


10. 입력_타입_검증

개요

TypeScript나 스키마 검증 라이브러리를 활용하여 입력 데이터의 타입과 형식을 엄격하게 검증합니다.

코드 예제

const Joi = require('joi');

const userSchema = Joi.object({
  id: Joi.number().integer().positive().required(),
  username: Joi.string().alphanum().min(3).max(30),
  email: Joi.string().email()
});

const { error, value } = userSchema.validate(req.body);

설명

Joi, Zod 같은 스키마 검증 라이브러리로 입력값의 타입, 길이, 형식을 검증합니다. SQL Injection에 사용되는 특수문자나 예상 밖의 입력을 사전에 차단합니다.


11. 쿼리_빌더_안전_사용

개요

Knex.js 같은 쿼리 빌더를 사용하면 동적 쿼리를 안전하게 작성할 수 있으며, 자동으로 파라미터 바인딩이 적용됩니다.

코드 예제

const knex = require('knex')({ client: 'mysql2' });

async function searchUsers(filters) {
  return await knex('users')
    .where('status', filters.status)
    .andWhere('age', '>', filters.minAge)
    .select('*');
}

설명

쿼리 빌더는 메서드 체이닝으로 쿼리를 구성하며, 모든 값은 자동으로 파라미터화됩니다. SQL 문자열을 직접 작성하지 않아 안전성이 높습니다.


12. 정기_보안_테스트

개요

OWASP ZAP, SQLMap 같은 도구로 정기적으로 SQL Injection 취약점을 스캔하여 보안 상태를 점검합니다.

코드 예제

// package.json 스크립트
{
  "scripts": {
    "security:scan": "npm audit && snyk test",
    "pentest:sql": "sqlmap -u 'http://localhost/api' --batch --risk=3"
  }
}

// CI/CD 파이프라인에 통합

설명

자동화된 보안 스캔을 CI/CD 파이프라인에 통합하여 배포 전에 SQL Injection 취약점을 발견합니다. 지속적인 모니터링으로 새로운 취약점을 조기에 탐지할 수 있습니다.


마치며

이번 글에서는 SQL Injection 방어 완벽 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#JavaScript #SQLInjection #Security #PreparedStatement #InputValidation

#JavaScript#SQLInjection#Security#PreparedStatement#InputValidation