작은따옴표를 이스케이프 처리하고 사용자 입력을 작은따옴표로 묶어 SQL 주입으로부터 보호할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/139199

문제

사용자 입력이 포함된 쿼리를 작성할 때 매개 변수화된 SQL 쿼리가 사용자 입력을 삭제하는 최적의 방법이라는 것을 알고 있지만 사용자 입력을 가져와 작은따옴표를 이스케이프하고 전체 문자열을 작은따옴표로 묶는 데 무엇이 문제인지 궁금합니다.코드는 다음과 같습니다.

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

사용자가 입력하는 모든 작은 따옴표는 이중 작은 따옴표로 대체되어 사용자가 문자열을 끝낼 수 없게 되므로 세미콜론, 퍼센트 기호 등과 같이 사용자가 입력할 수 있는 모든 항목은 모두 문자열의 일부가 되며 문자열의 일부가 됩니다. 실제로 명령의 일부로 실행됩니다.우리는 Microsoft SQL Server 2000을 사용하고 있는데 작은 따옴표가 유일한 문자열 구분 기호이고 문자열 구분 기호를 이스케이프하는 유일한 방법이므로 사용자가 입력하는 내용을 실행할 수 있는 방법이 없습니다.

이에 대해 SQL 주입 공격을 시작할 수 있는 방법은 없지만 이것이 나에게 보이는 것처럼 방탄이었다면 다른 사람이 이미 생각했을 것이고 이것이 일반적인 관행이었을 것이라는 점을 깨달았습니다.내 질문은 이것입니다:이 코드에 무슨 문제가 있나요?이 삭제 기술을 넘어서 SQL 주입 공격을 받는 방법을 아는 사람이 있습니까?이 기술을 활용하는 샘플 사용자 입력은 매우 유용합니다.

업데이트:

답변해 주신 모든 분들께 감사드립니다.내가 연구하면서 발견한 거의 모든 정보는 이 페이지 어딘가에 나타났습니다. 이는 바쁜 시간에도 불구하고 이 질문에 답하기 위해 시간을 내어 도움을 준 사람들의 지능과 기술을 보여주는 것입니다.

아직 답변을 수락하지 않은 이유는 이 코드에 대해 SQL 주입 공격을 효과적으로 시작할 수 있는 방법을 아직 모르기 때문입니다.몇몇 사람들은 백슬래시가 하나의 작은따옴표를 이스케이프하고 다른 하나는 문자열을 끝내도록 남겨두어 문자열의 나머지 부분이 SQL 명령의 일부로 실행될 것이라고 제안했습니다. mySQL 데이터베이스이지만 MS SQL 2000에서 작은 따옴표를 이스케이프 처리하는 유일한 방법은 다른 작은 따옴표를 사용하는 것입니다.백 슬래시는 그것을하지 않습니다.그리고 작은따옴표의 이스케이프를 중지할 수 있는 방법이 없으면 사용자 입력의 나머지 부분은 모두 하나의 연속 문자열로 간주되므로 실행되지 않습니다.

입력 내용을 삭제하는 더 좋은 방법이 있다는 것을 이해하지만 위에서 제공한 방법이 왜 작동하지 않는지 알아보는 데 더 관심이 있습니다.이 삭제 방법에 대해 SQL 주입 공격을 수행하는 특정 방법을 아는 사람이 있다면 보고 싶습니다.

도움이 되었습니까?

해결책

우선, 그것은 단지 나쁜 연습입니다. 입력 유효성 검사는 항상 필요하지만 항상 iffy입니다.
더 나쁜 것은, 블랙리스트 검증은 항상 문제가되며, 당신이 받아들이는 값/형식을 명시적이고 엄격하게 정의하는 것이 훨씬 낫습니다. 분명히, 이것은 항상 가능한 것은 아니지만 어느 정도까지는 항상 이루어져야합니다.
주제에 관한 일부 연구 논문 :

포인트, 당신이하는 모든 블랙리스트 (그리고 너무 긴급한 화이트리스트)는 우회 할 수 있다는 것입니다. 내 논문에 대한 마지막 링크는 인용문 탈출조차 우회 할 수있는 상황을 보여줍니다.

이러한 상황이 당신에게 적용되지 않더라도 여전히 나쁜 생각입니다. 또한 앱이 사소하게 작지 않는 한 유지 보수와 일정량의 거버넌스를 처리해야 할 것입니다. 항상 어디서나 올바르게 이루어 지도록 어떻게해야합니까?

