저장 프로 시저가 SQL 삽입을 방지합니까?


83

저장 프로 시저가 PostgreSQL 데이터베이스에 대한 SQL 주입 공격을 막는 것이 사실입니까? 나는 약간의 연구를 해본 결과 저장 프로 시저 만 사용하더라도 SQL Server, Oracle 및 MySQL이 SQL 삽입에 대해 안전하지 않다는 것을 알았습니다. 그러나 PostgreSQL에는이 문제가 없습니다.

PostgreSQL 코어에서 스토어드 프로 시저 구현이 SQL 인젝션 공격을 방지합니까 아니면 다른 것입니까? 아니면 스토어드 프로 시저 만 사용하더라도 PostgreSQL도 SQL 삽입에 취약합니까? 그렇다면 예를 들어주세요 (예 : 책, 사이트, 종이 등).


4
이상하게도 여기에 가장 많이 나오는 대답은 대부분 SQL Server를 다루는 OT이며 Postgres 에 관한 질문입니다 . 여기에 포스트 그레스에 대한 관련 대답은 : dba.stackexchange.com/questions/49699/... . 다른 사람의 몇 가지가 있습니다, 검색을 시도 : dba.stackexchange.com/...
어윈 Brandstetter

@ErwinBrandstetter 원래 질문은 (OP에 의해) postgres로 태그되지 않았으며 여전히 여러 다른 DBMS를 언급했습니다. 그것이 다른 DBMS에 중점을 둔 다양한 답변의 이유라고 생각합니다. Postgres에 중점을 두는 것이 좋습니다.
ypercubeᵀᴹ

@ ypercubeᵀᴹ : 시간을 찾으면 여기에 답변을 추가하겠습니다. 그 동안 dba.stackexchange.com/questions/49699/… 를보다 명확하고 포괄적으로 업데이트 했습니다 .
Erwin Brandstetter 2018 년

답변:


71

아니요, 저장 프로시 저는 SQL 삽입을 막지 않습니다. 불행히도 SQL 주입을 허용하는 저장 프로 시저의 실제 예 (내가 누군가가 만든 사내 앱에서)는 다음과 같습니다.

이 SQL 서버 코드 :

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

postgres와 거의 동일합니다.

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

개발자의 아이디어는 다양한 검색 프로 시저를 작성하는 것이었지만 결과는 WHERE 절에 사용자가 원하는 모든 것을 포함 할 수 있으므로 작은 Bobby Tables 에서 방문 할 수 있습니다.

SQL 문을 사용하는지 아니면 저장 프로 시저를 사용하는지는 중요하지 않습니다. 중요한 것은 SQL이 매개 변수를 사용하는지 또는 연결된 문자열을 사용하는지입니다. 매개 변수는 SQL 삽입을 방지합니다. 연결된 문자열은 SQL 삽입을 허용합니다.


46

SQL-Injection 공격은 신뢰할 수없는 입력에 직접 쿼리를 추가하여 사용자 가이 정식 XKCD 만화에 표시된대로 임의의 코드를 효과적으로 실행할 수있는 공격 입니다.

따라서 우리는 상황을 얻습니다.

userInput = getFromHTML # "Robert ') 테이블 학생 삭제;-"

쿼리 = "선택 * studentName ="+ userInput 인 학생에서 *

일반적으로 저장 프로시 저는 들어오는 매개 변수가 구문 분석되지 않기 때문에 SQL 주입 공격에 대한 효과적인 방어 입니다.

저장 프로 시저에서 대부분의 DB (및 프로그램)에서는 미리 컴파일 된 쿼리가 저장 프로 시저로 계산된다는 것을 잊지 마십시오.

 

저장된 프로 시저 foo (
studentName = : 1 인 학생 중에서 *를 선택하십시오.
);

그런 다음 프로그램이 액세스를 원할 때 foo(userInput)결과를 호출 하고 행복하게 검색합니다.

사람들이 잘못된 저장 프로 시저 를 작성할 수 있기 때문에 저장 프로시 저는 SQL-Injection에 대한 마법의 방어가 아닙니다 . 그러나 사전 컴파일 된 쿼리는 데이터베이스 나 프로그램에 저장되므로 SQL-Injection 작동 방식을 이해하면 보안 허점을 여는 것이 훨씬 더 어렵습니다 .

SQL-Injection에 대한 자세한 내용을 읽을 수 있습니다.


29

예, 어느 정도입니다.
저장 프로 시저만으로는 SQL 삽입을 막을 수 없습니다.

OWASP 에서 SQL 인젝션에 대해 먼저 인용하겠습니다

SQL 주입 공격은 클라이언트에서 응용 프로그램으로의 입력 데이터를 통한 SQL 쿼리 삽입 또는 "주입"으로 구성됩니다. 성공적인 SQL 주입 익스플로잇은 데이터베이스에서 중요한 데이터를 읽고, 데이터베이스 데이터를 수정 (삽입 / 업데이트 / 삭제)하고, 데이터베이스에서 관리 작업을 실행 (예 : DBMS 종료), DBMS 파일에있는 특정 파일의 내용을 복구 할 수 있습니다 시스템 및 경우에 따라 운영 체제에 명령을 내립니다. SQL 주입 공격은 사전 정의 된 SQL 명령의 실행에 영향을주기 위해 SQL 명령이 데이터 플레인 입력에 주입되는 일종의 주입 공격입니다.

저장 프로 시저를 사용하는 경우에도 사용자 입력을 삭제하고 SQL 문을 연결하지 않아야합니다.

제프 애트우드는 "에 SQL을 연결의 결과를 설명 나에게 매개 변수화 된 SQL을 부여하거나, 나에게 죽음을 줄을 "

