ProgramingTip

매개 변수화 된 문이 모든 SQL 제출을 중지 할 수 있습니까?

bestdevel 2020. 10. 21. 21:15
반응형

매개 변수화 된 문이 모든 SQL 제출을 중지 할 수 있습니까?


여전히 많은 성공적인 SQL 제출이 있습니까? 일부 개발자가 매개 변수화 된 명령문을 사용하기에는 너무 멍청해서?


질문에 대한 내 의견에 게시 한 링크는 문제를 매우 잘 설명합니다. 문제가 지속되는 이유에 대한 내 감정을 아래에 요약했습니다.

  1. 막 시작하는 사람들은 SQL에 대해 인식하지 못합니다.

  2. 이스케이프가 (유일한?)이라고 생각합니다. 에 대해 빠른 Google 검색을 수행하는 php mysql query경우에 첫 번째 페이지는 이스케이프 된 사용자 입력을 쿼리에 삽입하는 예제 가있는 페이지입니다. (대해서 사용할 수있는 것이 없습니다). 다른 사람들이 말했듯이 많은 변수들이 보간을 사용하는 튜토리얼이 너무 많아서 여전히 얼마나 자주 사용하는 것이 놀라운 일이 아닙니다.mysql_query

  3. 매개 변수화 된 명령문이 작동하는 방식에 대한 이해 부족. 어떤 사람들은 그것이 가치를 피하는 멋진 수단이라고 생각합니다.

  4. 사용하지 않는 명령문을 사용하지 않습니다. 나는 많은 사람들이 얼마나 느린 지 포함하는 문장이 얼마나 많은 사람들이 자신의 테스트를하지 않았다고 생각한다. Bill Karwin이 그의 강연에서 지적했듯이, 준비된 성능의 사용을 고려할 때 성능의 차이를 거의 사용합니다. 한 번 준비하고 여러 번 실행 하는 것의 이점은 보안 및 코드 유지 관리의 개선과 거의 잊혀진 것처럼 보입니다.

  5. 일부는 모든 곳에서 사용되는 변수화 된 명령문을 사용하지만 테이블 및 열 이름, 키워드 및 조건부 연산자와 같은 확인되지 않은 값을 보간합니다. 사용자가 검색 필드, 비교 조건 및 정렬 순서를 수있는 것과 같은 동적 검색이 이에 대한 다양한 예입니다.

  6. ORM을 사용할 때 잘못된 보안 감각. ORM은 여전히 ​​SQL 문 부분의 보간을 허용합니다.

  7. 복잡한 주제이고, 보안은 엄격한 주제입니다. 안전한 데이터베이스 응용 프로그램을 개발하는 것은 쉽지 않습니다. 깔깔 한 개발자도 잡힐 수 있습니다.

  8. stackoverflow에 대한 많은 답변이 도움이되지 않습니다. 동적 SQL 및 매개 변수 보간을 사용하는 질문을 때 대신 변수화 된 명령문을 사용 제안하는 응답이 부족한 경우에 사람들이 사용합니다. 나는 제안에 반박하는 것을 보았습니다-일반적으로 허용 할 수없는 성능 오버 헤드 때문에. 나는 많은 질문의 대부분을 설치하는 사람들이 많은 요청의 대부분을 설치하는 사람들이 준비하는 데 추가 몇 밀리 초가 애플리케이션에 치명적인 영향을주는 위치에 안전하게 의심합니다.


SQL 공격을 막는 변수화 된 쿼리에 대한 기사에서는 그 이유를 설명하지 못합니다. "그렇기 때문에 이유를 종종 묻지."라는 경우가 있습니다. 나쁜 교육자의 확실한 신호는 그들이 말할 수 있다는 것을 알 수 있습니다. 그러나 나는 빗나 갔다. 내가 혼란스러워하는 것이 효율적이다. 동적 SQL 쿼리를 상상해보세요.

sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password

따라서 간단한 SQL 삽입은 사용자 이름을 'OR 1 = 1로 입력하는 것입니다. 이것은 스케줄 SQL 쿼리를 만듭니다.

sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password

즉, 사용자 이름이 비어있는 모든 고객 ( '') 또는 1 = 1 (부울 인 true와 동일) 인 모든 고객을 선택합니다. 그런 다음-를 사용하여 나머지 쿼리를 주석 처리합니다. 따라서 모든 고객 테이블을 인쇄하거나 원하는 모든 작업을 수행합니다. 로그인하면 관리자가 될 수있는 첫 번째 사용자의 권한으로 로그인합니다.

