programing

PHP에서 SQL 주입을 방지하려면 어떻게 해야 합니까?

prostudy 2022. 9. 8. 17:42
반응형

PHP에서 SQL 주입을 방지하려면 어떻게 해야 합니까?

사용자 입력을 수정하지 않고 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에서 분리하여 데이터가 그대로 유지되고 SQL 파서에 의해 명령어로 해석되지 않도록 하는 것입니다.올바른 형식의 데이터 부분을 사용하여 SQL 문을 만들 수 있지만 세부 정보를 완전히 이해하지 못할 경우 항상 준비된 문과 매개 변수화된 쿼리를 사용해야 합니다.데이터베이스 서버에서 매개 변수와 별도로 전송 및 구문 분석되는 SQL 문입니다.이렇게 하면 공격자가 악의적인 SQL을 주입할 수 없습니다.

여기에는 기본적으로 다음 두 가지 옵션이 있습니다.

  1. PDO 사용(지원되는 데이터베이스 드라이버의 경우):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    $stmt->execute([ 'name' => $name ]);
    
    foreach ($stmt as $row) {
        // Do something with $row
    }
    
  2. 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수 의 두 들어 MySQL의 경우, MySQL의 경우, 2의 경우).pg_prepare() ★★★★★★★★★★★★★★★★★」pg_execute()(포스트) ( ) 입니다.PDO를 사용하다


올바른 연결 설정

PDO

PDO를 사용하여 MySQL 데이터베이스에 액세스하는 경우 real prepared 문은 기본적으로 사용되지 않습니다.이 문제를 해결하려면 준비된 문의 에뮬레이션을 비활성화해야 합니다.PDO를 사용하여 연결을 만드는 예는 다음과 같습니다.

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8mb4', 'user', 'password');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

위의 예에서는 에러 모드가 반드시 필요한 것은 아니지만 추가하는 것이 좋습니다.이 방법을 통해 PDO는 모든 MySQL 오류를 사용자에게 알립니다.PDOException.

단, 의무적인 것은 첫 번째입니다.setAttribute()line: PDO에 대해 에뮬레이트된 준비된 문을 비활성화하고 실제 준비된 문을 사용하도록 지시합니다.그러면 문장 및 값이 MySQL 서버로 전송되기 전에 PHP에 의해 구문 분석되지 않습니다(가능한 공격자가 악의적인 SQL을 주입할 기회는 없습니다).

,는할 수 ,charset컨스트럭터의 옵션에서는 PHP의 '오래된' 버전(5.3.6 이전)이 DSN의 charset 파라미터를 무시한 것에 주의해 주십시오.

미스크리

mysqli의 경우 동일한 절차를 따라야 합니다.

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // error reporting
$dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test');
$dbConnection->set_charset('utf8mb4'); // charset

설명.

에 하는 SQL 문prepare는 데이터베이스 서버에 의해 해석 및 컴파일됩니다.으로써( 「」의 를 지정합니다).? 변수, 예를 들어주세요.:name위의 예에서) 필터링할 위치를 데이터베이스 엔진에 지시합니다. 나서, 이 전화했을 때.execute준비된 문은 지정한 파라미터 값과 조합됩니다.

여기서 중요한 것은 파라미터 값이 SQL 문자열이 아닌 컴파일된 문과 결합된다는 것입니다.SQL 주입은 스크립트가 데이터베이스로 전송할 SQL을 만들 때 악의적인 문자열을 포함하도록 속이는 방식으로 작동합니다.따라서 실제 SQL을 매개 변수와 별도로 전송함으로써 의도하지 않은 결과가 발생할 위험을 줄일 수 있습니다.

준비된 스테이트먼트를 사용할 때 송신하는 파라미터는 모두 문자열로 취급됩니다(데이터베이스 엔진에서 최적화가 이루어지기 때문에 파라미터도 물론 수치로 간주될 수 있습니다).에서 " " "의 경우,$name는 variable수음음음음음음음음 variable variable variable variable variable variable를 포함합니다.'Sarah'; DELETE FROM employees는 단순히 일 뿐입니다."'Sarah'; DELETE FROM employees"빈 테이블이 되는 일은 없습니다.

