DB에 연결하지 않고 mysql_real_escape_string의 대안


91

DB 연결없이 건식 테스트를 수행해야 할 때처럼 데이터베이스에 연결하지 않고 mysql_real_escape_string으로 작동하는 함수를 갖고 싶습니다. mysql_escape_string은 더 이상 사용되지 않으므로 바람직하지 않습니다. 내 결과 중 일부 :

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064



1
+1 저는 MySQL 클래스를 직접 작성하고 매개 변수 바인딩 목적으로 mysql_real_escape_string ()을 사용합니다. 모든 호스팅이 지원하는 것은 아니므로 mysqli를 사용하지 않습니다. 나는 또한 다중 파일 및 다중 클래스 라이브러리를 피합니다. 내가 필요한 것은 깔끔하고 깨끗한 단일 클래스입니다. 감사합니다!
Viet

나도 +1. 내 사용 사례는 API를 통해 SQL 조각을 원격 SugarCRM 인스턴스로 푸시해야하는 SugarCRM APi입니다. 불쾌하지만 그것은 내가 함께 일해야 할 것입니다 (SugarCRM 개발자 헤드를 함께 두 드리십시오). API를 사용하는 응용 프로그램에서 SQL의 문자열을 이스케이프해야하며 SugarCRM 인스턴스 뒤의 데이터베이스와 완전히 분리되어 있습니다.
Jason

답변:


76

DB 연결 없이는 문자열을 안전하게 이스케이프 할 수 없습니다. mysql_real_escape_string()준비된 문은 적절한 문자 집합을 사용하여 문자열을 이스케이프 할 수 있도록 데이터베이스에 연결해야합니다. 그렇지 않으면 다중 바이트 문자를 사용하여 SQL 주입 공격이 여전히 가능합니다.

만하는 경우 테스트 , 당신은뿐만 아니라 사용할 수 mysql_escape_string()는 SQL 인젝션 공격에 대한 보증 100 % 아닙니다, 그러나 그것은 DB 연결없이 안전한 빌드 아무것도 불가능하다.


1
+1 메모 감사합니다. 멀티 바이트 문자를 사용하여 SQL 주입 공격에 대해 테스트하는 방법을 잘 모르겠습니다.
Viet

2
업데이트 할 오래된 코드를 받았습니다. mysql_escape_string연결없이 사용 합니다 (여전히 이유를 알아 내려고합니다). 해당 기능은 더 이상 사용되지 않으므로 어떻게 대체 할 수 있는지 궁금합니다. 연결을 열지 않고 대체하는 기능에 "적절한 문자 집합"을 지정할 수 있다는 것은 확실히 합리적입니다.
JohnK

3
불가능한? mysql_real_escape_string은 동등한 함수에 직접 전달할 수있는 구성 데이터가 아닌 데이터베이스 연결에서 무엇을 얻습니까? 편집 : 아래를 읽으면 MySQL 내에서 라이브러리 함수를 호출하므로 PHP 외부에서 발생하는 일부 처리가 있습니다. 여전히 이식 가능할 수 있지만 최신 상태로 유지하는 것은 그 자체로 프로젝트가 될 것입니다.
Jason

2
DB 문자 집합이 미리 알려지면 어떻게됩니까?
jchook

7
예, 문자 집합을 알고 있다면 연결없이 탈출하는 것을 막는 것은 무엇입니까?
Johan

67

음, mysql_real_escape_string 함수 참조 페이지 에 따르면 "mysql_real_escape_string ()은 MySQL의 라이브러리 함수 mysql_real_escape_string을 호출하여 다음 문자를 이스케이프합니다. \ x00, \ n, \ r, \, ',"및 \ x1a. "

이를 염두에두고 게시 한 두 번째 링크에 제공된 함수가 필요한 작업을 정확히 수행해야합니다.

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}

6
감사. 다른 것을 제안합니다 : function escape ($ aQuery) {return strtr ($ aQuery, array ( "\ x00"=> '\ x00', "\ n"=> '\ n', "\ r"=> '\ r', '\\'=> '\\\\', " '"=> "\'", ' "'=> '\"', "\ x1a"=> '\ x1a')) ; }
Viet

1
\ x1a가 \\ x1a가 아닌 \\\ x1a로 대체되는 이유는 무엇입니까? 오타입니까?
Michael Z

16
-1 이것은 매우 위험합니다. 데이터베이스 연결이 멀티 바이트 문자 집합을 사용하는 경우 이와 같은 간단한 바이트 교체로 인해 데이터 손상 (이스케이프 / 인용 문자 포함)이 발생할 수 있습니다. 악의적 인 공격자가 임의의 SQL을 삽입하기 위해 의도적으로 악용 할 수 있습니다.
eggyal 2014

문자 세트가 잘못되면 위험 할 수 있습니다. 멀티 바이트 문자 집합의 경우 mysql이이를 사용하는 경우 누군가 바이트를 입력하여 \\를 취소 할 수 있습니다. 멀티 바이트 문자 세트는 종종 \\를 포함하여 두 번째 바이트로 무엇이든 취할 수 있습니다 .mysql은 독립형 \\으로 보지 않지만 멀티 바이트 문자의 일부로 간주합니다. UTF8에서 어떤 일이 발생하는지 전혀 모릅니다. 나는 [0xB0, '\\']와 함께 유효하지 않은 바이트 \\를 쳤을 때 그 바이트를 삼키는 것이 아니라 그 바이트로 멈추고 다시 시작하기를 바랍니다.
jgmjgm

