>백엔드 개발 >PHP 튜토리얼 >PHP에서 SQL 주입을 방지하는 Anti-SQL 주입 코드

PHP에서 SQL 주입을 방지하는 Anti-SQL 주입 코드

WBOY
WBOY원래의
2016-07-29 08:44:27988검색

1. 인젝션 공격의 종류
공격 동기는 다양할 수 있지만 얼핏 보면 종류가 더 많아 보인다. 이는 매우 사실입니다. 악의적인 사용자가 여러 쿼리를 수행하는 방법을 찾는 경우입니다. 이에 대해서는 이 기사의 뒷부분에서 자세히 논의하겠습니다.
예를 들어
스크립트가 SELECT 명령을 실행하는 경우 공격자는 아래와 같이 WHERE 절에 "1=1"과 같은 조건을 삽입하여 테이블의 모든 행을 강제로 표시할 수 있습니다. (굵은 글씨로 표시된 주입 부분):
SELECT * FROM wines WHERE Variety = 'lagrein' OR 1=1;'
앞서 논의한 것처럼 이 정보는 그 자체로 일반적인 구조를 보여주기 때문에 매우 유용한 정보가 될 수 있습니다. 테이블의 정보(일반 기록으로는 불가능한 것)뿐만 아니라 기밀 정보가 포함된 기록을 잠재적으로 드러낼 수도 있습니다.
업데이트 지시문은 잠재적으로 더 즉각적인 위협을 가할 수 있습니다. SET 절에 다른 속성을 배치함으로써 공격자는 다음 예와 같이 현재 업데이트된 레코드의 모든 필드를 수정할 수 있습니다(주입된 부분은 굵게 표시됨).
UPDATE wines SET type= 'red', 'vintage' ='9999' WHERE 다양성 = 'lagrein'
업데이트 명령의 WHERE 절에 1=1과 같은 참 조건을 추가하여 이 수정 범위를 확장할 수 있습니다. 각 레코드는 다음 예와 같습니다(여기서 주입 부분은 굵게 표시됨):
UPDATE wines SET type='red', 'vintage'='9999 WHERE breed = 'lagrein' OR 1=1;'
아마도 가장 위험한 명령은 DELETE일 것입니다. 어렵지 않습니다. 상상하다. 주입 기술은 우리가 이미 본 것과 동일합니다. 다음 예(주입 부분이 굵게 표시됨)와 같이 WHERE 절을 수정하여 영향을 받는 레코드의 범위를 확장합니다.
DELETE FROM wines WHERE 다양성 = ' lagrein' OR 1=1;'
2. 다중 쿼리 삽입
다중 쿼리 삽입은 단일 쿼리에 여러 개의 파괴적인 명령이 포함될 수 있도록 하여 공격자가 초래할 수 있는 잠재적 피해를 악화시킵니다. MySQL 데이터베이스를 사용할 때 공격자는 예상치 못한 종결자를 쿼리에 삽입하여 이를 쉽게 달성할 수 있습니다. 삽입된 따옴표(단일 또는 이중)는 예상 변수의 끝을 표시한 다음 세미콜론으로 지시문을 종료합니다. 이제 종료된 원래 명령 뒤에 추가 공격 명령을 추가할 수 있습니다. 최종 파괴적인 쿼리는 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.


