1. 구조
sp_executesql 문법
|
1 2 3 4 5 6 7 8 |
EXEC sp_executesql @statement, @params, @param1=value1, @param2=value2, ... |
2. EXEC(@sql) 와 차이
위험한 방법
|
1 2 3 4 5 6 7 8 |
SET @sql = 'SELECT * FROM MYDATA WHERE Address=''' + @Address + '''' EXEC(@sql) |
만약
|
1 2 3 4 |
@Address = 'ABC123'' OR 1=1 --' |
이면
|
1 2 3 4 5 |
SELECT * FROM MYDATA WHERE ddress='ABC123' OR 1=1 -- |
가 되어 SQL Injection 공격이 가능합니다.
안전한 방법
|
1 2 3 4 5 6 |
EXEC sp_executesql @sql, N'@Address varchar(6)', @Address=@Address |
파라미터가 값으로 처리되므로
|
1 2 3 |
OR 1=1 |
같은 문자열도 단순 데이터로 취급됩니다.
|
1 2 3 |
EXEC(@sql) |
반면
|
1 2 3 |
sp_executesql |
은 실행 계획(Execution Plan)을 재사용할 수 있습니다.
1. 왜 EXEC(@SQL)은 위험할까?
저장 프로시저가 안전한 이유는 보통 파라미터화된 쿼리(Parameterized Query)를 사용해 입력값을 ‘데이터’로만 취급하기 때문입니다.
하지만 EXEC(@SQL) 처럼 문자열을 더해서 동적 SQL을 만들면, SQL Server는 그 최종 문자열을 처음부터 다시 컴파일합니다. 이때 사용자가 입력한 악의적인 SQL 구문이 데이터가 아닌 실행 가능한 명령어로 변환되면서 보안 구멍이 뚫리게 됩니다.
🚨 취약한 코드 예시
SQL
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CREATE PROCEDURE usp_GetUserInfo @SearchName NVARCHAR(100) AS BEGIN DECLARE @SQL NVARCHAR(MAX); -- 문자열을 단순히 더해서 동적 SQL을 생성 (매우 위험!) SET @SQL = 'SELECT * FROM Users WHERE UserName = ''' + @SearchName + ''''; EXEC(@SQL); END; |
만약 공격수가 @SearchName 입력값으로 admin' OR '1'='1 또는 admin'; DROP TABLE Users; --를 입력한다면, 시스템은 그대로 테이블을 삭제하거나 전체 회원 정보를 노출하게 됩니다.
2. 안전하게 동적 SQL을 작성하는 방법
동적 SQL이 반드시 필요한 상황(예: 검색 조건이 매번 달라지는 동적 검색 쿼리 등)이라면, EXEC(@SQL) 대신 sp_executesql을 사용해야 합니다.
sp_executesql은 동적 SQL 안에서도 파라미터 바인딩을 지원하기 때문에, 사용자가 이상한 값을 입력해도 안전하게 처리합니다.
✅ 안전한 코드 예시 (sp_executesql 사용)
SQL
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
CREATE PROCEDURE usp_GetUserInfo_Safe @SearchName NVARCHAR(100) AS BEGIN DECLARE @SQL NVARCHAR(MAX); DECLARE @ParamList NVARCHAR(500); -- 1. 쿼리 틀을 만들고 변수명(@pName)을 지정합니다. (문자열 더하기 금지) SET @SQL = 'SELECT * FROM Users WHERE UserName = @pName'; -- 2. 동적 SQL 내부에서 사용할 파라미터의 타입을 정의합니다. SET @ParamList = '@pName NVARCHAR(100)'; -- 3. sp_executesql을 통해 파라미터를 안전하게 바인딩하여 실행합니다. EXEC sp_executesql @SQL, @ParamList, @pName = @SearchName; END; |
💡 요약 및 체크리스트
EXEC(@SQL)+ 문자열 더하기 (+): SQL 인젝션에 무방비로 노출됩니다.sp_executesql+ 파라미터 지정: 입력값이 완전히 분리되어 데이터로만 처리되므로 안전합니다.- 테이블 이름이나 컬럼 이름 자체가 동적으로 바뀌어야 해서 어쩔 수 없이 문자열을 더해야 한다면,
QUOTENAME()함수를 사용해 입력값을 강제로 대괄호([])로 감싸 보호해야 합니다.