다음은 내가 SQL 주입을들을 때마다 내 마음에 오는 재미있는 만화입니다 대체 텍스트 :-) 난 당신이 지점을 찾은 것 같아

SQL Injection Prevention Cheat Sheet를 살펴보십시오 . 예방 방법이 깔끔하게 설명되어 있습니다 ...


12

문자열 연결은 SQL 삽입의 원인입니다. 이것은 매개 변수를 사용하여 피할 수 있습니다.

스토어드 프로시 저는 연결할 때 유효하지 않은 구문을 적용하여 보안 계층을 추가하지만 동적 SQL을 사용하는 경우 "안전하지"않습니다.

따라서 위의 코드 는 이러한 문자열의 연결 로 인해 발생합니다

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

운 좋게도 잘못된 구문을 제공합니다

매개 변수 를 제공하면

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

이것은 의미

  • @UserName = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = monkey

이제 위 코드에서 사용자가 없다고 가정하기 때문에 행이 없습니다. x' AND 1=(SELECT COUNT(*) FROM Client); --

저장된 proc이 이와 같이 보이는 경우 (연결된 동적 SQL 사용 ) 매개 변수화 된 proc 호출은 여전히 ​​SQL 삽입을 허용합니다.

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

따라서 시연 한 것처럼 문자열 연결은 SQL 삽입의 주요 적입니다.

저장 프로시 저는 캡슐화, 트랜잭션 처리, 권한 감소 등을 추가하지만 SQL 주입으로 인해 남용 될 수 있습니다.

매개 변수에 대한 자세한 내용은 스택 오버플로를 볼 수 있습니다


10

"SQL 주입 공격 때 발생하는 사용자 입력이 잘못 인코딩됩니다. 사용자가 그녀의 쿼리를 전송 일부 데이터의에서 즉 값 일반적으로 사용자 입력이되고 $_GET, $_POST, $_COOKIE, $_REQUEST, 또는 $_SERVER배열. 그러나, 사용자 입력이 다른 다양한에서 올 수 소스 등 소켓, 원격 웹 사이트, 파일처럼 .. 따라서, 당신은 정말해야 상수를 제외한 모든 치료 (같은 'foobar') 사용자 입력 등을 . "

나는 최근에이 주제에 대해 철저히 조사해 왔으며 다른 사람들과 매우 흥미로운 자료를 공유하고 싶기 때문에이 글을 더 완전하고 유익하게 만들었습니다.



YouTube에서


위키 백과에서


OWASP에서


PHP 매뉴얼에서


Microsoft와 Oracle에서


스택 오버플로


SQL 주입 스캐너


2

저장 프로시 저는 마술로 SQL 삽입을 방지하지는 않지만 훨씬 더 쉽게 방지 할 수 있습니다. 당신이해야 할 일은 다음과 같습니다 (Postgres 예제).

CREATE OR REPLACE FUNCTION my_func (
  IN in_user_id INT 
)
[snip]
  SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]

그게 다야! 문자열 연결 (예 : 동적 SQL)을 통해 쿼리를 구성 할 때만 문제가 발생하며 이러한 경우에도 바인딩 할 수 있습니다! (데이터베이스에 따라 다릅니다.)

동적 쿼리에서 SQL 삽입을 피하는 방법 :

1 단계) 동적 쿼리가 정말로 필요한지 자문 해보십시오. 입력을 설정하기 위해 문자열을 묶는 경우 잘못 입력했을 수 있습니다. (이 규칙에는 예외가 있습니다. 일부 데이터베이스에서 쿼리를보고하는 경우는 예외입니다. 각 실행마다 새 쿼리를 강제로 컴파일하지 않으면 성능 문제가 발생할 수 있습니다. 그러나이 문제를 조사하기 전에 조사하십시오. )

2 단계) 특정 RDBMS에 변수를 설정하는 올바른 방법을 연구하십시오. 예를 들어, Oracle에서는 다음을 수행 할 수 있습니다 (문서에서 인용).

sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE ' 
           || v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!

여기에서는 여전히 입력을 연결하지 않습니다. 당신은 안전하게 묶고 있습니다! 만세!

데이터베이스가 위와 같은 것을 지원하지 않는 경우 (바람직하게도 여전히 나쁘지는 않지만 놀라지 않을 것입니다) 또는 여전히 입력을 연결 해야하는 경우 (예 : 쿼리를보고하는 "때때로"의 경우) 위의 힌트), 적절한 탈출 기능을 사용해야합니다. 직접 쓰지 마십시오. 예를 들어 postgres는 quote_literal () 함수를 제공합니다. 그래서 당신은 실행할 것입니다 :

sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);

in_name이 '[snip] 또는 1 = 1'과 같은 악의적 인 경우 ( "or 1 = 1"부분은 모든 행을 선택하여 사용자가하지 말아야 할 급여를 볼 수 있도록합니다!), quote_literal은 엉덩이를 절약합니다. 결과 문자열 만들기 :

SELECT salary FROM employees WHERE name = '[snip] or 1=1'

이름이 이상한 직원이없는 한 결과가 없습니다.

그것이 요점입니다! 이제 Oracle Injection 전문가 Tom Kyte가 SQL 인젝션 주제에 대한 고전적인 게시물에 대한 링크를 남기도록하겠습니다. Linky


언급하는 것을 잊지 마십시오. quote_ident()그러나 일반적으로 주입 방지 동적 SQL을 작성하는 가장 쉬운 방법 은 식별자 및 리터럴에 format()자리 표시자를 사용 하고 사용하는 것 입니다. 그 방법은 SQL을 사용하여 훨씬 더 읽기에 해당하는 버전보다 및 기능%I%L||quote_....()
a_horse_with_no_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.