SELECT * FROM wines WHERE 다양성 = 'lagrein';
'gotcha'로 식별된 'BadGuy@%'에 *.*에 대한 모든 권한 부여;'
이 주입은 새로운 사용자 BadGuy를 생성하고 이 사용자에게 네트워크 권한(모든 테이블에 대한 모든 권한)을 부여합니다. 또한 이 간단한 SELECT 문에 "불길한" 비밀번호가 추가됩니다. 이전 기사의 조언을 따르고 프로세스 사용자의 권한을 엄격하게 제한한 경우 웹 서버 데몬에는 취소한 GRANT 권한이 더 이상 없기 때문에 이 방법은 작동하지 않습니다. 그러나 이론적으로 이러한 공격을 통해 BadGuy는 데이터베이스로 원하는 모든 작업을 자유롭게 수행할 수 있습니다.
이러한 다중 쿼리가 MySQL 서버에서 처리되는지 여부에 대한 결론은 고유하지 않습니다. 이 중 일부는 MySQL의 다른 버전으로 인해 발생할 수 있지만 대부분은 여러 쿼리가 존재하는 방식으로 인해 발생합니다. MySQL의 모니터링 프로그램은 이러한 쿼리를 완벽하게 허용합니다. 일반적으로 사용되는 MySQL GUI-phpMyAdmin은 최종 쿼리 전에 이전 내용을 모두 복사하고 이 작업만 수행합니다.
그러나 삽입 컨텍스트 내의 다중 쿼리 대부분은 PHP의 mysql 확장으로 관리됩니다. 다행스럽게도 기본적으로 쿼리에서 여러 명령을 실행하는 것을 허용하지 않습니다. 두 명령(예: 위에 표시된 주입)을 실행하려고 하면 단순히 실패가 발생합니다. 오류가 설정되지 않으며 출력 정보도 생성되지 않습니다. 이 경우 PHP는 기본 동작을 "정기적으로"만 구현하지만 실제로 대부분의 간단한 주입 공격으로부터 사용자를 보호할 수 있습니다.
PHP5의 새로운 mysqli 확장(http://php.net/mysqli 참조)은 mysql과 마찬가지로 본질적으로 다중 쿼리를 지원하지 않지만 다중 쿼리 구현을 지원하기 위해 mysqli_multi_query() 함수를 제공합니다. 정말로 그렇게 하고 싶다면.
그러나 PHP5와 함께 번들로 제공되는 내장형 SQL 데이터베이스 엔진인 SQLite(http://sqlite.org/ 및 http://php.net/sqlite 참조)의 경우 사용하기 쉽기 때문에 상황은 훨씬 더 심각합니다. 많은 사용자의 관심을 끌 수 있습니다. 어떤 경우에는 데이터베이스가 일괄 쿼리, 특히 일괄 INSERT 문 처리를 매우 효율적으로 최적화할 수 있기 때문에 SQLite는 기본적으로 이러한 다중 명령 쿼리를 허용합니다. 그러나 sqlite_query() 함수는 쿼리 결과가 스크립트에서 사용되는 경우(예: SELECT 문을 사용하여 레코드를 검색하는 경우) 여러 쿼리 실행을 허용하지 않습니다. 3. INVISION Power BOARD SQL 인젝션 취약점
Invision Power Board는 잘 알려진 포럼 시스템입니다. 2005년 5월 6일 로그인 코드에서 SQL 주입 취약점이 발견되었습니다.
GulfTech Security Research의 James Bercegay가 발견했습니다.
이 로그인 쿼리는 다음과 같습니다.
$DB->query("SELECT * FROM ibf_members WHERE id=$mid AND Password='$pid'")
이 중 회원 ID 변수 $mid 및 비밀번호 ID 변수 $pid는 다음 두 줄의 코드를 사용하여 my_cookie() 함수에서 검색됩니다.

코드 복사 코드는 다음과 같습니다. :


$mid = intval($std->my_getcookie('member_id'))
$pid = $std->my_getcookie('pass_hash')


여기에서 my_cookie() 함수는 다음 문을 사용하여 쿠키에서 필요한 변수를 검색합니다.
return urldecode($_COOKIE[$ibforums->vars['cookie_id'].$name]) ;
[참고] 여기에서 쿠키가 반환한 값은 전혀 처리되지 않습니다. $mid는 쿼리에 사용되기 전에 정수로 변환되지만 $pid는 변경되지 않습니다. 따라서 앞서 설명한 주입 공격 유형에 취약합니다.
따라서 my_cookie() 함수를 다음과 같이 수정하면 본 취약점이 노출됩니다.

코드 복사 코드는 다음과 같습니다.


if ( ! in_array( $name, array('topicsread', 'forum_read', 'collapseprefs') ) ) )
{
return $this-> urldecode( $_COOKIE[$ibforums->vars['cookie_id'].$name]))
}
else
{
return urldecode($_COOKIE[$ibforums->vars ['cookie_id'].$name])
}


