이 코드는 다음과 같은 이유로 제대로 작동합니다.
- 매개 변수화 및
- 동적 SQL을 수행 하지 않음
SQL 인젝션이 작동하려면 쿼리 문자열을 작성하고 (하지 않는) 단일 아포스트로피 ( )를 이스케이프 된 아포스트로피 ( )로 변환 하지 않아야 합니다 (입력 매개 변수를 통해 이스케이프 된 것).'
''
"손상된"값을 전달하려는 경우 'Male; DROP TABLE tblActor'
문자열은 단순한 일반 문자열입니다.
이제, 당신이 다음 라인을 따라 무언가를하고 있다면 :
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT fields FROM table WHERE field23 = '
+ @InputParam;
EXEC(@SQL);
그런 다음 그 때문에 SQL 인젝션에 취약 것 그 쿼리는 현재, 사전 구문 분석 된 상황에서되지 않습니다; 해당 쿼리는 현재 다른 문자열입니다. 따라서 해당 쿼리는 다음과 같이 렌더링되고 실행되므로 문제 @InputParam
가 될 수 있고 발생할 수 있습니다 '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
.
SELECT fields FROM table WHERE field23 = '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
이것이 Stored Procedures를 사용하는 주요 이유 중 하나입니다. 본질적으로 더 안전합니다 (사용 된 매개 변수의 값을 확인하지 않고 위에서 보여준 것과 같이 쿼리를 작성하여 보안을 우회하지 않는 한). 동적 SQL을 빌드해야하는 경우 선호되는 방법은 다음을 사용하여 매개 변수화하는 것입니다 sp_executesql
.
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT fields FROM table WHERE field23 = @SomeDate_tmp';
EXEC sp_executesql
@SQL,
N'SomeDate_tmp DATETIME',
@SomeDate_tmp = @InputParam;
시도 누군가에 전달하려면이 방법을 사용하여 '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
A의 DATETIME
저장 프로 시저를 실행할 때 입력 매개 변수하면 오류를 얻을 것입니다. 또는 저장 프로 시저가 접수 되더라도 @InputParameter
로 NVARCHAR(100)
, 그것은로 변환하는 것 DATETIME
그에 통과하기 위해 sp_executesql
호출. 그리고 동적 SQL의 매개 변수가 문자열 유형 인 경우에도 처음에 스토어드 프로 시저로 들어가면 단일 아포스트로피가 자동으로 이중 아포스트로피로 이스케이프됩니다.
공격자가 입력 필드를 아포스트로피로 채우려 고 시도하는 덜 알려진 유형의 공격이 있습니다. 예를 들어 저장 프로 시저 내부의 문자열이 동적 SQL을 구성하는 데 사용되지만 너무 작게 선언 된 문자열은 모든 것에 맞지 않을 수 있습니다 결말 아포스트로피를 밀어 내고 어떻게 든 문자열 내에서 더 이상 "탈출"되지 않도록 올바른 수의 아포스트로피로 끝납니다. 이를 SQL 잘림이라고하며 Bala Neerumalla의 "New SQL 잘림 공격 및 방지 방법"이라는 MSDN 잡지 기사에서 다루었지만 더 이상 온라인 기사는 아닙니다. MSDN Magazine 2006 년 11 월호이 기사가 포함 된 문제 는 Windows 도움말 파일로만 제공됩니다. .chm체재). 다운로드하면 기본 보안 설정으로 인해 열리지 않을 수 있습니다. 이 경우 MSDNMagazineNovember2006en-us.chm 파일 을 마우스 오른쪽 단추로 클릭 하고 "속성"을 선택하십시오. 이러한 탭 중 하나에는 "이 유형의 파일 신뢰"(또는 이와 유사한 것)에 대한 옵션이 있으며이를 확인 / 활성화해야합니다. "확인"버튼을 클릭 한 다음 .chm 파일을 다시 열어보십시오 .
잘림 공격의 또 다른 변형은 로컬 변수를 사용하여 이스케이프하기 위해 작은 따옴표를 두 배로 늘려서 "안전한"사용자 제공 값을 저장하는 데 사용되는 경우 해당 로컬 변수를 채우고 작은 따옴표를 배치하는 것입니다 끝에. 여기서 로컬 변수의 크기가 적절하지 않으면 두 번째 작은 따옴표의 끝에 충분한 공간이 없으며 변수를 작은 따옴표로 끝내고 작은 따옴표와 결합합니다 는 동적 SQL에서 리터럴 값을 종료하고 종료되는 작은 따옴표를 포함 된 이스케이프 된 작은 따옴표로 바꾸고 Dynamic SQL의 문자열 리터럴은 다음 문자열 리터럴을 시작하려는 다음 작은 따옴표로 끝납니다. 예를 들면 다음과 같습니다.
-- Parameters:
DECLARE @UserID INT = 37,
@NewPassword NVARCHAR(15) = N'Any Value ....''',
@OldPassword NVARCHAR(15) = N';Injected SQL--';
-- Stored Proc:
DECLARE @SQL NVARCHAR(MAX),
@NewPassword_fixed NVARCHAR(15) = REPLACE(@NewPassword, N'''', N''''''),
@OldPassword_fixed NVARCHAR(15) = REPLACE(@OldPassword, N'''', N'''''');
SELECT @NewPassword AS [@NewPassword],
REPLACE(@NewPassword, N'''', N'''''') AS [REPLACE output],
@NewPassword_fixed AS [@NewPassword_fixed];
/*
@NewPassword REPLACE output @NewPassword_fixed
Any Value ....' Any Value ....'' Any Value ....'
*/
SELECT @OldPassword AS [@OldPassword],
REPLACE(@OldPassword, N'''', N'''''') AS [REPLACE output],
@OldPassword_fixed AS [@OldPassword_fixed];
/*
@OldPassword REPLACE output @OldPassword_fixed
;Injected SQL-- ;Injected SQL-- ;Injected SQL--
*/
SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
+ @NewPassword_fixed + N''' WHERE [TableNameID] = '
+ CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
+ @OldPassword_fixed + N''';';
SELECT @SQL AS [Injected];
실행할 동적 SQL은 다음과 같습니다.
UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
보다 읽기 쉬운 형식의 동일한 Dynamic SQL은 다음과 같습니다.
UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';
Injected SQL--';
이것을 고치는 것은 쉽다. 다음 중 하나를 수행하십시오.
- 절대적으로 필요한 경우를 제외하고 동적 SQL을 사용하지 마십시오 ! (나는 이것이 가장 먼저 고려해야하기 때문에 이것을 먼저 나열하고 있습니다).
- 전달 된 모든 문자가 작은 따옴표 인 경우를 위해 로컬 변수의 크기를 적절하게 조정하십시오 (즉, 입력 매개 변수 크기의 두 배 여야합니다).
"고정 된"값을 저장하기 위해 로컬 변수를 사용하지 마십시오. REPLACE()
동적 SQL을 작성 하는 데 직접 넣으십시오 .
SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
+ REPLACE(@NewPassword, N'''', N'''''') + N''' WHERE [TableNameID] = '
+ CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
+ REPLACE(@OldPassword, N'''', N'''''') + N''';';
SELECT @SQL AS [No SQL Injection here];
동적 SQL은 더 이상 손상되지 않습니다.
UPDATE dbo.TableName SET [Password] = N'Any Value ....''' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
위의 잘림 예제에 대한 참고 사항 :
- 예, 이것은 매우 고안된 예입니다. 15 자만 입력하면 할 수있는 일이 많지 않습니다. 물론
DELETE tableName
파괴적 일 수 있지만 백도어 사용자를 추가하거나 관리자 암호를 변경할 가능성은 적습니다.
- 이 유형의 공격은 아마도 코드, 테이블 이름 등에 대한 지식이 필요할 것입니다 . 임의의 낯선 사람 / 스크립트 -kiddie에 의해 수행 될 가능성은 적지 만, 취약점을 알고있는 다소 화가 난 전직 직원에 의해 공격을받는 곳에서 일했습니다. 아무도 알지 못하는 특정 웹 페이지에서 즉, 공격자는 때때로 시스템에 대한 친밀한 지식을 가지고 있습니다.
- 물론, 모든 사람의 암호를 재설정 하는 것이 조사 될 가능성이 있으며, 이로 인해 공격이 발생했다는 사실을 회사에 알릴 수 있지만 여전히 백도어 사용자를 주입하거나 나중에 사용 / 탐색 할 보조 정보를 얻을 수있는 충분한 시간을 제공 할 수 있습니다.
- 이 시나리오가 대부분 학문적이지만 (실제 세계에서는 일어날 가능성이없는 경우에도) 여전히 불가능하지는 않습니다.
SQL 주입과 관련된 자세한 정보 (다양한 RDBMS 및 시나리오 포함)는 OWASP ( Open Web Application Security Project) 에서 다음을 참조하십시오.
SQL 주입 테스트
SQL 주입 및 SQL 잘림에 대한 관련 스택 오버플로 응답 :
'이스케이프 문자를 교체 한 후 T-SQL은 얼마나 안전합니까?
EXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'