준비된 문을 사용하는 또 다른 장점은 같은 세션에서 여러 번 실행할 경우 구문 분석과 컴파일이 한 번만 수행되므로 속도가 향상된다는 것입니다.

아, 인서트 방법에 대해 질문하셨으니 예를 들어보겠습니다(PDO 사용).

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute([ 'column' => $unsafeValue ]);

준비된 문을 동적 쿼리에 사용할 수 있습니까?

쿼리 파라미터에는 준비된 문을 사용할 수 있지만 동적 쿼리 구조 자체는 파라미터화할 수 없으며 특정 쿼리 기능을 파라미터화할 수 없습니다.

이러한 특정 시나리오에서는 가능한 값을 제한하는 화이트리스트 필터를 사용하는 것이 가장 좋습니다.

// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}

매개 변수화된 쿼리를 사용하려면 Mysqli 또는 PDO를 사용해야 합니다.mysqli로 예를 다시 쓰려면 다음과 같은 것이 필요합니다.

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("server", "username", "password", "database_name");

$variable = $_POST["user-input"];
$stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
// "s" means the database expects a string
$stmt->bind_param("s", $variable);
$stmt->execute();

여기서 설명하는 주요 기능은 입니다.

또한 다른 사람들이 제안했듯이 PDO와 같은 으로 추상화 층을 높이는 것이 유용하거나 더 쉽다는 것을 알 수 있습니다.

문의하신 케이스는 매우 단순한 케이스이며, 보다 복잡한 케이스는 보다 복잡한 접근법이 필요할 수 있습니다.특히:

  • 되지 않으며 에서 다루지 .mysql_real_escape_string이런 경우 사용자의 입력을 화이트리스트에 전달하여 '안전한' 값만 통과시키는 것이 좋습니다.

여기 있는 모든 답변은 문제의 일부만을 다루고 있습니다.실제로 SQL에 동적으로 추가할 수 있는 쿼리 부분은 4가지가 있습니다.-

  • 번호
  • 식별자
  • 구문 키워드

그리고 준비된 진술서는 그 중 단 두 가지에 불과합니다.

그러나 때로는 연산자 또는 식별자를 추가하여 쿼리를 더욱 역동적으로 만들어야 합니다.따라서 다른 보호 기술이 필요합니다.

일반적으로 이러한 보호 접근 방식은 화이트리스트에 기반합니다.

이 경우 스크립트에서 모든 다이내믹 파라미터를 하드코드하여 그 세트에서 선택해야 합니다.예를 들어, 동적 순서를 설정하려면:

$orders  = array("name", "price", "qty"); // Field names
$key = array_search($_GET['sort'], $orders)); // if we have such a name
$orderby = $orders[$key]; // If not, first one will be set automatically. 
$query = "SELECT * FROM `table` ORDER BY $orderby"; // Value is safe

프로세스를 쉽게 하기 위해 모든 작업을 한 줄로 처리하는 화이트리스트 도우미 기능을 작성했습니다.

$orderby = white_list($_GET['orderby'], "name", ["name","price","qty"], "Invalid field name");
$query  = "SELECT * FROM `table` ORDER BY `$orderby`"; // sound and safe

식별자를 보호하는 또 다른 방법이 있습니다.탈출이지만 저는 보다 강력하고 명시적인 접근법으로 화이트리스트에 있는 것을 고수합니다.그러나 따옴표로 묶인 식별자가 있으면 따옴표로 묶인 문자를 피해 안전하게 사용할 수 있습니다.예를 들어 mysql의 경우 기본적으로 따옴표를 두 번 눌러 이스케이프해야 합니다.다른 DBMS 이스케이프 규칙은 다릅니다.

SQL 키워드SQL」등.AND,DESC등) 하지만 이 경우에는 화이트 클로즈만이 유일한 접근법인 것 같습니다.

따라서 일반적인 권장사항은 다음과 같이 표현될 수 있습니다.

  • SQL 데이터 리터럴을 나타내는 변수(간단히 말하면 SQL 문자열 또는 숫자)는 준비된 문을 통해 추가해야 합니다.예외는 없습니다.
  • SQL 키워드, 테이블 또는 필드 이름 또는 연산자와 같은 다른 쿼리 부분은 화이트리스트를 통해 필터링해야 합니다.