이제 매개 변수화 된 쿼리는 다음과 같은 코드를 사용하여 다르게 수행합니다.

sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'

parameters.add("User", username)
parameters.add("Pass", password)

여기서 사용자 이름 및 암호는 입력 된 관련 사용자 이름 및 암호를 입력 된 변수입니다.

이제 전혀 변경되지 않는다고 생각할 수 있습니다. 확실히 Nobody OR 1 = 1 '-과 같은 사용자 이름 필드에 입력하여 입력하여 입력 할 수 있습니다.

sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'

그리고 유효한 주장처럼 보일 것입니다. 그러나 당신은 틀릴 것입니다.

매개 변수가있는 쿼리가 작동하는 방식은 sqlQuery가 쿼리로 전송되고 데이터베이스 가이 쿼리가 수행 할 작업을 정확히 알고있는 경우에만 사용자 이름과 암호를 값으로 삽입한다는 것입니다. 이는 데이터베이스가 쿼리가 수행 할 작업을 이미 알고 있기 때문에 쿼리에 영향을 미칠 수 없음을 의미합니다. 따라서이 경우 "Nobody OR 1 = 1 '-"의 사용자 이름과 빈 암호를 찾습니다. 이것은 거짓되어야합니다.

그러나 이것은 완전한 솔루션이 문제가 있기 때문에 여전히 javascript를 사용하므로 XSS 공격과 같은 다른 유효성 검사를 수행해야합니다. 그런 다음 페이지에 읽 히면 출력 유효성 검사에 따라 일반 자바 펼쳐 표시됩니다. 따라서 가장 좋은 방법은 여전히 ​​입력 유효성 검사를 사용하지만 매개 변수가있는 쿼리 또는 저장 프로 시저를 사용하여 SQL 공격을 중지하는 것입니다.


좋은 질문입니다. 대답은 결정 론적보다 확률 적이며 작은 예를 사용하여 내 견해를 설명하려고 노력할 것입니다.

SQL (SQLi)을 피하기 위해 쿼리에서 사용하는 매개 변수를 사용하거나 사용하는 제안하는 인터넷 참조가 있습니다. 저장 프로 시저 (예 :)가 SQLi에 대한 마술 지팡이가 아님을 보여 드리겠습니다. 책임은 여전히 ​​프로그래머에게 있습니다.

'사용자'테이블에서 사용자 행을 가져와 다음 SQL Server 저장 프로 시저를 고려하십시오.

create procedure getUser
 @name varchar(20)
