FlawOpen

flawopen.com/SQL 인젝션/저장 프로시저

저장 프로시저는 SQL 인젝션을 막나요?

참고 페이지
핵심 답변

아닙니다. 흔한 오해입니다. 저장 프로시저는 내부에서 매개변수를 바인딩할 때만 보호 기능을 제공합니다. 입력을 연결해 쿼리 문자열을 만들고 EXEC 또는 sp_executesql로 실행하면 애플리케이션의 문자열 연결과 같은 위험이 있습니다.

위험 — 값을 동적 SQL에 연결
-- SQL Server T-SQL; dbo.Users.Id is NVARCHAR(50).
CREATE PROCEDURE dbo.GetUser
  @UserId NVARCHAR(50)
AS
BEGIN
  DECLARE @sql NVARCHAR(MAX) =
    N'SELECT Id FROM dbo.Users WHERE Id = N'''
      + @UserId + N'''';
  EXEC(@sql);
END;
안전 — sp_executesql로 매개변수 바인딩
-- SQL Server T-SQL; same illustrative schema.
CREATE PROCEDURE dbo.GetUser
  @UserId NVARCHAR(50)
AS
BEGIN
  DECLARE @sql NVARCHAR(MAX) =
    N'SELECT Id FROM dbo.Users WHERE Id = @id';
  EXEC sys.sp_executesql
    @stmt = @sql,
    @params = N'@id NVARCHAR(50)',
    @id = @UserId;
END;

이 오해가 흔한 이유

“저장 프로시저를 사용하라”는 SQL 인젝션의 만능 해결책처럼 반복됩니다. 일반 쿼리에서 값을 바인딩 매개변수로 전달할 때만 맞는 말입니다. EXEC로 동적 SQL을 만들고 신뢰할 수 없는 값을 연결하면 같은 위험이 다시 생깁니다. 동적 SQL이 필요하면 sp_executesql로 값을 바인딩하세요. 테이블 및 열 이름은 값처럼 바인딩할 수 없으므로 허용된 선택지를 고정 식별자에 매핑하는 엄격한 allowlist를 사용하세요.

자주 묻는 질문

sp_executesql은 안전하게 사용할 수 있나요?

가능합니다. sp_executesql은 매개변수를 지원합니다. 매개변수를 선언하고 값을 별도로 전달하세요(예: EXEC sp_executesql @sql, N'@id INT', @id = @UserId). 값을 @sql에 연결하지 마세요. 동적 테이블명이나 열 이름은 바인딩할 수 없으므로 엄격한 allowlist를 사용하세요.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com TypeORM QueryBuilder는 SQL Injection에 안전한가요? Django ORM SQL Injection: 안전한 패턴 Doctrine ORM SQL 인젝션: 안전한 쿼리 EF Core FromSqlRaw: 안전한 SQL 매개변수화 FastAPI SQL 인젝션: Pydantic이 막는 것과 막지 못하는 것 GORM Raw SQL: Go SQL 인젝션 방지