갱신하다

SQL 주입 보호에 관한 베스트 프랙티스에 대한 일반적인 합의는 있지만 여전히 많은 나쁜 프랙티스가 있습니다.그 중 일부는 PHP 사용자의 마음에 너무 깊이 뿌리박고 있다.예를 들어, 바로 이 페이지에는 (대부분 방문자에게는 보이지 않지만) 80개 이상의 삭제된 답변이 있습니다.이들 답변은 모두 품질이 나쁘거나 악질적이고 시대에 뒤떨어진 관행을 조장하기 위해 커뮤니티에 의해 삭제되었습니다.설상가상으로, 일부 오답은 삭제되지 않고 오히려 번창하고 있다.

를 들어, (2) still(3) many(4) answer(5)있습니다.여기에는 수동 스트링 이스케이프를 시사하는 두 번째로 높은 응답도 포함되어 있습니다.이것은 안전하지 않은 것으로 판명된 오래된 접근법입니다.

아니면 현악기 포맷의 또 다른 방법을 제안하고 궁극의 만병통치약이라고 자랑하는 조금 더 나은 답이 있다.물론 그렇지 않습니다.이 방법은 일반 문자열 형식과 다를 바 없지만 모든 단점을 유지합니다. 즉, 문자열에만 적용 가능하며 다른 수동 형식과 마찬가지로 기본적으로 임의이며 의무적이지 않으며 어떠한 종류의 인위적 오류도 발생하기 쉽습니다.

이 모든 것은 OWASP나 PHP 매뉴얼같은 당국으로부터 지지를 받고 있는 매우 오래된 미신 때문인 것 같습니다.이 미신은 SQL 주입으로부터 "회피"와 보호 사이의 평등을 선언합니다.

PHP 매뉴얼이 오랫동안 설명한 내용과 상관없이 데이터를 안전하게 하거나 의도한 적이 없습니다.수동 이스케이프는 문자열 이외의 SQL 부분에서는 사용할 수 없을 뿐만 아니라 자동화와는 반대로 수동이기 때문에 잘못된 것입니다.

게다가 OWASP는, 유저의 입력을 회피하는 것을 강조해, 한층 더 상황을 악화시키고 있습니다.이것은 전혀 말도 안 되는 것입니다.주입 보호의 맥락에서는 이러한 단어를 사용할 수 없습니다.모든 변수는 잠재적으로 위험합니다. 출처와 상관없이!즉, 소스에 관계없이 모든 변수는 쿼리에 넣기 위해 올바른 형식을 가져야 합니다.중요한 것은 목적지다.개발자가 양과 염소를 분리하는 순간(특정 변수가 '안전성'인지 아닌지를 생각하면서) 재앙을 향해 첫발을 내딛는다.이 문구조차도 이미 경멸, 비호감, 제거된 마법의 인용 기능과 유사한 입구에서의 대량 탈출을 시사하는 것은 말할 것도 없습니다.

따라서 "회피"와는 달리 준비된 문장은 SQL 주입(해당하는 경우)으로부터 보호하는 수단입니다.

PDO(PHP Data Objects)를 사용하여 매개 변수화된 SQL 쿼리를 실행하는 것이 좋습니다.

SQL 주입으로부터 보호할 뿐만 아니라 쿼리 속도도 향상됩니다.

가 아닌 mysql_,mysqli_ , , , , 입니다.pgsql_데이터베이스 프로바이더를 전환해야 하는 경우는 드물지만 애플리케이션을 데이터베이스에서 조금 더 추상화할 수 있습니다.

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++ 에는, 라고 하는 함수가 있습니다.PHP 에서는 를 사용할 수 있습니다.

    수. 왜냐하면 2배는 원래 길이의 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');

헥스는 완벽한 탈출구야주사할 방법이 없어요.

UNHEX 함수와 0x 프리픽스의 차이

댓글에 몇 가지 논의가 있었기 때문에, 최종적으로 명확하게 하고 싶습니다.이 두 가지 접근법은 매우 유사하지만 몇 가지 점에서 약간 다릅니다.