이러한 수정 후 전역 clean_value() 함수를 "통과"한 후 주요 변수가 반환되고 다른 변수는 확인되지 않습니다.
이제 SQL 인젝션이 무엇인지, 어떻게 작동하는지, 이 인젝션이 얼마나 취약한지 전반적으로 이해했으므로 이를 효과적으로 방지하는 방법을 살펴보겠습니다. 다행스럽게도 PHP는 풍부한 리소스를 제공하므로 권장 기술을 사용하여 신중하고 철저하게 구축된 애플리케이션이 본질적으로 스크립트에서 SQL 삽입 가능성을 제거할 것이라고 확신할 수 있습니다. 이는 사용자 데이터를 "정리"함으로써 달성됩니다. 손상을 입힐 수 있기 전에.
4. 쿼리에서 각 값을 정의하세요.
쿼리에서 각 값을 정의하는 것이 좋습니다. 문자열 값은 일반적으로 "이중"이 아닌 "단일" 따옴표를 사용할 것으로 예상되는 것과 마찬가지로 가장 먼저 영향을 받습니다. 한편으로, 문자열 내에서 PHP 변수 대체를 허용하기 위해 큰따옴표를 사용하면 쿼리 입력이 더 쉬워지는 반면, 이는 향후 분석에서 PHP 코드의 양을 (물론 최소한으로) 줄여줄 것입니다. 일하다.
다음으로 이 문제를 설명하기 위해 처음에 사용한 비주입 쿼리를 사용하겠습니다.
SELECT * FROM wines WHERE Variant = 'lagrein'
또는 PHP 문에서 다음과 같이 표현합니다.
$ query = "SELECT * FROM wines WHERE 다양성 = '$variety'"
기술적으로 숫자 값에는 따옴표가 필요하지 않습니다. 그러나 와인과 같은 필드의 값 주위에 따옴표를 사용하는 것이 괜찮고 사용자가 양식에 null 값을 입력하면 다음과 같은 쿼리가 표시됩니다.
SELECT * FROM wines WHERE vintage =
물론 이 쿼리는 구문상 유효하지 않습니다. 그러나 다음 구문은 유효합니다.
SELECT * FROM wines WHERE vintage = ''
두 번째 쿼리는 (아마도) 결과를 반환하지 않지만 최소한 오류 메시지를 반환하지 않습니다.
5. 사용자가 제출한 값의 유형을 확인합니다
이전 논의를 통해 지금까지 SQL 주입의 주요 원인은 예상치 못한 양식 항목에서 오는 경우가 많다는 것을 알 수 있습니다. 그러나 사용자에게 양식을 통해 특정 값을 제출할 수 있는 기회를 제공하면
얻고자 하는 입력 콘텐츠를 결정하는 데 상당한 이점이 있어야 합니다. 이렇게 하면 사용자 항목이 다음과 같은지 더 쉽게 확인할 수 있습니다. 유효한 섹스. 이전 기사에서 이러한 검증 문제에 대해 논의한 적이 있으므로 여기서는 당시 논의의 주요 사항만 간략하게 요약하겠습니다. 숫자를 기대한다면 다음 기술 중 하나를 사용하여 얻고 있는 것이 실제로 숫자 유형인지 확인할 수 있습니다. is_int() 함수(또는 is_integer() 또는 is_long())를 사용하십시오.
 · gettype() 함수를 사용하세요.
 · intval() 함수를 사용하세요.
 · settype() 함수를 사용하세요.
사용자 입력 길이를 확인하려면 strlen() 함수를 사용하면 됩니다. 원하는 시간이나 날짜가 유효한지 확인하려면 strtotime() 함수를 사용하면 됩니다. 사용자 항목에 세미콜론 문자가 포함되지 않도록 보장하는 것이 거의 확실합니다(법적으로 구두점을 포함할 수 없는 경우). 아래와 같이 strpos() 함수를 사용하면 쉽게 이를 달성할 수 있습니다.
if( strpos( $variety, ';' ) ) exit ( "$variety는 다양한 값에 적합하지 않습니다!" ); >앞서 언급했듯이 사용자 입력 기대치를 주의 깊게 분석하면 많은 문제를 쉽게 발견할 수 있습니다.
6. 검색어에서 의심스러운 문자를 모두 필터링합니다.
이전 기사에서는 위험한 문자를 필터링하는 방법을 설명했지만 여기서는 이 문제를 간략하게 강조하고 요약하겠습니다.
· 하지 마세요. Magic_quotes_gpc 지시어 또는 해당 "비하인드 더 씬 파트너"(addlashes() 함수)를 사용하십시오. 이 함수는 응용 프로그램 개발에서 제한되며 추가 단계가 필요합니다. - Stripslashes() 함수를 사용하십시오.
· 이에 비해 mysql_real_escape_string() 함수가 더 일반적으로 사용되지만 나름대로의 단점도 있습니다.
위 내용은 SQL 인젝션 방지 내용을 포함하여 PHP에서 SQL 인젝션을 방지하는 코드를 소개하고 있는데, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되었으면 좋겠습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.