1
charset이 utf8이라는 것을 알고 있다면 이것을 사용하는 것이 안전 합니까 mb_strpos()(그리고와 mb_substr()유사한 동작을 생성하는 것 substr_replace())?
SOFe

28

내 다른 대답과는 정반대 로이 다음 함수는 멀티 바이트 문자로도 안전합니다.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

나보다 더 많은 지식이있는 사람이 위의 코드가 작동하지 않는 이유를 말해 줄 수 있기를 바랍니다.


+1 노력해 주셔서 감사합니다. 멀티 바이트 관련 SQL 주입에 대해 자세히 알아 보려고합니다.
Viet

$ return. = '\ x'이어야한다고 생각합니다. dechex ($ ord); 대신
Viet

1
일반적으로 작은 따옴표로 묶인 문자열에도 '\\'를 사용하는 것을 선호합니다.주의하지 않으면 '\'하나가 다음 문자에 영향을 미칠 수 있기 때문입니다. 나는 아마도 다시 강박증이 될 것입니다.
너무 많은 PHP

1
이 함수는 mysql 이스케이프 규칙을 따르지 않으며 데이터 무결성이 손실됩니다. "MySQL은 표 9.1,"특수 문자 이스케이프 시퀀스 "에 표시된 이스케이프 시퀀스를 인식합니다. 다른 모든 이스케이프 시퀀스의 경우 백 슬래시가 무시됩니다. 즉, 이스케이프 된 문자는 이스케이프되지 않은 것처럼 해석됩니다. 예 :"\ x " "x"입니다. " - dev.mysql.com/doc/refman/5.6/en/...
velcrow

2
\ xAA는 실제로 MySQL 문자열 리터럴에서 "xAA"라는 텍스트보다 더 많은 것을 의미합니까? 문서에서 \ x에는 특별한 의미가 없다고 나와 있으므로 \는 무시됩니다. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason

6

추가 연구를 통해 다음을 발견했습니다.

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

보안 수정 :

다중 바이트 인코딩 처리에서 SQL 삽입 보안 구멍이 발견되었습니다. 버그는 서버에 있었으며 mysql_real_escape_string () C API 함수로 이스케이프 된 문자열을 잘못 구문 분석했습니다.

이 취약점은 OSDB 컨소시엄의 프로젝트 간 보안 협력의 일환으로 Josh Berkus와 Tom Lane이 발견하고보고했습니다. SQL 주입에 대한 자세한 내용은 다음 텍스트를 참조하십시오.

토론. 멀티 바이트 인코딩 처리에서 SQL 삽입 보안 허점이 발견되었습니다. SQL 주입 보안 허점은 사용자가 데이터베이스에 삽입 할 데이터를 제공 할 때 사용자가 서버가 실행할 데이터에 SQL 문을 주입 할 수있는 상황을 포함 할 수 있습니다. 이 취약점과 관련하여 문자 집합을 인식하지 못하는 이스케이프 (예 : PHP에서 addlash ())를 사용하면 일부 멀티 바이트 문자 집합 (예 : SJIS, BIG5 및 GBK)에서 이스케이프를 우회 할 수 있습니다. 결과적으로, addlashes ()와 같은 함수는 SQL 주입 공격을 방지 할 수 없습니다. 서버 측에서는이 문제를 해결할 수 없습니다. 가장 좋은 솔루션은 애플리케이션이 mysql_real_escape_string ()과 같은 함수에서 제공하는 문자 집합 인식 이스케이프를 사용하는 것입니다.

그러나 MySQL 서버가 mysql_real_escape_string ()의 출력을 구문 분석하는 방법에서 버그가 발견되었습니다. 그 결과 문자 집합 인식 함수 mysql_real_escape_string ()을 사용하더라도 SQL 주입이 가능했습니다. 이 버그가 수정되었습니다.

해결 방법. MySQL을 mysql_real_escape_string () 구문 분석의 버그 수정이 포함 된 버전으로 업그레이드 할 수 없지만 MySQL 5.0.1 이상을 실행하는 경우 해결 방법으로 NO_BACKSLASH_ESCAPES SQL 모드를 사용할 수 있습니다. (이 모드는 MySQL 5.0.1에서 도입되었습니다.) NO_BACKSLASH_ESCAPES는 백 슬래시가 특수 문자로 간주되지 않는 SQL 표준 호환 모드를 활성화합니다. 그 결과 쿼리가 실패합니다.

현재 연결에 대해이 모드를 설정하려면 다음 SQL 문을 입력하십시오.

SET sql_mode='NO_BACKSLASH_ESCAPES';

모든 클라이언트에 대해 전역 적으로 모드를 설정할 수도 있습니다.

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

이 SQL 모드는 명령 줄 옵션 --sql-mode = NO_BACKSLASH_ESCAPES를 사용하거나 서버 옵션 파일 (예 : my.cnf 또는 my.ini)에서 sql-mode = NO_BACKSLASH_ESCAPES를 설정하여 서버가 시작될 때 자동으로 활성화 될 수도 있습니다. , 시스템에 따라 다름). (버그 # 8378, CVE-2006-2753)

Bug # 8303도 참조하십시오.


1
이것은 오래 전에 수정되었습니다.
당신의 상식

2
또한 NO_BACKSLASH_ESCAPES 다른 취약성도입 하는 것에주의하십시오 .
eggyal 2014

2
5.1.11에서 수정 됨-링크가 끊어졌습니다. 아카이브는 다음과 같습니다. web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.