0x접두사는 다음과 같은 데이터 열에만 사용할 수 있습니다.char,varchar,text,block,binary 등등.
하려고 할 복잡합니다. 써야 ''에러가 표시됩니다.

UNHEX()는 임의의 컬럼에서 동작하므로 빈 문자열에 대해 걱정할 필요가 없습니다.


16진법(hex method)은 종종 공격으로 사용됩니다.

과 동일하고 주입 됩니다.mysql_real_escape_string을 사용하다

예를 들어 다음과 같은 작업을 수행하는 경우:

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

공격은 당신에게 아주 쉽게 주사할 수 있습니다.스크립트에서 반환되는 다음 삽입 코드를 고려합니다.

SELECT ... WHERE id = -1 UNION ALL SELECT table_name FROM information_schema.tables;

이제 테이블 구조를 추출합니다.

SELECT ... WHERE id = -1 UNION ALL SELECT column_name FROM information_schema.column WHERE table_name = __0x61727469636c65__;

원하는 데이터를 선택하면 됩니다.멋지지 않아요?

그러나 주입 가능한 사이트의 코더가 이를 16진수할 경우 쿼리는 다음과 같이 나타나므로 주입할 수 없습니다.

SELECT ... WHERE id = UNHEX('2d312075...3635');

폐지된 경고:이 답변의 샘플 코드(질문 샘플 코드 등)는 PHP를 사용합니다.MySQL5.5.7.0.되었습니다.

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.mysql_real_escape_string()PHP 7 ))))))) 。

중요한

SQL 주입을 방지하는 가장 좋은 방법은 승인된 답변에서 알 수 있듯이 이스케이프 대신 Prepared 문을 사용하는 입니다.

아우라 같은 도서관들이 있어요.SQL 및 Easy개발자가 준비된 문장을 더 쉽게 사용할 수 있도록 하는 DB.준비된 문이 SQL 주입을 중지하는 데 더 나은 이유에 대한 자세한 내용은 WordPress의 이 우회최근 수정된 Unicode 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 주입 방지에서 확인할 수 있습니다.

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.

다음과 같은 기본적인 작업을 수행할 수 있습니다.

$safe_variable = mysqli_real_escape_string($dbConnection, $_POST["user-input"]);
mysqli_query($dbConnection, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

이것이 모든 문제를 해결하지는 않겠지만, 그것은 매우 좋은 디딤돌이다.변수의 존재 여부, 형식(숫자, 문자 등) 등 명백한 항목은 생략했습니다.

사용하더라도 아직 합니다.magic_quotes 을 샅샅이 .stripslashes소독할 수 있는 거라도요

폐지된 경고:이 답변의 샘플 코드(질문 샘플 코드 등)는 PHP를 사용합니다.MySQL5.5.7.0.되었습니다.

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.mysql_real_escape_string()PHP 7 ))))))) 。

파라미터화된 쿼리 AND 입력 검증이 최선의 방법입니다.은 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 패턴과 Cake와 같은 프레임워크 채택PHP 또는 CodeIgniter는 아마도 올바른 방법일 것입니다: 안전한 데이터베이스 쿼리 작성과 같은 일반적인 작업이 이러한 프레임워크에서 해결되고 중앙에서 구현되었습니다.웹 응용 프로그램을 합리적인 방법으로 구성하고 단일 SQL 쿼리를 안전하게 구성하는 것보다 개체를 로드하고 저장하는 데 더 많은 생각을 할 수 있도록 도와줍니다.

SQL 주입 및 기타 SQL 해킹을 방지하는 방법은 여러 가지가 있습니다.인터넷(Google 검색)에서 쉽게 찾을 수 있습니다.물론 PDO는 좋은 솔루션 하나입니다.하지만 SQL 주입에 의한 좋은 링크 방지책을 제안하고 싶습니다.

SQL 주입이란 무엇이며 이를 방지하는 방법

SQL 주입용 PHP 설명서

PHP에서의 SQL 주입 및 차단에 대한 Microsoft 설명

MySQLPHP를 통한 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 주입을 막지 않으면 매우 위험합니다.