적절한 방법 :

  • 화이트리스트 검증 : 유형, 길이, 형식 또는 허용 값
  • 블랙리스트를 원한다면 바로 가십시오. 인용문 탈출은 좋지만 다른 완화의 맥락 내에서.
  • 명령 및 매개 변수 개체를 사용하여 준비하고 검증하십시오.
  • 매개 변수화 쿼리 만 호출합니다.
  • 더 나은 방법은 저장 절차를 독점적으로 사용하십시오.
  • 동적 SQL을 사용하지 말고 문자열 연결을 사용하여 쿼리를 작성하지 마십시오.
  • SPS를 사용하는 경우 데이터베이스의 권한을 필요한 SPS 만 실행하도록 제한하고 테이블에 직접 액세스 할 수 없습니다.
  • 전체 코드베이스가 SPS를 통해 DB에만 액세스하는지 쉽게 확인할 수 있습니다.

다른 팁

좋아,이 응답은 다음과 같은 질문의 업데이트와 관련이 있습니다.

"이 소독 방법에 대한 SQL 주사 공격을 장착하는 특정한 방법을 알고 있다면 나는 그것을보고 싶다."

이제 MySQL Backslash Escaping 외에도 MSSQL에 대해 실제로 이야기하고 있음을 고려하면 실제로 코드를 주입하는 SQL이 실제로 3 가지 가능한 방법이 있습니다.

ssanitizedInput = " '"& Replace (sinput, "'", " ''") & " ''"

이것들이 항상 모두 유효하지는 않으며 그 주변의 실제 코드에 매우 의존한다는 점을 고려하십시오.

  1. 2 차 SQL 주입 - 데이터베이스에서 검색된 데이터를 기반으로 SQL 쿼리가 재건 된 경우 탈출 후, 데이터는 에스코지되지 않은 상태로 연결되어 있으며 간접적으로 SQL 주사 될 수 있습니다. 보다
  2. String Truncation- (좀 더 복잡한) - 시나리오는 사용자 이름과 비밀번호를 말하는 두 개의 필드가 있으며 SQL은 두 분야를 모두 연결합니다. 그리고 두 분야 (또는 첫 번째 필드)는 길이가 단단한 한계가 있습니다. 예를 들어 사용자 이름은 20 자로 제한됩니다. 이 코드가 있다고 가정합니다.
username = left(Replace(sInput, "'", "''"), 20)

그런 다음 당신이 얻는 것은 사용자 이름입니다. 탈출 한 다음 20 자로 다듬습니다. 여기서 문제 - 나는 20 번째 캐릭터 (예 : 19 A 이후)에 내 인용문을 고수하고, 당신의 탈출 인용문은 (21 번째 캐릭터에서) 다듬어 질 것입니다. 그런 다음 SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

앞서 언급 한 오르플 폼 사용자 이름과 결합하면 비밀번호가 이미 밖의 인용문은 페이로드 만 직접 포함합니다.
3. 유니 코드 밀수 - 특정 상황에서는 높은 수준의 유니 코드 문자를 통과 할 수 있습니다. 외모 인용문처럼 그렇지 않습니다 - 갑자기 데이터베이스에 도달 할 때까지 갑자기 그것은이다. 검증 할 때 인용이 아니므로 쉽게 진행할 것입니다 ... 자세한 내용은 이전의 응답을 참조하고 원래 연구에 링크하십시오.

간단히 말해서 : 절대 쿼리가 자신을 탈출하지 마십시오. 당신은 뭔가 잘못되게해야합니다. 대신 매개 변수화 된 쿼리를 사용하거나 어떤 이유로 할 수없는 경우이를 수행하는 기존 라이브러리를 사용하십시오. 직접 할 이유가 없습니다.

나는 이것이 질문을받은 후에 오랜 시간이라는 것을 알고 있지만 ..

'인용 인용'절차에 대한 공격을 시작하는 한 가지 방법은 String Truncation입니다. MSDN에 따르면 SQL Server 2000 SP4 (및 SQL Server 2005 SP1)에서 너무 긴 문자열이 조용히 잘립니다.

문자열을 인용하면 문자열의 크기가 증가합니다. 모든 아포스트로피가 반복됩니다. 그런 다음 버퍼 외부 SQL의 일부를 밀어 넣는 데 사용할 수 있습니다. 따라서 WHERE 절의 일부를 효과적으로 다듬을 수 있습니다.

이것은 아마도 'User Admin'페이지 시나리오에서 '업데이트'명령문을 남용하여 모든 검사를 수행하지 않을 수 있습니다.

따라서 모든 인수를 인용하기로 결정한 경우 문자열 크기와 무슨 일이 일어나고 있는지 알고 잘라 내지 않도록하십시오.

