태그 보관물: dynamic-sql

dynamic-sql

저장 프로 시저 내에서이 쿼리에 대해 SQL 주입이 발생하지 않는 이유는 무엇입니까? ActorName FROM

다음 저장 프로 시저를 만들었습니다.

ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender

이제 이런 식으로 시도했습니다. 어쩌면 나는 이것을 잘못하고 있지만 그러한 절차가 SQL 주입을 막을 수 있기를 원합니다.

EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'

아래 이미지는 SSMS에서 위의 SQL이 실행되고 오류 대신 올바르게 표시되는 결과를 보여줍니다.

여기에 이미지 설명을 입력하십시오

Btw, 쿼리 실행이 완료된 후 세미콜론 뒤에 해당 부분을 추가했습니다. 그런 다음 다시 실행했지만 테이블 tblActor의 존재 여부를 확인했을 때 여전히 존재했습니다. 내가 뭔가 잘못하고 있습니까? 아니면 정말 주사 방지인가요? 나는 또한 여기에서 묻고 자하는 것이이 안전과 같은 저장 프로 시저라고 생각합니까? 감사합니다.



답변

이 코드는 다음과 같은 이유로 제대로 작동합니다.

  1. 매개 변수화 및
  2. 동적 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저장 프로 시저를 실행할 때 입력 매개 변수하면 오류를 얻을 것입니다. 또는 저장 프로 시저가 접수 되더라도 @InputParameterNVARCHAR(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--';

이것을 고치는 것은 쉽다. 다음 중 하나를 수행하십시오.

  1. 절대적으로 필요한 경우를 제외하고 동적 SQL을 사용하지 마십시오 ! (나는 이것이 가장 먼저 고려해야하기 때문에 이것을 먼저 나열하고 있습니다).
  2. 전달 된 모든 문자가 작은 따옴표 인 경우를 위해 로컬 변수의 크기를 적절하게 조정하십시오 (즉, 입력 매개 변수 크기의 두 배 여야합니다).
  3. “고정 된”값을 저장하기 위해 로컬 변수를 사용하지 마십시오. 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--';

위의 잘림 예제에 대한 참고 사항 :

  1. 예, 이것은 매우 고안된 예입니다. 15 자만 입력하면 할 수있는 일이 많지 않습니다. 물론 DELETE tableName파괴적 일 수 있지만 백도어 사용자를 추가하거나 관리자 암호를 변경할 가능성은 적습니다.
  2. 이 유형의 공격은 아마도 코드, 테이블 이름 등에 대한 지식이 필요할 것입니다 . 임의의 낯선 사람 / 스크립트 -kiddie에 의해 수행 될 가능성은 적지 만, 취약점을 알고있는 다소 화가 난 전직 직원에 의해 공격을받는 곳에서 일했습니다. 아무도 알지 못하는 특정 웹 페이지에서 즉, 공격자는 때때로 시스템에 대한 친밀한 지식을 가지고 있습니다.
  3. 물론, 모든 사람의 암호를 재설정 하는 것이 조사 될 가능성이 있으며, 이로 인해 공격이 발생했다는 사실을 회사에 알릴 수 있지만 여전히 백도어 사용자를 주입하거나 나중에 사용 / 탐색 할 보조 정보를 얻을 수있는 충분한 시간을 제공 할 수 있습니다.
  4. 이 시나리오가 대부분 학문적이지만 (실제 세계에서는 일어날 가능성이없는 경우에도) 여전히 불가능하지는 않습니다.

SQL 주입과 관련된 자세한 정보 (다양한 RDBMS 및 시나리오 포함)는 OWASP ( Open Web Application Security Project) 에서 다음을 참조하십시오.
SQL 주입 테스트

SQL 주입 및 SQL 잘림에 대한 관련 스택 오버플로 응답 :
‘이스케이프 문자를 교체 한 후 T-SQL은 얼마나 안전합니까?


답변

간단한 문제는 데이터를 명령과 혼동하지 않는다는 것입니다. 매개 변수 값은 명령의 일부로 처리되지 않으므로 실행되지 않습니다.

나는 이것을 http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/ 에서 블로그에 올렸다.


답변