보안 관점에서 스토어드 프로시저를 선호합니다(MySQL은 5.0 이후 스토어드 프로시저를 지원했습니다). 장점은 다음과 같습니다.

  1. 대부분의 데이터베이스(MySQL 포함)에서는 사용자 액세스가 저장 프로시저 실행으로 제한됩니다.세밀한 보안 접근컨트롤은 특권 공격의 에스컬레이션을 방지하는 데 도움이 됩니다.이렇게 하면 손상된 응용 프로그램이 데이터베이스에 대해 직접 SQL을 실행할 수 없습니다.
  2. 응용 프로그램에서 원시 SQL 쿼리를 추출하여 응용 프로그램에서 사용할 수 있는 데이터베이스 구조의 정보를 줄입니다.이로 인해 사람들은 데이터베이스의 기본 구조를 이해하고 적절한 공격을 설계하기가 어려워집니다.
  3. 파라미터만 받아들이기 때문에 파라미터화된 쿼리의 장점은 있습니다.물론 IMO는 특히 저장 프로시저 내에서 동적 SQL을 사용하는 경우 입력을 삭제해야 합니다.

단점은 다음과 같습니다.

  1. 저장 프로시저는 유지보수가 어렵고 매우 빠르게 증식하는 경향이 있습니다.이로 인해 관리 문제가 발생합니다.
  2. 동적 쿼리에 적합하지 않습니다. 동적 코드를 매개 변수로 받아들이도록 구축되어 있으면 많은 이점이 무효화됩니다.

누군가 PHP와 MySQL 또는 다른 DataBase 서버를 사용하고 싶다면:

  1. PDO(PHP Data Objects) 학습에 대해 생각해 보십시오.PHP는 여러 데이터베이스에 대한 통일된 액세스 방법을 제공하는 데이터베이스 액세스 계층입니다.
  2. MySQLi 학습에 대해 생각해 보십시오.

라이브러리의 예:

----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가 이 전투에서 쉽게 승리합니다.12개의 다른 데이터베이스 드라이버와 명명된 파라미터를 지원하므로 API에 익숙해질 수 있습니다.보안의 관점에서 개발자가 사용할 수 있는 방식으로 사용하는 한 둘 다 안전합니다.

가능한 경우 파라미터 유형을 캐스팅합니다.하지만 int, bool, float와 같은 단순한 유형에서만 작동합니다.

$unsafe_variable = $_POST['user_id'];

$safe_variable = (int)$unsafe_variable ;

mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

RedisMemcached 등의 캐시 엔진을 이용하고 싶다면 DALMP를 선택할 수 있습니다.순수 MySQLi를 사용합니다.체크: PHP를 사용하는 MySQL용 DALMP Database Abstraction Layer를 선택합니다.

또한 쿼리를 준비하기 전에 인수를 '준비'하여 동적 쿼리를 작성하고 마지막에 완전히 준비된 문 쿼리를 가질 수 있습니다.PHP를 사용하는 MySQL용 DALMP 데이터베이스 추상화 계층입니다.

분(PDO에서 )mysql_하나의 파일로 되어 있는 매우 간단한 PDO 래퍼를 만들었습니다.애플리케이션 실행에 필요한 모든 일반적인 작업을 얼마나 쉽게 수행할 수 있는지를 보여주기 위해 존재합니다.Postgre와 연동SQL, 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'));

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.

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_preparemysqli_stmt_bind_param을 사용합니다.이 경우 적절한 변환을 위해 대응하는 바인드 변수의 유형을 지정해야 합니다.

예:

$stmt = $mysqli->prepare("INSERT INTO table (column1, column2) VALUES (?,?)");

$stmt->bind_param("is", $integer, $string);

$stmt->execute();

이든, 준비된 문장이든 .mysqli_real_escape_string작업 중인 입력 데이터의 유형을 항상 알아야 합니다.

준비한 문장을 , .mysqli_stmt_bind_param★★★★★★ 。

