SQL 쿼리에 사용자 입력을 수정하지 않고 삽입하면 응용 프로그램이SQL 인젝션다음 예제와 같습니다.
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
사용자가 다음과 같이 입력 할 수 있기 때문입니다.value'); DROP TABLE table;--
, 쿼리는 다음과 같이됩니다.
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
이것이 일어나지 않도록하기 위해 할 수있는 일은 무엇입니까?
준비된 문과 매개 변수화 된 쿼리를 사용하십시오.이것은 매개 변수와 별도로 데이터베이스 서버로 보내고 구문 분석되는 SQL 문입니다. 이렇게하면 공격자가 악의적 인 SQL을 삽입하는 것은 불가능합니다.
기본적으로이 작업을 수행하는 데는 두 가지 옵션이 있습니다.
사용PDO(지원되는 모든 데이터베이스 드라이버 용) :
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array('name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
사용MySQLi(MySQL 용) :
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
MySQL 이외의 데이터베이스에 연결하는 경우 참조 할 수있는 드라이버 관련 두 번째 옵션이 있습니다 (예 :pg_prepare()
과pg_execute()
PostgreSQL 용). PDO는 보편적 인 옵션입니다.
사용시PDO
MySQL 데이터베이스에 액세스하는 방법레알준비된 진술은기본적으로 사용되지 않음. 이 문제를 해결하려면 준비된 문장의 에뮬레이션을 비활성화해야합니다. PDO를 사용하여 연결을 만드는 예는 다음과 같습니다.
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
위의 예제에서 오류 모드는 반드시 필요한 것은 아니지만,그러나 그것을 추가하는 것이 좋습니다. 이렇게하면 스크립트가Fatal Error
뭔가 잘못되었을 때. 그리고 개발자에게catch
모든 오류 (들)throw
n으로PDOException
에스.
무엇입니까의무적 인그러나, 첫 번째입니다setAttribute()
PDO에게 에뮬레이션 된 준비된 명령문을 사용하지 않도록 설정하고 사용하도록 지시합니다.레알준비된 진술. 이렇게하면 문과 값이 PHP에 의해 구문 분석되어 MySQL 서버로 전송되지 않습니다 (공격자가 악성 SQL을 삽입 할 가능성이 없음).
설정은 가능하지만charset
생성자의 옵션에서 PHP의 이전 버전 (<5.3.6)charset 매개 변수를 자동으로 무시함DSN에
무슨 일이 일어날 지 당신이 전달하는 SQL 문prepare
데이터베이스 서버에 의해 구문 분석되고 컴파일됩니다. 매개 변수를 지정하여 (?
또는 다음과 같은 명명 된 매개 변수:name
위의 예에서) 필터링 할 위치를 데이터베이스 엔진에 알려줍니다. 그럼 전화 할 때.execute
준비된 명령문은 지정한 매개 변수 값과 결합됩니다.
여기서 중요한 점은 매개 변수 값이 SQL 문자열이 아닌 컴파일 된 명령문과 결합된다는 것입니다. SQL 주입은 데이터베이스에 보낼 SQL을 생성 할 때 악의적 인 문자열을 포함하도록 스크립트를 속여서 작동합니다. 따라서 실제 SQL을 매개 변수와 별도로 전송하면 의도하지 않은 것으로 끝날 위험성을 제한 할 수 있습니다. 준비된 명령문을 사용할 때 보내는 모든 매개 변수는 단지 문자열로 취급됩니다 (데이터베이스 엔진이 매개 변수가 숫자로 끝날 수 있도록 일부 최적화를 수행 할 수도 있음). 위의 예에서$name
변수가 들어 있습니다.'Sarah'; DELETE FROM employees
결과는 단순히 문자열 검색입니다."'Sarah'; DELETE FROM employees"
, 너는 끝내지 않을거야.빈 테이블.
준비된 명령문을 사용하는 또 다른 이점은 동일한 세션에서 동일한 명령문을 여러 번 실행하면 구문 분석 및 컴파일이 한 번만 수행되어 속도가 약간 향상된다는 것입니다.
아, 그리고 삽입을 위해 어떻게해야하는지에 대해 물어 본 이래로, 여기에 (PDO를 사용하는) 예가 있습니다 :
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute(array('column' => $unsafeValue));
쿼리 매개 변수에 대해 준비된 문을 계속 사용할 수는 있지만 동적 쿼리 자체의 구조는 매개 변수화 할 수 없으며 특정 쿼리 기능을 매개 변수화 할 수 없습니다.
이러한 특정 시나리오의 경우 가능한 값을 제한하는 화이트리스트 필터를 사용하는 것이 가장 좋습니다.
// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
경고:이 답변의 샘플 코드 (예 : 질문의 샘플 코드)는 PHP의
MySQL
확장 기능은 PHP 5.5.0에서 더 이상 사용되지 않으며 PHP 7.0.0에서 완전히 제거되었습니다.
최근 버전의 PHP를 사용하고 있다면mysql_real_escape_string
아래에 설명 된 옵션은 더 이상 사용할 수 없습니다.mysqli::escape_string
현대 동등 물). 요즘에는mysql_real_escape_string
옵션은 구 버전의 PHP에서 레거시 코드에만 의미가 있습니다.
두 가지 옵션이 있습니다. 특수 문자를 이스케이프 처리하는 것입니다.unsafe_variable
, 또는 매개 변수가있는 쿼리를 사용합니다. 둘 다 SQL 주입으로부터 당신을 보호 할 것입니다. 매개 변수가있는 쿼리는 더 나은 방법으로 간주되지만 PHP를 사용하기 전에 PHP에서 새로운 MySQL 확장으로 변경해야합니다.
먼저 영향을 덜받는 문자열을 이스케이프 처리합니다.
//Connect
$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);
mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
//Disconnect
자세한 내용은mysql_real_escape_string
기능.
매개 변수가있는 쿼리를 사용하려면 다음을 사용해야합니다.MySQLi오히려MySQL기능. 예를 재 작성하려면 다음과 같은 것이 필요할 것입니다.
<?php
$mysqli = new mysqli("server", "username", "password", "database_name");
// TODO - Check that connection was successful.
$unsafe_variable = $_POST["user-input"];
$stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
// TODO check that $stmt creation succeeded
// "s" means the database expects a string
$stmt->bind_param("s", $unsafe_variable);
$stmt->execute();
$stmt->close();
$mysqli->close();
?>
거기에서 읽을 핵심 기능은 다음과 같습니다.mysqli::prepare
.
또한 다른 사람들이 제안했듯이 추상화 레이어를 유용하게 / 더 쉽게 찾을 수 있습니다.PDO.
요청한 사례는 매우 간단하며 복잡한 사례의 경우 더 복잡한 접근법이 필요할 수 있습니다. 특히:
mysql_real_escape_string
. 이런 경우에는 허용 된 값만 '안전'하도록 허용하기 위해 허용 목록을 통해 사용자 입력을 전달하는 것이 좋습니다.mysql_real_escape_string
접근 방식을 사용하면다항식아래의 코멘트에서. 정수는 따옴표로 묶이지 않기 때문에이 경우가 더 까다 롭습니다. 따라서 사용자 입력에 숫자 만 포함되어 있는지 확인하여 처리 할 수 있습니다.mysql_real_escape_string
충분합니까? 아니면 매개 변수화해야합니까? - peiman F.htmlentities
예를 들면 - Goufalitemysql_real_escape_string()
완전성을 위해,하지만 가장 오류가 발생하기 쉬운 방법을 먼저 나열하는 팬이 아닙니다. 독자는 첫 번째 예제를 빠르게 습득 할 수 있습니다. 지금은 더 이상 사용되지 않는 것이 좋습니다. :) - Time Sheep
모든 대답은 문제의 일부만을 다룹니다. 실제로, 거기있다네동적으로 추가 할 수있는 다른 쿼리 부분 : -
그리고 준비된 진술은 그 중 2 개만을 다루고 있습니다.
그러나 때로는 연산자 나 식별자를 추가하여 쿼리를 더욱 동적으로 만들어야합니다. 그래서, 우리는 다른 보호 기술이 필요합니다.
일반적으로, 그러한 보호 접근법은화이트리스트.
이 경우, 모든 동적 매개 변수는 스크립트에서 하드 코딩되어 해당 세트에서 선택되어야합니다. 예를 들어 동적 순서 지정을 수행하려면 다음을 수행하십시오.
$orders = array("name", "price", "qty"); // Field names
$key = array_search($_GET['sort'], $orders)); // See if we have such a name
$orderby = $orders[$key]; // If not, first one will be set automatically. smart enuf :)
$query = "SELECT * FROM `table` ORDER BY $orderby"; // Value is safe
그러나 식별자를 보호하는 또 다른 방법, 즉 이스케이프가 있습니다. 따옴표로 묶인 식별자가있는 한, 두 배로 역 따옴표를 이스케이프 할 수 있습니다.
추가 단계로, 준비된 문에서 일부 자리 표시 자 (쿼리의 실제 값을 나타 내기위한 프록시)를 사용하고 식별자 자리 표시자인 다른 유형의 자리 표시자를 만드는 진정한 아이디어를 빌릴 수 있습니다.
긴 이야기를 짧게하기 위해 :자리 표시 자, 아니라준비된 진술서은 총알로 간주 될 수 있습니다.
따라서 일반적인 추천은 다음과 같이 표현할 수 있습니다.자리 표시자를 사용하여 동적 파트를 쿼리에 추가하는 경우 (물론 이러한 올바르게 처리 된 자리 표시 자) 쿼리가 안전하다는 것을 확신 할 수 있습니다.
여전히 SQL 구문 키워드에 문제가 있습니다 (예 :AND
,DESC
그리고 그런 경우), 화이트리스트는이 경우 유일한 접근 방법 인 것처럼 보입니다.
SQL 주입 보호와 관련한 모범 사례에 대한 일반적인 합의가 있지만여전히 많은 나쁜 습관들.그리고 그들 중 일부는 PHP 사용자의 마음에 너무 뿌리 깊게 뿌리 내리고 있습니다. 예를 들어, 바로이 페이지에는 (대부분의 방문자에게는 보이지 않지만)80 개 이상의 삭제 된 답변- 품질이 좋지 않거나 나쁘고 오래된 관행을 조장하여 커뮤니티에서 제거한 모든 것. 더 나쁜 것은 나쁜 대답의 일부는 삭제되지 않고 번성하는 것입니다.
예를 들어,거기 (1) (2) 아직도 (3) 많은 (4) 답변 (5), 포함하는두 번째로 가장 많은 upvoted 대답당신에게 수동 문자열 이스케이프 - 안전하지 않은 것으로 입증 된 구식 접근법을 제안합니다.
아니면 조금 더 나은 대답이 있습니다.문자열 형식화의 또 다른 방법심지어 궁극의 만병 통치약으로 그것을 자랑합니다. 물론, 그렇지 않습니다. 이 방법은 일반 문자열 형식보다 낫지 만 모든 단점을 유지합니다. 문자열에만 적용 할 수 있으며 다른 수동 형식과 마찬가지로 본질적으로 선택적이며 비 강제적 인 방법이므로 사람의 실수가 발생하기 쉽습니다.
나는이 모든 것이 매우 오래된 미신 때문에 그런 권위자들에 의해지지받는다고 생각한다.OWASP또는PHP 매뉴얼어떤 "탈출"과 SQL 주입으로부터의 보호 사이의 평등을 선언합니다.
PHP 매뉴얼이 여러 해 동안 언급 한 것에 관계없이,*_escape_string
결코 데이터를 안전하게 만든다.결코 의도 된 것이 아닙니다. 문자열이 아닌 다른 SQL 부분에서는 쓸모가 없으며 수동 이탈은 잘못되었습니다.
그리고 OWASP는 더욱 악화되어 탈출을 강조합니다.사용자 입력완전한 넌센스입니다. 주입 방지의 맥락에서 그러한 단어가 없어야합니다. 모든 변수는 잠재적으로 위험합니다 - 소스에 관계없이! 또는 다시 말하면, 모든 변수는 소스에 상관없이 쿼리에 넣기 위해 올바른 형식을 가져야합니다. 중요한 곳입니다. 개발자가 양과 염소를 분리하기 시작한 순간 (특정 변수가 안전한지 아닌지를 생각할 때) 재난을 향한 첫 발걸음을 내딛습니다. 심지어 말씨조차도 진입 점에서 일괄 탈출을 제안합니다. 이미 마술 인용 부호 기능을 닮았습니다. 이미 멸시를 받았으며 삭제되었습니다.
그래서, 어떤 "탈출"과는 달리, 준비된 진술~이다.실제로 SQL 주입 (해당되는 경우)으로부터 보호하는 측정 값입니다.
아직 확신이 없다면 여기에 제가 쓴 단계별 설명이 있습니다.히치하이커의 SQL 주입 방지 가이드여기서 나는이 모든 문제를 자세히 설명하고 심지어 나쁜 습관과 공개에 전적으로 헌신하는 섹션을 작성했습니다.
FILTER_SANITIZE_NUMBER_INT
숫자 문자 만 허용하므로 전체 문자열이 아닌 흰색 문자를 나열 할 수 있습니다. 준비된 진술과 함께 좋은 "벨트 및 멜빵"을 만듭니다. 접근. - Sablefoste
사용하는 것이 좋습니다.PDO(PHP Data Objects)를 사용하여 매개 변수화 된 SQL 쿼리를 실행합니다.
SQL 인젝션을 방지 할뿐만 아니라 쿼리 속도를 높입니다.
그리고 PDO 대신에mysql_
,mysqli_
, 및pgsql_
함수를 사용하면 드물게 데이터베이스 공급자를 전환해야하는 상황에서 데이터베이스에서 앱을 좀 더 추상화 할 수 있습니다.
order by
불행히도 :( - Horse
용도PDO
준비된 쿼리.
($conn
~이다.PDO
목적)
$stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->execute();
보시다시피 사람들은 준비된 문장을 최대한 사용하는 것이 좋습니다. 그것은 잘못이 아니지만 쿼리가 실행될 때딱 한번프로세스 당 약간의 성능 저하가있을 수 있습니다.
나는이 문제에 직면했다. 그러나 나는 그것을 해결했다고 생각한다.대단히정교한 방법 - 해커가 따옴표 사용을 피하는 방법 필자는 에뮬레이트 된 준비 문과 함께이 기능을 사용했습니다. 나는 그것을 방지하기 위해 사용한다.모든가능한 SQL 주입 공격의 종류.
입력이 정수가 될 것으로 예상되면정말정수. PHP와 같은 변수 형 언어에서는대단히중대한. 예를 들어 매우 간단하면서도 강력한 솔루션을 사용할 수 있습니다.sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
정수에서 다른 것을 기대한다면16 진수. 16 진수라면 모든 입력을 완벽하게 피할 수 있습니다. C / C ++에는 다음과 같은 함수가 있습니다.mysql_hex_string()
, PHP에서 사용할 수 있습니다bin2hex()
.
이스케이프 된 문자열은 원래 길이의 2 배 크기이므로 걱정하지 마십시오.mysql_real_escape_string
, PHP는 같은 용량을 할당해야한다.((2*input_length)+1)
, 그것은 동일합니다.
이 16 진수 메서드는 이진 데이터를 전송할 때 자주 사용되지만 SQL 주입 공격을 막기 위해 모든 데이터에 사용하지 않아도됩니다. 데이터를 앞에 추가해야합니다.0x
또는 MySQL 함수를 사용하십시오.UNHEX
대신.
예를 들어, 쿼리는 다음과 같습니다.
SELECT password FROM users WHERE name = 'root'
될 것입니다:
SELECT password FROM users WHERE name = 0x726f6f74
또는
SELECT password FROM users WHERE name = UNHEX('726f6f74')
16 진수는 완벽한 탈출구입니다. 주사 할 방법이 없어.
코멘트에 약간의 토론이 있었기 때문에 나는 그것을 명확하게 밝히고 싶습니다. 이 두 가지 접근법은 매우 유사하지만 몇 가지면에서 조금 다릅니다.
** 0x ** 접두사는 다음과 같은 데이터 열에 만 사용할 수 있습니다.char, varchar, 텍스트, 블록, 바이너리 등.
또한 빈 문자열을 삽입하려는 경우 약간 복잡합니다. 당신은 완전히 그것을 대체해야합니다.''
, 또는 오류가 발생합니다.
UNHEX ()~에서 작동하다어떤기둥; 빈 문자열에 대해 걱정할 필요가 없습니다.
이 hex 메서드는 정수가 문자열과 같고 이스케이프 된 경우 SQL 주입 공격으로 자주 사용됩니다mysql_real_escape_string
. 그런 다음 따옴표를 사용하지 않아도됩니다.
예를 들어, 다음과 같이하면됩니다.
"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
공격은 당신을 매우 주입시킬 수있다.용이하게. 스크립트에서 반환 된 다음 주입 코드를 고려하십시오.
SELECT ... WHERE id =-1 유니온 모두 information_schema.tables에서 table_name을 선택하십시오.
이제 테이블 구조 만 추출하면됩니다.
SELECT ... where id = -1 union 모두 information_schema.column의 column_name을 선택하십시오. 여기서 table_name =0x61727469636c65
그리고 원하는 데이터를 선택하십시오. 멋지지 않니?
그러나 주 사용 사이트의 코더가 16 진수 일 경우, 쿼리가 다음과 같을 수 있으므로 주입 할 수 없습니다.SELECT ... WHERE id = UNHEX('2d312075...3635')
+
하지만 함께CONCAT
. 그리고 성능 : mysql은 데이터를 파싱해야하기 때문에 성능에 영향을 미쳤다고 생각합니다. 근원이 문자열 또는 16 진수이면 문제가되지 않습니다. - Zaffy'root'
또는 16 진수 수 있습니다.0x726f6f74
하지만 숫자를 원하면 문자열로 보내면 & # 39; 42 & # 39; CHAR (42) ... & # 42; & # 39; 16 진수는0x3432
아니0x42
- ZaffySELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')
- Zaffy
중대한
SQL 삽입을 방지하는 가장 좋은 방법은준비된 진술 탈출하는 대신, 같이받아 들인 대답보여줍니다.
다음과 같은 라이브러리가 있습니다.Aura.Sql과EasyDB개발자는 준비된 문장을 더 쉽게 사용할 수 있습니다. 준비된 진술이 왜 더 나은지에 대해 자세히 알아 보려면SQL 삽입 중지, 인용하다이
mysql_real_escape_string()
우회로과최근에 WordPress의 유니 코드 SQL 주입 취약점이 수정되었습니다..
사출 방지 -mysql_real_escape_string ()
PHP는 이러한 공격을 막기 위해 특별히 제작 된 함수를 가지고 있습니다. 함수의 입소문 만 사용하면됩니다.mysql_real_escape_string
.
mysql_real_escape_string
는 MySQL 쿼리에 사용될 문자열을 취하여 모든 SQL 삽입 시도가 안전하게 이스케이프 된 상태에서 동일한 문자열을 반환합니다. 기본적으로 사용자가 MySQL 안전 대체품 인 이스케이프 된 견적으로 입력 할 수있는 번거로운 따옴표 ( ')를 대체합니다.
노트:이 기능을 사용하려면 데이터베이스에 연결해야합니다!
// MySQL에 연결
$name_bad = "' OR 1'";
$name_bad = mysql_real_escape_string($name_bad);
$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";
$name_evil = "'; DELETE FROM customers WHERE 1 or username = '";
$name_evil = mysql_real_escape_string($name_evil);
$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;
자세한 내용은에서 찾을 수 있습니다.MySQL - SQL 인젝션 방지.
mysql_real_escape_string
목적은 모든 입력 데이터 문자열에 대해 올바른 SQL 쿼리를 작성할 수있게합니다. 예방 SQL 주입은이 함수의 부작용입니다. - sectusmysql_real_escape_string()
틀림 없다. - eggyalmysql_real_escape_string
이제는 더 이상 사용할 수없는 옵션이므로 더 이상 사용되지 않습니다. 앞으로 PHP에서 제거 될 것입니다. PHP 또는 MySQL 사람들이 권장하는 것에 최선을 다할 것입니다. - jww
보안 경고:이 답변은 보안 모범 사례와 일치하지 않습니다.이스케이프는 SQL 인젝션을 방지하기에 부적합합니다., 사용하다준비된 진술대신. 아래에 설명 된 전략을 따른다는 위험 부담이 있습니다. (또한,
mysql_real_escape_string()
PHP 7에서 삭제되었습니다.)
다음과 같이 기본적인 것을 할 수 있습니다 :
$safe_variable = mysql_real_escape_string($_POST["user-input"]);
mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
이것은 모든 문제를 해결하지는 못하지만 아주 좋은 디딤돌입니다. 변수의 존재, 형식 (숫자, 문자 등)을 검사하는 것과 같은 명백한 항목은 생략했습니다.
$q = "SELECT col FROM tbl WHERE x = $safe_var";
예를 들면. 환경$safe_var
에1 UNION SELECT password FROM users
이 경우 따옴표가 없기 때문에 작동합니다. 다음을 사용하여 문자열을 검색어에 삽입 할 수도 있습니다.CONCAT
과CHR
. - Polynomialmysql_real_escape_string()
틀림 없다. - eggyalmysql_real_escape_string
이제는 더 이상 사용할 수없는 옵션이므로 더 이상 사용되지 않습니다. 앞으로 PHP에서 제거 될 것입니다. PHP 또는 MySQL 사람들이 권장하는 것에 최선을 다할 것입니다. - jww
당신이 무엇을 사용하든, 입력이 이미 맹 글링되지 않았는지 확인하십시오.magic_quotes
또는 다른 어떤 의미있는 쓰레기가 있다면, 필요하다면stripslashes
또는 그것을 위생적으로하는 것이 무엇이든간에.
매개 변수화 된 쿼리 및 입력 유효성 검사가 필요합니다. SQL 주입이 발생할 수있는 시나리오는 많이 있지만mysql_real_escape_string()
사용 되왔다.
이러한 예제는 SQL 삽입에 취약합니다.
$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");
또는
$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");
두 경우 모두 사용할 수 없습니다.'
캡슐화를 보호합니다.
출처:예기치 않은 SQL 삽입 (이스 케이 핑이 충분하지 않을 때)
필자의 의견으로는 PHP 애플리케이션 (또는 웹 애플리케이션)에서 일반적으로 SQL 삽입을 방지하는 가장 좋은 방법은 애플리케이션의 아키텍처를 생각하는 것이다. SQL 인젝션으로부터 보호 할 수있는 유일한 방법은 데이터베이스와 대화 할 때마다 올바른 기능을 수행하는 특별한 방법이나 기능을 사용하는 것을 잊지 않는 것입니다. 그렇게하면 코드의 어느 시점에서 쿼리의 형식을 올바르게 지정하지 않는 한 시간 문제 일뿐입니다.
MVC 패턴 및 프레임 워크 사용CakePHP또는CodeIgniter의아마도 적절한 방법 일 것입니다. 안전한 데이터베이스 쿼리 작성과 같은 일반적인 작업이 해결되어 이러한 프레임 워크에서 중앙에서 구현됩니다. 이 도구를 사용하면 웹 응용 프로그램을 합리적인 방법으로 구성하고 단일 SQL 쿼리를 안전하게 작성하는 것보다 객체 로딩 및 저장에 대해 더 많이 생각하게 할 수 있습니다.
나는 좋아한다.저장 프로 시저(MySQL은 5.0 이후 프로 시저 지원을 저장했다.) 보안 관점에서 - 장점은 -
단점은 -
SQL 인젝션 및 기타 SQL 해킹을 방지하는 데는 여러 가지 방법이 있습니다. 인터넷 (Google 검색)에서 쉽게 찾을 수 있습니다. 당연하지PDO는 좋은 솔루션 중 하나입니다.그러나 나는 SQL Injection에 대한 좋은 링크를 제안하고 싶습니다.
PHP의 SQL 주입 및 예방에 대한 Microsoft의 설명
그리고 다른 일부는MySQL과 PHP로 SQL 주입 방지하기
지금,SQL 인젝션으로부터 쿼리를 보호해야하는 이유는 무엇입니까?
다음과 같은 간단한 예제로 SQL 인젝션을 막으려 고 시도하는 이유는 무엇입니까?
로그인 인증 일치에 대한 쿼리 :
$query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";
자, 누군가 (해커)가
$_POST['email']= admin@emali.com' OR '1=1
비밀 번호를 ....
쿼리는 다음과 같은 경우에만 시스템에 구문 분석됩니다.
$query="select * from users where email='admin@emali.com' OR '1=1';
다른 부분은 폐기됩니다. 그래서, 어떻게 될까요? 승인되지 않은 사용자 (해커)는 비밀번호가 없어도 관리자로 로그인 할 수 있습니다. 이제 그는 관리자 / 전자 메일 사용자가 할 수있는 모든 작업을 수행 할 수 있습니다. SQL 주입을 막지 않으면 매우 위험합니다.
나는 누군가가 PHP와 MySQL 또는 다른 데이터베이스 서버를 사용하기를 원한다면 나는 생각한다.
(int)$foo
. PHP에서 변수 유형에 대해 더 자세히 읽어보십시오.이리. PDO 또는 MySQLi와 같은 라이브러리를 사용하는 경우 항상PDO :: quote ()과mysqli_real_escape_string ().라이브러리 예제 :
----PDO
----- 자리 표시 자 없음 - SQL 주입에 익숙합니다!그것은 나쁜
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");
----- 이름없는 자리 표시 자
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);
----- 명명 된 자리 표시 자
$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");
---MySQLi
$request = $mysqliConnection->prepare('
SELECT * FROM trainers
WHERE name = ?
AND email = ?
AND last_login > ?');
$query->bind_param('first_param', 'second_param', $mail, time() - 3600);
$query->execute();
추신:
PDO는이 전투에서 쉽게 승리합니다. 열 두 개를 지원합니다. 다른 데이터베이스 드라이버와 명명 된 매개 변수는 무시할 수 있습니다. 작은 성능 손실을 경험하고 API에 익숙해집니다. 보안에서 관점에서 볼 때 개발자가 사용하는 한 둘 다 안전합니다. 그들이 사용되기로되어있는 길
그러나 PDO와 MySQLi 모두 매우 빠르지 만 MySQLi는 벤치 마크에서 미미하게 더 빠름 - 준비되지 않은 경우 ~ 2.5 % 진술서, ~ 준비된 환자의 ~ 6.5 %.
그리고 모든 쿼리를 데이터베이스에 테스트하십시오. 이것은 주사를 방지하는 더 좋은 방법입니다.
가능한 경우 매개 변수의 유형을 형변환하십시오. 하지만 int, bool 및 float와 같은 간단한 유형에서만 작동합니다.
$unsafe_variable = $_POST['user_id'];
$safe_variable = (int)$unsafe_variable ;
mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
캐시 엔진을 활용하려는 경우레디 스또는Memcached아마도 DALMP가 선택 일 수 있습니다. 그것은 순수를 사용합니다.MySQLi. 이것을 확인하십시오 :PHP를 사용하는 MySQL 용 DALMP 데이터베이스 추상화 계층.
또한 동적 u 리를 빌드 할 수 있도록 u 리를 준비하기 전에 인수를 '준비'할 수 있으며 결국에는 완전히 준비된 명령문 u 리를 갖습니다.PHP를 사용하는 MySQL 용 DALMP 데이터베이스 추상화 계층.
PDO 사용 방법을 잘 모르는 사람들을 위해 (mysql_
함수), 나는매우 간단한 PDO wrapper그것은 하나의 파일입니다. 응용 프로그램을 수행하는 데 필요한 모든 일반적인 작업을 수행하는 것이 얼마나 쉬운지를 보여주기 위해 존재합니다. PostgreSQL, MySQL 및 SQLite에서 작동합니다.
기본적으로 그것을 읽으십시오.당신이 매뉴얼을 읽는 동안실생활에서 사용하기 위해 PDO 함수를 두는 방법을 알아서 형식의 값을 저장하고 검색하는 것을 간단하게하십시오.당신필요.
나는 하나의 칼럼을 원한다.
$count = DB::column('SELECT COUNT(*) FROM `user`);
배열 (키 => 값) 결과 (즉, 선택 상자 만들기)가 필요합니다.
$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);
단일 행 결과를 원합니다.
$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));
나는 일련의 결과를 원한다.
$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));
이 PHP 함수 사용하기mysql_escape_string()
당신은 빠른 방법으로 좋은 예방을 얻을 수 있습니다.
예 :
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'
mysql_escape_string
- mysql_query에서 사용할 문자열 이스케이프
더 많은 예방을 위해 마지막에 추가 할 수 있습니다 ...
wHERE 1=1 or LIMIT 1
마지막으로 다음을 얻습니다.
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1
SQL 문에서 특수 문자를 이스케이프 처리하기위한 몇 가지 지침.
사용하지 마십시오.MySQL이 확장 프로그램은 더 이상 사용되지 않습니다.MySQLi또는PDO.
MySQLi
문자열의 특수 문자를 수동으로 이스케이프 처리하려면mysqli_real_escape_string기능. 올바른 문자 집합을 사용하지 않으면 함수가 제대로 작동하지 않습니다.mysqli_set_charset.
예:
$mysqli = new mysqli( 'host', 'user', 'password', 'database' );
$mysqli->set_charset( 'charset');
$string = $mysqli->real_escape_string( $string );
$mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );
준비된 명령문을 사용하여 값을 자동으로 이스케이프하려면 다음을 사용하십시오.mysqli_prepare, 및mysqli_stmt_bind_param여기서 적절한 바인드 변수의 유형은 적절한 변환을 위해 제공되어야합니다.
예:
$stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );
$stmt->bind_param( "is", $integer, $string );
$stmt->execute();
prepared statement 나 mysqli_real_escape_string을 사용하든 관계없이 항상 작업중인 입력 데이터의 유형을 알아야합니다.
따라서 준비된 문장을 사용한다면, mysqli_stmt_bind_param 함수를위한 변수의 타입을 지정해야한다.
mysqli_real_escape_string의 사용은 이름에서 알 수 있듯이 문자열에서 특수 문자를 이스케이프 처리하므로 정수가 안전하지 않을 수 있습니다. 이 함수의 목적은 SQL.에서. 자열을 손상시키지 못하게하고 데이터베이스의 손상을 f 지하기위한 것입니다. mysqli_real_escape_string은 특히 sprintf와 함께 사용할 때 유용하게 사용된다.
예:
$string = "x' OR name LIKE '%John%";
$integer = '5 OR id != 0';
$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5
$integer = '99999999999999999999';
$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647
이 문제에 대한 간단한 대안은 데이터베이스 자체에 적절한 권한을 부여하여 해결할 수 있습니다. 예 : MySQL 데이터베이스를 사용하는 경우 터미널이나 제공된 UI를 통해 데이터베이스에 들어가 다음 명령을 따르십시오.
GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';
이렇게하면 사용자는 지정된 쿼리에만 국한 될 수 있습니다. 삭제 권한을 제거하면 PHP 페이지에서 실행 된 쿼리에서 데이터가 삭제되지 않습니다. 두 번째로해야 할 일은 권한을 플러시하여 MySQL이 권한과 업데이트를 새로 고치는 것입니다.
FLUSH PRIVILEGES;
추가 정보플러시.
사용자에 대한 현재 권한을 보려면 다음 쿼리를 실행하십시오.
select * from mysql.user where User='username';
더 자세히 알아보기부여.
웹 응용 프로그램이 SQL 주입에 취약하지 않도록 세 가지 방법을 사용합니다.
mysql_real_escape_string()
, 이는 사전 정의 된 함수입니다.PHP이 코드는 다음 문자에 백 슬래시를 추가합니다.\x00
,\n
,\r
,\
,'
,"
과\x1a
. 입력 값을 매개 변수로 전달하여 SQL 주입 가능성을 최소화하십시오.이게 당신을 도울 수 있기를 바랍니다.
다음 쿼리를 고려하십시오.
$iId = mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";
mysql_real_escape_string ()은 여기서 보호하지 않습니다. 쿼리 내에서 변수 주위에 작은 따옴표 ( '')를 사용하면이 문제를 방지 할 수 있습니다. 다음은이를위한 해결책입니다.
$iId = (int) mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";
이의문이것에 대해 좋은 답변을하고 있습니다.
PDO를 사용하는 것이 가장 좋은 방법이라고 제안합니다.
편집하다:
mysql_real_escape_string()
PHP 5.5.0부터는 더 이상 사용되지 않습니다. mysqli 또는 PDO를 사용하십시오.
mysql_real_escape_string ()의 대안은 다음과 같습니다.
string mysqli_real_escape_string ( mysqli $link , string $escapestr )
예:
$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");
간단한 방법은 PHP 프레임 워크를 사용하는 것입니다.CodeIgniter의또는Laravel필터링 및 액티브 레코드와 같은 내장 기능이있어 이러한 뉘앙스에 대해 걱정할 필요가 없습니다.
많은 유용한 답변과 관련하여이 스레드에 몇 가지 값을 추가하겠습니다. SQL 주입은 사용자 입력 (사용자가 입력 한 다음 쿼리 내부에서 사용되는 입력)을 통해 수행 할 수있는 공격입니다. SQL 주입 패턴은 올바른 쿼리 구문으로, 호출 할 수 있지만 나쁜 이유 때문에 잘못된 쿼리가있을 수 있습니다. 보안 (기밀성, 무결성, 가용성)의 세 가지 원칙에 영향을주는 비밀 정보 (액세스 제어 무시)를 얻으려는 나쁜 사람입니다.
이제 우리의 요점은 SQL 인젝션 공격과 같은 보안 위협, PHP를 사용하는 SQL 인젝션 공격을 막는 방법, 더 현실적인 것, 데이터 필터링 또는 입력 데이터 소거와 같은 보안 문제를 방지하는 것입니다. PHP 또는 다른 프로그래밍 언어를 사용하는 쿼리가 아니거나 준비된 문이나 현재 SQL 주입 방지를 지원하는 다른 도구와 같은 최신 기술을 사용하도록 더 많은 사람들이 권장하는 방법으로 이러한 도구를 더 이상 사용할 수 없다고 생각합니까? 응용 프로그램 보안 방법
SQL 인젝션에 대한 나의 접근 방식은 사용자 입력 데이터를 데이터베이스로 보내기 전에 (모든 쿼리 내에서 사용하기 전에) 사용자 입력 데이터를 지우는 것입니다.
데이터 필터링 (안전하지 않은 데이터를 안전한 데이터로 변환)그것을 생각해 보라.PDO과MySQLi사용할 수없는 응용 프로그램은 어떻게 보호 할 수 있습니까? 당신이 나를 사용하도록 강요합니까? PHP 이외의 다른 언어는 어떻게됩니까? 특정 언어뿐만 아니라 더 넓은 범위의 테두리에 사용할 수있는 일반 아이디어를 제공하는 것을 선호합니다.
만나다최소 권한 원칙
데이터 필터링 : 쿼리 사용자 입력을 작성하기 전에 프로그래머에게 유효성을 검사하고 필터링해야하며 각 사용자 입력 변수에 대한 속성을 정의하는 것이 중요합니다.데이터 유형, 데이터 패턴 및 데이터 길이. (x와 y) 사이의 숫자 인 필드는 정확한 규칙을 사용하여 문자열 (텍스트) 인 필드에 대해 정확히 유효성을 검사해야합니다. 예를 들어, 패턴은 대소 문자를 포함해야합니다. [a- zA-Z0-9_-] 길이는 (x 및 n) (여기서 x 및 n은 정수, x≤n) 사이에서 변한다.규칙 : 정확한 필터 및 유효성 검사 규칙을 만드는 것이 나에게 가장 좋습니다.
다른 도구 사용 : 여기에서는 준비된 문 (매개 변수화 된 쿼리) 및 저장 프로 시저에 동의합니다. 단점은 이러한 방법은 대부분의 사용자에게는 존재하지 않는 고급 기술을 필요로한다는 것인데, 여기서 기본적인 개념은 SQL 쿼리 및 내부에서 사용되는 데이터를 사용하면 사용자 입력 데이터가 (any 또는 x = x와 같은) 원래 쿼리에 아무 것도 추가하지 않기 때문에 안전하지 않은 데이터에서도 두 가지 방법 모두 사용할 수 있습니다. 자세한 내용은 다음을 참조하십시오.OWASP SQL 인젝션 방지 컨닝 페이퍼.
이제 고급 사용자 인 경우이 방어 방법을 원하는대로 사용할 수 있지만 초보자는 저장 프로 시저를 신속하게 구현할 수없고 문을 준비 할 수없는 경우 입력 데이터를 가능한 한 많이 필터링하는 것이 좋습니다.
마지막으로, 사용자가 사용자 이름을 입력하는 대신이 텍스트를 아래에 보냈다고 가정 해 보겠습니다.
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
이 입력은 준비된 명령문 및 저장 프로 시저없이 초기에 검사 할 수 있지만 사용자 데이터 필터링 및 유효성 검사 후에 시작하는 것이 안전 측면에 있습니다.
마지막 요점은 더 많은 노력과 복잡성을 필요로하는 예기치 않은 동작을 감지하는 것입니다. 일반 웹 응용 프로그램에는 권장되지 않습니다. 위의 사용자 입력에서 예기치 않은 동작이 발생하면 SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, root가 검색되고 입력을 피할 수 있습니다.
사용자는이 게시물이 쓸모 없다고 댓글을 달았습니다. 여기에OWASP.ORG제공 :
기본 방어 :
옵션 # 1 : 준비된 문 사용 (매개 변수가있는 쿼리)
옵션 # 2 : 저장 프로 시저 사용
옵션 # 3 : 모든 사용자 제공 입력 이스케이프
추가 방어 :
또한 시행 : 최소 권한
또한 수행 : 화이트리스트 입력 검증
아시다시피, 기사를 주장하는 것은 유효한 논증, 최소한 하나의 참고 문헌에 의해 뒷받침되어야합니다! 그렇지 않으면 공격과 나쁜 주장으로 간주됩니다!
PHP 매뉴얼에서,PHP : Prepared Statements - Manual:
도주 및 SQL 주입
바운드 변수는 서버에 의해 자동으로 이스케이프됩니다. 그만큼 서버는 이스케이프 된 값을 적절한 위치에 실행 전 명령문 템플릿. 힌트는 바인딩 된 변수 유형에 맞는 서버를 생성하여 적절한 변환. 더 자세한 정보는 mysqli_stmt_bind_param () 함수를 참고하십시오. 정보.
서버 내에서 자동으로 값을 이스케이프 처리하는 경우가 있습니다. SQL 주입을 방지하는 보안 기능을 고려했습니다. 똑같다 다음과 같은 경우 준비되지 않은 명령문을 사용하여 보안 등급을 얻을 수 있습니다. 입력 값이 올바르게 이스케이프됩니다.
준비된 명령문을 사용할 때 PDO와 MySQLi가 MySQL 서버에 쿼리를 보내는 방법을 알기위한 테스트 케이스를 만들었습니다.
PDO :
$user = "''1''"; //Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
검색어 로그 :
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\'' 189 Quit
MySQLi :
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
검색어 로그 :
188 Prepare SELECT * FROM awa_user WHERE username =? 188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\'' 188 Quit
위 성명서에서도 언급했듯이The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly
따라서 이것은 다음과 같은 데이터 유효성 검사가intval()
쿼리를 보내기 전에 정수 값에 대한 좋은 아이디어이며, 또한 쿼리를 보내기 전에 악의적 인 사용자 데이터를 방지합니다.정확하고 유효한 접근법.
자세한 내용은이 질문을 참조하십시오.PDO가 원시 쿼리를 MySQL로 보내고 Mysqli가 준비된 쿼리를 보내면 동일한 결과가 생성됩니다.
참고 문헌 :
** 경고 :이 답변에 설명 된 접근법은 매우 특정한 시나리오에만 적용되며 SQL 주입 공격은 주입 할 수있는 것에 의존하지 않으므로 안전하지 않습니다.X=Y
. **
공격자가 PHP를 통해 양식을 해킹하려는 경우$_GET
변수 또는 URL의 쿼리 문자열을 사용하면 보안되지 않은 항목을 잡을 수 있습니다.
RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php
때문에1=1
,2=2
,1=2
,2=1
,1+1=2
, 등 ...은 공격자의 SQL 데이터베이스에 대한 일반적인 질문입니다. 어쩌면 그것은 또한 많은 해킹 응용 프로그램에 의해 사용됩니다.
그러나주의해야합니다. 사이트에서 안전한 쿼리를 다시 작성하면 안됩니다. 위 코드는 다시 작성하거나 리디렉션 할 수있는 팁을 제공합니다.(이것은 너에게 달려있어)해킹 관련 동적 쿼리 문자열을 공격자의IP 주소또는 쿠키, 역사, 브라우저 또는 기타 민감한 정보가 포함되어 있으므로 나중에 계정을 금지하거나 관계 당국에 문의하여 거래 할 수 있습니다.
많은 답변이 있습니다.PHP와 MySQL,하지만 여기에 대한 코드입니다PHP와 오라클oci8 드라이버의 일반적인 사용뿐만 아니라 SQL 삽입을 방지하기 위해 :
$conn = oci_connect($username, $password, $connection_string);
$stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
oci_bind_by_name($stmt, ':xx', $fieldval);
oci_execute($stmt);
좋은 아이디어는'객체 - 관계형 매퍼'처럼이디엄:
$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();
$user->first_name = 'Jamie';
$user->save();
$tweets = ORM::for_table('tweet')
->select('tweet.*')
->join('user', array(
'user.id', '=', 'tweet.user_id'
))
->where_equal('user.username', 'j4mie')
->find_many();
foreach ($tweets as $tweet) {
echo $tweet->text;
}
SQL 인젝션뿐만 아니라 구문 오류로부터도 당신을 구할 수 있습니다! 또한 메서드 체인을 사용하여 한 번에 여러 결과에 대한 작업을 필터링하거나 적용 할 수있는 모델 모음을 지원합니다.
사용PDO과MYSQLiSQL 인젝션을 방지하는 좋은 방법이지만, MySQL 함수와 쿼리로 작업하고 싶다면 다음을 사용하는 것이 좋습니다.
$unsafe_variable = mysql_real_escape_string($_POST['user_input']);
ident처럼 - 입력이 문자열, 숫자, 문자 또는 배열이면 이것을 탐지하는 많은 내장 함수가 있습니다. 또한 이러한 기능을 사용하여 입력 데이터를 확인하는 것이 좋습니다.
$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');
$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');
그리고 이러한 기능을 사용하여 입력 데이터를 확인하는 것이 훨씬 낫습니다.mysql_real_escape_string
.
mysql_real_escape_string()
틀림 없다. - eggyalmysql_real_escape_string
이제는 더 이상 사용할 수없는 옵션이므로 더 이상 사용되지 않습니다. 앞으로 PHP에서 제거 될 것입니다. PHP 또는 MySQL 사람들이 권장하는 것에 최선을 다할 것입니다. - jww
몇 년 전에이 작은 기능을 작성했습니다.
function sqlvprintf($query, $args)
{
global $DB_LINK;
$ctr = 0;
ensureConnection(); // Connect to database if not connected already.
$values = array();
foreach ($args as $value)
{
if (is_string($value))
{
$value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
}
else if (is_null($value))
{
$value = 'NULL';
}
else if (!is_int($value) && !is_float($value))
{
die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
}
$values[] = $value;
$ctr++;
}
$query = preg_replace_callback(
'/{(\\d+)}/',
function($match) use ($values)
{
if (isset($values[$match[1]]))
{
return $values[$match[1]];
}
else
{
return $match[0];
}
},
$query
);
return $query;
}
function runEscapedQuery($preparedQuery /*, ...*/)
{
$params = array_slice(func_get_args(), 1);
$results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results.
return $results;
}
이렇게하면 한 줄짜리 C #에서 String.Format과 같은 문을 실행할 수 있습니다.
runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);
그것은 가변 타입을 고려하여 빠져 나간다. 테이블, 열 이름을 매개 변수화하려고하면 모든 문자열을 잘못된 구문 인 따옴표로 묶으므로 실패합니다.
보안 업데이트 : 이전str_replace
버전은 {#} 토큰을 사용자 데이터에 추가하여 주입을 허용했습니다. 이preg_replace_callback
교체에 이러한 토큰이 포함되어 있으면 버전에서 문제가 발생하지 않습니다.