,@pass varchar(20)
as
declare @sql as nvarchar(512)
set @sql = 'select usrID, usrUName, usrFullName, usrRoleID '+
           'from Users '+
           'where usrUName = '''+@name+''' and usrPass = '''+@pass+''''
execute(@sql)

사용자 이름과 비밀번호를 매개 변수로 전달하여 결과를 얻을 수 있습니다. 암호가 자유 텍스트로되어있어 가정하면 (이 예제의 단순성을 위해) 일반적인 호출은 다음과 같습니다.

DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)

EXECUTE @RC = [dbo].[getUser] 
   @name = 'admin'
  ,@pass = '!@Th1siSTheP@ssw0rd!!'
GO

그러나 거기에는 프로그래머가 저장 프로 시저 내에서 사용하는 잘못된 프로그래밍 기술이 있으므로 공격자가 다음을 수 있습니다.

DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)

EXECUTE @RC = [TestDB].[dbo].[getUser] 
   @name = 'admin'
  ,@pass = 'any'' OR 1=1 --'
GO

위의 매개 변수는 저장 프로 시저에 인수로 전달하고 최종적으로 실행될 SQL 명령은 다음과 같습니다.

select usrID, usrUName, usrFullName, usrRoleID 
from Users 
where usrUName = 'admin' and usrPass = 'any' OR 1=1 --'

.. 사용자로부터 모든 행을 다시 가져옵니다.

여기서 문제는 "저장 프로 시저를 만들고 필드를 매개 변수로 검색하도록 전달"원칙을 따르더라도 SQLi가 여전히 수행된다는 것입니다. 이는 저장 프로 시저 내부에 잘못된 프로그래밍 방식을 복사하기 때문입니다. 문제에 대한 해결책은 다음과 같이 저장 프로 시저를 다시 작성하는 것입니다.

alter procedure getUser
 @name varchar(20)
,@pass varchar(20)
as
select usrID, usrUName, usrFullName, usrRoleID 
from Users 
where usrUName = @name and usrPass = @pass

제가 말하고자하는 것은 개발자가 먼저 SQLi 공격이 무엇인지, 어떻게 수행 할 수 있는지 배운 다음 그에 따라 코드를 보호해야한다는 것입니다. 맹목적으로 '모범 사례'를 따르는 것이 항상 더 안전한 방법은 아닙니다 ... 그리고 아마도 이것이 우리가 많은 '모범 사례'를 가지고있는 이유입니다.


예, 준비된 명령문을 사용하면 적어도 이론적으로 모든 SQL 삽입이 중지됩니다. 실제로 매개 변수화 된 명령문은 실제 준비된 명령문이 아닐 수 있습니다. 예를 들어 PDOPHP에서는 기본적으로 에뮬레이트하므로 엣지 케이스 공격에 노출됩니다 .

실제 준비된 진술을 사용하는 경우 모든 것이 안전합니다. 글쎄, 적어도 예를 들어 테이블 이름을 준비 할 수 없다는 반응으로 안전하지 않은 SQL을 쿼리에 연결하지 않는 한.

그렇다면 왜 여전히 많은 성공적인 SQL 주입이 있습니까? 일부 개발자가 매개 변수화 된 명령문을 사용하기에는 너무 멍청해서?

예, 교육은 여기서 주요 포인트이며 레거시 코드베이스입니다. 많은 튜토리얼은 이스케이프를 사용하며 불행히도 웹에서 쉽게 제거 할 수 없습니다.


나는 프로그래밍에서 절대적인 것을 피합니다. 항상 예외가 있습니다. 저장 프로 시저와 명령 개체를 적극 권장합니다. 내 배경의 대부분은 SQL Server에 있지만 때때로 MySql을 사용합니다. 캐시 된 쿼리 계획을 포함하여 저장 프로 시저에는 많은 이점이 있습니다. 예, 이것은 매개 변수와 인라인 SQL을 사용하여 수행 할 수 있지만 주입 공격에 대한 더 많은 가능성을 열어 우려를 분리하는 데 도움이되지 않습니다. 제 애플리케이션은 일반적으로 상기 저장 프로 시저에 대한 실행 권한 만 가지고 있기 때문에 데이터베이스 보안이 훨씬 쉽습니다. 직접 테이블 / 뷰 액세스 없이는 아무것도 주입하기가 훨씬 더 어렵습니다. 응용 프로그램 사용자가 손상되면 사전 정의 된 것을 정확하게 실행할 수있는 권한 만 있습니다.

내 2 센트.


나는 "벙어리"라고 말하지 않을 것이다.

튜토리얼이 문제라고 생각합니다. 대부분의 SQL 자습서, 책, 바인드 매개 변수를 전혀 언급하지 않고 인라인 값으로 SQL을 설명합니다. 이 튜토리얼에서 배우는 사람들은 그것을 올바르게 배울 기회가 없습니다.


대부분의 코드는 보안과 관리를 염두에두고 작성되지 않았기 때문에 기능 추가 (특히 판매 할 수있는 것)와 보안 / 안정성 / 신뢰성 (매출이 훨씬 더 어렵습니다) 사이에서 선택이 주어지면 거의 항상 전자. 보안은 문제가 될 때만 문제가됩니다.


매개 변수화 된 문이 모든 SQL 주입을 중지 할 수 있습니까?

예, 데이터베이스 드라이버가 가능한 모든 SQL 리터럴에 대한 자리 표시자를 제공하는 한 가능합니다. 대부분의 준비된 진술 드라이버는 그렇지 않습니다. 필드 이름이나 값 배열에 대한 자리 표시자를 찾을 수 없습니다. 그러면 개발자가 연결 및 수동 서식을 사용하여 수동으로 쿼리를 조정하는 것으로 돌아갈 수 있습니다. 예상 된 결과.

그래서 배열과 식별자를 포함하여 쿼리에 동적으로 추가 할 수있는 대부분의 리터럴을 지원하는 PHP 용 Mysql 래퍼를 만들었습니다.

그렇다면 왜 여전히 많은 성공적인 SQL 주입이 있습니까? 일부 개발자가 매개 변수화 된 명령문을 사용하기에는 너무 멍청해서?

보시다시피, 실제로 바보가 아니더라도 모든 쿼리를 매개 변수화하는 것은 불가능합니다 .


첫 번째 질문에 대한 첫 번째 대답 : 예, 제가 아는 한 매개 변수화 된 쿼리를 사용하면 SQL 삽입이 더 이상 가능하지 않습니다. 다음 질문에 대해서는 확실하지 않으며 그 이유에 대한 의견 만 드릴 수 있습니다.

삽입 할 값과 함께 일부 다른 부분 (일부 논리적 검사에 의존 할 수도 있음)을 연결하여 SQL 쿼리 문자열을 "그냥"작성하는 것이 더 쉽다고 생각합니다. 쿼리를 생성하고 실행하는 것입니다. 또 다른 장점은 SQL 쿼리 문자열을 인쇄 (에코, 출력 등) 한 다음이 문자열을 데이터베이스 엔진에 대한 수동 쿼리에 사용할 수 있다는 것입니다.

준비된 명령문으로 작업 할 때는 항상 한 단계 이상 더 있어야합니다. 쿼리를 작성해야합니다 (물론 매개 변수 포함). 서버에서 쿼리를 준비해야합니다. 매개 변수를 원하는 실제 값에 바인딩해야합니다. 쿼리에 사용하기 쿼리를 실행해야합니다.

특히 매우 오래 지속되는 것으로 입증되는 일부 "빠르고 더러운"작업에 대해서는 다소 더 많은 작업 (그리고 프로그래밍하기가 그리 간단하지 않음)입니다.

친애하는,

상자


SQL 주입으로부터 애플리케이션을 보호하려면 다음 단계를 수행하십시오.

1 단계. 입력 제한. 2 단계. 저장 프로 시저와 함께 매개 변수를 사용합니다. 3 단계. 동적 SQL과 함께 매개 변수를 사용하십시오.

http://msdn.microsoft.com/en-us/library/ff648339.aspx 참조


SQL 주입은 데이터와 코드가 동일한 채널을 통해 제공되고 데이터가 코드로 오인되는 더 큰 코드 주입 문제의 하위 집합입니다. 매개 변수가있는 쿼리는 데이터 및 코드에 대한 컨텍스트를 사용하여 쿼리를 형성하여 이러한 문제가 발생하지 않도록합니다.

일부 특정 경우에는 이것이 충분하지 않습니다. 많은 DBMS에서 저장 프로 시저를 사용하여 SQL을 동적으로 실행할 수 있으므로 DBMS 수준에서 SQL 주입 결함이 발생합니다. 매개 변수가있는 쿼리를 사용하여 이러한 저장 프로 시저를 호출해도 프로 시저의 SQL 삽입이 악용되는 것을 방지 할 수 없습니다. 이 블로그 게시물 에서 또 다른 예를 볼 수 있습니다 .

일반적으로 개발자는 기능을 잘못 사용합니다. 일반적으로 코드는 올바르게 완료되면 다음과 같이 보입니다.

db.parameterize_query("select foo from bar where baz = '?'", user_input)

일부 개발자는 문자열을 함께 연결 한 다음 매개 변수화 된 쿼리를 사용합니다.이 쿼리는 실제로 우리가 찾고있는 보안 보장을 제공하는 앞서 언급 한 데이터 / 코드 구분을 만들지 않습니다.

db.parameterize_query("select foo from bar where baz = '" + user_input + "'")

매개 변수가있는 쿼리를 올바르게 사용하면 SQL 주입 공격에 대해 매우 강력하지만 뚫을 수없는 보호를 제공합니다.


준비된 명령문이 웹 응용 프로그램의 자체 코드 전체에서 적절하게 사용 되더라도 데이터베이스 코드 구성 요소가 안전하지 않은 방식으로 사용자 입력에서 쿼리를 생성하면 SQL 주입 결함이 여전히 존재할 수 있습니다. 다음은 @name 매개 변수에 SQL 삽입에 취약한 저장 프로 시저의 예입니다.

CREATE PROCEDURE show_current_orders
(@name varchar(400) = NULL)
AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ‘SELECT id_num, searchstring FROM searchorders WHERE ‘ +
‘searchstring = ‘’’ + @name + ‘’’’;
EXEC (@sql)
GO

응용 프로그램이 사용자가 제공 한 이름 값을 안전한 방식으로 저장 프로 시저에 전달하더라도 프로 시저 자체가이를 동적 쿼리에 직접 연결하므로 취약합니다.

참고 URL : https://stackoverflow.com/questions/6786034/can-parameterized-statement-stop-all-sql-injection

반응형