,의 ,mysqli_real_escape_string이름에서 알 수 있듯이 문자열의 특수 문자를 이스케이프하기 때문에 정수가 안전하지 않습니다.이 함수의 목적은 SQL 문의 문자열이 끊어지거나 데이터베이스 손상을 방지하는 것입니다. 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

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.mysql_real_escape_string()PHP 7 ))))))) 。

경고:이 시점에서 mysql 확장이 삭제됩니다.PDO 확장을 사용하는 것이 좋습니다.

함수 「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

이 문제에 대한 간단한 대안은 데이터베이스 자체에 적절한 권한을 부여함으로써 해결할 수 있습니다.예를 들어 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';

GRANT에 대해 자세히 알아보기.

많은 유익한 답변에 대해 이 스레드에 가치를 더하고 싶습니다.

SQL 주입은 사용자 입력(사용자가 입력한 후 내부 쿼리)을 통해 수행할 수 있는 공격입니다.SQL 주입 패턴은 올바른 쿼리 구문입니다.부정한 이유로 인한 부정한 쿼리입니다.또한 보안의 3원칙(비밀성, 무결성, 가용성)에 영향을 주는 비밀정보(액세스컨트롤의 패스)를 취득하려고 하는 악당이 있을 가능성이 있습니다.

여기서 중요한 것은 SQL 주입 공격, 질문(PHP를 사용하여 SQL 주입 공격을 방지하는 방법)과 같은 보안 위협을 방지하는 것입니다. 보다 현실적인 질문, 데이터 필터링 또는 입력 데이터 클리어 등은 이러한 쿼리 내에서 사용자 입력 데이터를 사용할 때, PHP 또는 기타 프로그래밍 언어를 사용할 경우 또는 더 많은 사용자가 권장하는 바와 같습니다.현재 SQL 주입 방지를 지원하는 preaded 스테이트먼트나 기타 도구와 같은 최신 기술을 사용하는 사용자는 이러한 도구를 더 이상 사용할 수 없다고 생각하십니까?애플리케이션 보안은 어떻게 보호합니까?

SQL 주입에 대한 접근법은 사용자 입력 데이터를 데이터베이스로 보내기 전에 지우는 것입니다(쿼리 내에서 사용하기 전).

데이터 필터링(안전하지 않은 데이터를 안전한 데이터로 변환)

PDOMySQLi는 사용할 수 없는 것으로 간주합니다.애플리케이션을 보호하려면 어떻게 해야 합니까?억지로 쓰라고?PHP 이외의 언어는 어떻습니까?특정 언어뿐만 아니라 보다 넓은 국경에서 사용할 수 있기 때문에 일반적인 아이디어를 제공하는 것을 선호합니다.

  1. SQL 사용자(사용자 권한 제한): 대부분의 일반적인 SQL 조작은 (SELECT, UPDATE, INSERT)인데, UPDATE 권한이 필요하지 않은 사용자에게 UPDATE 권한을 부여하는 이유는 무엇입니까?예를 들어 로그인 페이지와 검색 페이지는 SELECT만을 사용하고 있는데 왜 이 페이지에서 DB 사용자를 높은 권한으로 사용하는가?

규칙: 모든 권한에 대해 하나의 데이터베이스 사용자를 만들지 마십시오.모든 SQL 작업에 대해 사용자 이름으로 (deluser, selectuser, updateuser)와 같은 체계를 생성하여 쉽게 사용할 수 있습니다.