매개 변수를 사용하는 것이 좋습니다. 언제나. 데이터베이스에서 그것을 시행 할 수 있기를 바랍니다. 그리고 부작용으로, 더 많은 진술이 동일하게 보이기 때문에 더 나은 캐시 히트를 얻을 가능성이 높습니다. (이것은 확실히 Oracle 8에서 사실이었습니다)

입력 위생은 당신이 하프 ass를 원하는 것이 아닙니다. 엉덩이 전체를 사용하십시오. 텍스트 필드에 정규 표현식을 사용하십시오. 숫자를 적절한 숫자 유형으로 시도하고 작동하지 않으면 유효성 검사 오류를보고하십시오. ' -와 같은 입력에서 공격 패턴을 검색하는 것은 매우 쉽습니다. 사용자의 모든 입력이 적대적이라고 가정합니다.

나는 '고급 검색'기능을 다룰 때이 기술을 사용했는데, 여기서 쿼리를 처음부터 구축하는 것이 유일한 대답이었습니다. (예 : 사용자가 제품 속성에 대한 무제한 제약 조건을 기반으로 제품을 검색하고 열 및 허용 값을 GUI 컨트롤로 표시하여 사용자의 학습 임계 값을 줄입니다.)

그 자체로는 안전합니다. 그러나 다른 답변자가 지적했듯이 백 스페이스 탈출을 처리해야 할 수도 있습니다 (적어도 ADO 또는 ADO.NET을 사용하여 쿼리를 SQL Server로 전달할 때는 적어도 모든 데이터베이스 나 기술을 보증 할 수는 없습니다).

SNAG는 어떤 문자열에 사용자 입력 (항상 잠재적으로 악의적 인)이 포함되어 있고 어떤 문자열이 유효한 SQL 쿼리인지 확인해야한다는 것입니다. 트랩 중 하나는 데이터베이스의 값을 사용하는 경우-원래 값이 사용자에게 제공 되었습니까? 그렇다면 탈출해야합니다. 내 대답은 SQL 쿼리를 구성 할 때 가능한 한 늦게 소독하려고 시도하는 것입니다.

그러나 대부분의 경우 매개 변수 바인딩이가는 길입니다. 더 간단합니다.

어쨌든 당신이 알고있는 것처럼 나쁜 생각입니다.

다음과 같이 문자열로 인용문을 피하는 것과 같은 것은 어떻습니까 : '

당신의 교체는 다음과 같습니다. ''

백 슬래시가 첫 번째 인용문을 피하면 두 번째 인용문이 문자열을 종료했습니다.

간단한 답변 : 때로는 작동하지만 항상 작동하는 것은 아닙니다. 흰색 목록 검증을 사용하려고합니다 모든 것 당신은하지만, 나는 그것이 항상 가능하지는 않다는 것을 알고 있으므로, 당신은 최고의 추측 블랙리스트와 함께 가야합니다. 마찬가지로, 당신은 매개 변수 저장 Procs를 사용하고 싶습니다. 모든 것, 그러나 다시 한번, 그것은 항상 가능한 것은 아니므로 매개 변수와 함께 sp_execute를 사용해야합니다.

사용 가능한 블랙리스트 주변에는 여러분이 생각해 낼 수있는 방법이 있습니다 (및 일부 화이트리스트도).

괜찮은 글은 다음과 같습니다. http://www.owasp.org/index.php/top_10_2007-a2

당신이 진짜 물건을 확보 할 시간을주기 위해 빠른 해결책으로 이것을해야한다면, 그렇게하십시오. 그러나 당신이 안전하다고 생각하지 마십시오.

SQL-Injections로부터 안전한 방법은 예외없이 두 가지가 있습니다. 준비된 진술 또는 전모 저장 절차.

매개 변수화 된 쿼리가있는 경우 항상 쿼리를 사용해야합니다. 하나의 쿼리가 그물을 통해 미끄러지고 DB가 위험에 처해 있습니다.

예, 누군가가 달릴 때까지 바로 작동해야합니다. quoted_identifier를 설정하십시오 그리고 당신에게 이중 인용문을 사용합니다.

편집 : 악의적 인 사용자가 인용 된 식별자를 끄는 것을 허용하지 않는 것만 큼 간단하지 않습니다.

SQL Server 기본 클라이언트 ODBC 드라이버 및 SQL Server 기본 클라이언트 OLE DB 제공 업체는 연결 시점 할 때 QUOTED_IDENTIFIER를 자동으로 설정합니다. 이는 ODBC 데이터 소스, ODBC 연결 속성 또는 OLE DB 연결 속성에서 구성 할 수 있습니다. DB-Library 응용 분야의 연결을 위해 SET Quoted_Iendifier의 기본값이 꺼져 있습니다.