최소 권한 원칙을 참조하십시오.

  1. 데이터 필터링: 쿼리 사용자 입력을 작성하기 전에 검증 및 필터링해야 합니다.프로그래머의 경우 데이터 유형, 데이터 패턴 및 데이터 길이와 같은 각 사용자 입력 변수에 대한 몇 가지 속성을 정의하는 것이 중요합니다.(x와 y 사이의 숫자인 필드는 정확한 규칙을 사용하여 정확하게 검증해야 합니다.문자열(텍스트)인 필드는 pattern입니다.예를 들어, 사용자 이름에 포함되는 문자는 [a-zA-Z0-9_-]라고 합니다.길이는 (x와 n) 사이에서 변화합니다.여기서 x와 n(x <=n)은 다음과 같습니다.규칙: 정확한 필터 및 검증 규칙을 만드는 것이 나에게 가장 좋은 방법입니다.

  2. 다른 도구 사용:여기에서는 준비된 스테이트먼트(파라미터 쿼리)와 스토어드 프로시저에 대해서도 동의합니다.단점은 이러한 방법에는 대부분의 사용자에게 존재하지 않는 고도의 기술이 필요하다는 것입니다.여기서 기본적인 개념은 SQL 쿼리와 내부에서 사용되는 데이터를 구별하는 것입니다.여기에 있는 사용자 입력 데이터는 (임의 또는 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입니다.이러한 단어가 검출되면 입력을 회피할 수 있습니다.

업데이트 1:

이 게시물은 무용지물이라고 유저가 코멘트했습니다.OK! OWASP는 다음과 같습니다.제공된 조직:

방어: " " " "

1: ( Queries) 옵 1 : option매매매 ( Parameterized Queries )
2: 프로시저의 © 2 : [ ]
all Input © 3 : " " " " " " " " "

방어: " " " "

적용: 권한: " " "
화이트리스트 입력 검증

아시다시피, 기사를 주장하는 것은 적어도 하나의 참조에 의해 유효한 논거가 뒷받침되어야 합니다.그렇지 않으면 공격과 잘못된 클레임으로 간주됩니다!

업데이트 2:

PHP 매뉴얼에서 PHP: 준비된 스테이트먼트 - 매뉴얼:

및 주입

바인딩된 변수는 서버에 의해 자동으로 이스케이프됩니다.서버는 실행 전에 적절한 위치에 이스케이프 값을 스테이트먼트템플릿에 삽입합니다.적절한 변환을 작성하려면 바인딩된 변수 유형에 대한 힌트를 서버에 제공해야 합니다.mysqli_stmt_mt_mt_mt()는 mysqli_stmt_mt_mt_mt()로 지정합니다.

서버 내의 값 자동 이스케이프는 SQL 주입을 방지하기 위한 보안 기능으로 간주될 수 있습니다.입력값이 올바르게 이스케이프되면 준비되지 않은 스테이트먼트에서 동일한 수준의 보안을 실현할 수 있습니다.

업데이트 3:

준비된 문을 사용할 때 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

준비된 진술서 또한 다른 어떤 것도 아닌 데이터로부터 도망치고 있는 것이 분명합니다.

위의 설명에서도 언급했듯이,

서버 내의 값 자동 이스케이프는 SQL 주입을 방지하기 위한 보안 기능으로 간주될 수 있습니다.입력 값이 올바르게 이스케이프되면 준비되지 않은 스테이트먼트에서 동일한 수준의 보안을 달성할 수 있습니다.

때문에 이것은 것을 합니다.intval()는 쿼리를 송신하기 전에 정수 값을 지정하는 것이 좋습니다.또한 쿼리를 전송하기 전에 악의적인 사용자 데이터를 방지하는 것이 올바르고 유효한 방법입니다.

자세한 내용은 다음 질문을 참조하십시오.PDO는 MySQL로 원시 쿼리를 전송하고 Mysqli는 준비된 쿼리를 전송하며 둘 다 동일결과를 생성합니다.

참고 자료:

  1. SQL 주입 치트 시트
  2. SQL 주입
  3. 정보 보안
  4. 보안 원칙
  5. 데이터 검증

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.mysql_real_escape_string()PHP 7 ))))))) 。

폐지된 경고:현재 mysql 확장은 사용되지 않습니다.PDO 확장을 사용하는 것이 좋습니다.

웹 응용 프로그램이 SQL 주입에 취약하지 않도록 세 가지 방법을 사용합니다.

  1. 「」의 mysql_real_escape_string()PHP에서 미리 정의된 함수이며 이 코드는 다음 문자에 백슬래시를 추가합니다.\x00,\n,\r,\,'," ★★★★★★★★★★★★★★★★★」\x1a입력값을 파라미터로 전달하여 SQL 주입 가능성을 최소화합니다.
  2. 가장 고도의 방법은 PDO를 사용하는 것입니다.

이것이 당신에게 도움이 되길 바랍니다.

다음 쿼리를 고려합니다.

$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_sysql_string()은 여기서 보호되지 않습니다.쿼리 내에서 변수 주위에 작은 따옴표(')를 사용하는 경우 이를 방지할 수 있습니다.이에 대한 해결책은 다음과 같습니다.

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

질문에는 이에 대한 몇 가지 좋은 답이 있습니다.

PDO를 사용하는 것이 최선의 선택입니다.

편집:

mysql_real_escape_string() 5.5. 현재 .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");

간단한 방법은 필터링이나 액티브 레코드와 같은 기능이 내장된 CodeIgniter나 Larabel같은 PHP 프레임워크를 사용하는 것입니다.이러한 차이점에 대해 걱정할 필요가 없습니다.

이되어 있는 은 주입 하는 것이 때문에 하지 않습니다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=2SQL 데이터베이스에 대한입니다공격자의 SQL 데이터베이스에 대한 일반적인 질문입니다.아마도 많은 해킹 어플리케이션에서 사용되고 있을 것이다.

그러나 사이트에서 안전한 쿼리를 다시 작성하지 않도록 주의해야 합니다.위의 코드는 공격자의 IP 주소, 심지어 공격자의 쿠키, 이력, 브라우저 또는 기타 중요한 정보를 저장하는 페이지로 해킹 고유의 동적 쿼리 문자열을 다시 쓰거나 리디렉션하기 위한 힌트를 제공합니다(사용자에 따라 다름).따라서 나중에 계정 또는 당국에 연락하지 못하도록 금지합니다.

Idiorm과 같은 객체 관계형 맵퍼를 사용하는 것이 좋습니다.

$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 주입뿐만 아니라 구문 오류도 방지할 수 있습니다.또한 한 번에 여러 결과를 필터링하거나 여러 연결에 작업을 적용하는 메서드 체인을 사용하는 모델 모음도 지원합니다.

PHP와 MySQL에 대한 답변은 매우 많지만, SQL 주입 및 oci8 드라이버의 정기적인 사용을 방지하기 위한 PHPOracle용 코드는 다음과 같습니다.

$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);

폐지된 경고:이 답변의 샘플 코드(질문 샘플 코드 등)는 PHP를 사용합니다.MySQL이 확장 기능은 PHP 5.5.0에서 사용되지 않고 PHP 7.0.0에서 완전히 제거되었습니다.

보안 경고:이 답변은 보안의 베스트 프랙티스와 일치하지 않습니다.SQL 주입을 방지하기 위해 이스케이프가 충분하지 않습니다. 대신 준비된 문을 사용하십시오.아래에 설명된 전략을 자신의 책임으로 사용하십시오.mysql_real_escape_string()PHP 7에서 삭제되었습니다.)

PDOMYSQLi를 사용하는 것은 SQL 주입을 방지하기 위한 좋은 방법이지만 MySQL 함수 및 쿼리로 작업하고 싶다면 사용하는 것이 좋습니다.

mysql_real_sysql_string

$unsafe_variable = mysql_real_escape_string($_POST['user_input']);

이를 방지하는 기능이 더 많이 있습니다. 예를 들어 식별 - 입력이 문자열, 숫자, 문자 또는 배열인 경우 이를 감지하는 함수가 매우 많이 내장되어 있습니다.또한 입력 데이터를 확인할 때 이 기능을 사용하는 것이 좋습니다.

is_string

$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');

is_filename(이것들)

$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

그리고 이러한 기능을 사용하여 입력 데이터를 확인하는 것이 훨씬 더 좋습니다.mysql_real_escape_string.

저는 몇 년 전에 이 작은 함수를 썼습니다.

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#-ish String 한 줄에서 문을 실행할 수 있습니다.형식:

runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);

그것은 가변형을 고려하여 탈출한다.테이블, 열 이름을 매개 변수화하려고 하면 잘못된 구문인 따옴표 안에 모든 문자열을 넣기 때문에 실패합니다.

보안 업데이트: 이전 버전str_replace버전에서는 {#}개의 토큰을 사용자 데이터에 추가하여 주입할 수 있습니다.이것.preg_replace_callback버전에는 이러한 토큰이 포함되어 있으면 문제가 발생하지 않습니다.

언급URL : https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php

반응형