저장된 절차가 만들어지면 set quoted_identifier 및 set ansi_nulls 설정은 저장 프로 시저의 후속 호출에 캡처되어 사용됩니다..

quoted_identifier를 설정하십시오 Alter 데이터베이스의 quoted_identifer 설정에 해당합니다.

quoted_identifier는 세트입니다 구문 분석 시간에 설정하십시오. 구문 분석 시간을 설정한다는 것은 세트 문이 배치 또는 저장 프로 시저에 존재하는 경우 코드 실행이 실제로 해당 지점에 도달하는지 여부에 관계없이 적용됩니다. 그리고 세트 진술은 진술이 실행되기 전에 발효됩니다.

당신이 반드시 그것을 알지 못하고 인용 한 quoted_identifier는 많은 방법이 있습니다. 분명히 - 이것은 당신이 찾고있는 흡연 건 착취가 아니지만 꽤 큰 공격 표면입니다. 물론, 당신도 이중 인용문을 피했다면 - 우리는 우리가 시작한 곳으로 돌아 왔습니다. ;)

다음과 같은 경우 방어가 실패합니다.

  • 쿼리에 문자열이 아닌 숫자가 필요합니다.
  • 다음을 포함하여 작은따옴표를 나타내는 다른 방법이 있었습니다.
    • \039와 같은 이스케이프 시퀀스
    • 유니코드 문자

(후자의 경우 교체를 완료한 후에만 확장된 것이어야 합니다)

PATRICK, 모든 입력, 숫자 입력에 대한 단일 따옴표를 추가하고 있습니까? 숫자 입력이 있지만 그 주위에 단일 인용문을 넣지 않으면 노출됩니다.

사용자 입력의 소아화가 무엇인지 추악한 코드! 그런 다음 SQL 문에 대한 Clunky StringBuilder. 준비된 명령문 방법은 훨씬 더 깨끗한 코드를 초래하며 SQL 주입 혜택은 정말 좋은 추가 기능입니다.

또한 왜 바퀴를 재창조합니까?

단일 인용문을 두 개의 단일 인용문으로 변경하는 대신, 아포스트로피, 인용문으로 변경하거나 완전히 제거하는 것이 어떻습니까?

어느 쪽이든, 그것은 약간의 kludge입니다 ... 특히 단일 따옴표를 사용할 수있는 합법적으로 이름을 가질 때 ...

참고 : 귀하의 방법은 또한 앱에서 작업하는 모든 사람이 데이터베이스에 부딪 치기 전에 입력을 소독하는 것을 기억한다고 가정합니다.

문자열에 맞는 솔루션을 찾을 수 있지만, 수치 적 예측을 위해서는 숫자 만 통과 해야하는지 확인해야합니다 (간단한 점검은 int/double/decimal으로 구문 분석 할 수 있습니까?).

많은 추가 작업입니다.

효과가 있지만 나에게 약간의 호키처럼 보입니다. 대신 정규 표현식에 대해 테스트하여 각 문자열이 유효한지 확인하는 것이 좋습니다.

예, 할 수 있습니다.

주제를 연구 한 후에는 입력이 제안한대로 소독 된 입력이 안전하다고 생각하지만이 규칙에 의해서만 가능합니다.

  1. 사용자로부터 오는 문자열 값이 문자열 리터럴이 아닌 다른 것이되도록 허용하지 않습니다 (즉, 구성 옵션 : "추가 SQL 열 이름/표현식을 입력하십시오 :"). 문자열 이외의 값 유형 (숫자, 날짜, ...) : 기본 데이터 유형으로 변환하고 각 데이터 유형에서 SQL 리터럴에 대한 루틴을 제공합니다.

    • SQL 문은 검증하는 데 문제가 있습니다
  2. 당신은 사용합니다 nvarchar/nchar 열 (및 접두사 문자 리터럴이 있습니다 N) 또는 제한 값으로 들어갑니다 varchar/char ASCII 문자에 대한 열 (예 : SQL 문을 만들 때 예외를 던지기)

    • 이런 식으로 당신은 Char (700)에서 char (39)로 자동 아포스트로피 변환을 피할 것입니다 (및 다른 유사한 유니 코드 해킹)
  3. 당신은 항상 실제 열 길이에 맞게 값 길이를 검증합니다 (더 긴 경우 예외를 던지십시오)

    • SQL Server에 알려진 결함이 있었는
  4. 당신은 그것을 보장합니다 SET QUOTED_IDENTIFIER 항상 ON

    • 주의 할 수없는 코드 섹션에서도 구문 분석 시간에 시행됩니다.

이 4 점을 준수하면 안전해야합니다. 당신이 그들 중 하나를 위반하면 SQL 주입 방법이 열립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top