포함의 남용
1. 취약점의 원인:
포함은 PHP 웹 사이트 작성에 가장 일반적으로 사용되는 기능이며 상대 경로를 지원합니다. 입력 변수를 포함 매개변수로 직접 사용하는 PHP 스크립트가 많아 임의 스크립트 참조, 절대 경로 유출 등의 취약점이 발생합니다. 다음 코드를 보세요:
...
$includepage=$_GET["includepage"];
include($includepage);
...
분명히 원하는 페이지를 얻으려면 다른 includepage 변수만 제출하면 됩니다. 존재하지 않는 페이지를 제출하면 PHP 스크립트에 오류가 발생하고 실제 절대 경로가 유출될 수 있습니다. 이 문제에 대한 해결 방법은 다음 문서에 설명되어 있습니다.
2. 취약점 해결:
이 취약점에 대한 해결책은 매우 간단합니다. 먼저 페이지가 존재하는지 확인한 다음 이를 포함하는 것입니다. 또는 더 엄격하게는 배열을 사용하여 포함할 수 있는 파일을 지정합니다. 다음 코드를 보세요:
$pagelist=array("test1.php","test2.php","test3.php") //포함할 수 있는 파일을 지정합니다.
if(isset($_GET["includepage"])) //$includepage가 있는지 확인
{
$includepage=$_GET["includepage"];
foreach($pagelist를 $prepage로)
{
if($includepage==$prepage) //파일이 허용 목록에 있는지 확인
{
include($prepage);
$checkfind=true;
부서지다;
}
}
if($checkfind==true){ unset($checkfind) }
else{ die("잘못된 참조 페이지입니다!") }
}
이렇게 하면 문제가 아주 잘 해결될 것입니다.
팁: 이 문제가 있는 함수에는 require(), require_once(), include_once(), readfile() 등이 있습니다. 작성할 때도 주의해야 합니다.
입력 변수는 필터링되지 않습니다.
1. 취약점의 원인:
이 취약점은 오랫동안 ASP에 나타나며 당시 수많은 인젝션 취약점을 야기했습니다. 하지만 당시에는 PHP의 영향력이 미미했기 때문에 이에 관심을 두는 사람이 많지 않았습니다. PHP의 경우 더 많은 PHP 스크립트가 텍스트 데이터베이스를 사용하기 때문에 이 취약점의 영향은 ASP보다 더 큽니다. 물론 SQL 문 주입 문제도 있습니다. 보다 고전적인 예를 들자면 첫 번째는 데이터베이스입니다.
$id=$_GET["id"];
$query="SELECT * FROM my_table where id='".$id."'" //매우 전형적인 SQL 주입 취약점
$result=mysql_query($query);
데이터베이스의 다른 내용을 얻기 위해 주입을 사용할 수 있다는 것은 여기서 분명합니다. 여기서는 자세히 설명하지 않겠습니다. ASP 인젝션과 마찬가지로 이전의 블랙 방어도 살펴보실 수 있습니다. 그런 다음 텍스트 데이터베이스의 문제를 살펴보겠습니다.
$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
텍스트의 취약성은 틀림없이 훨씬 더 심각합니다. 제출된 변수에 작은 PHP 코드 조각을 삽입하면 이 텍스트 데이터베이스 test.php를 PHP 백도어로 바꿀 수 있습니다. 업로드 코드를 삽입하는 것만으로도 완전한 PHP 백도어를 업로드할 수 있습니다. 그런 다음 권한을 높이면 서버가 귀하의 것입니다.
2. 취약점 해결:
이 취약점에 대한 해결책은 실제로 매우 간단합니다. 즉, 제출된 모든 변수를 엄격하게 필터링하는 것입니다. 일부 민감한 문자를 바꾸십시오. PHP에서 제공하는 htmlspecialchars() 함수를 사용하여 HTML의 내용을 바꿀 수 있습니다. 예는 다음과 같습니다.
//필터 함수 www.knowsky.com 구성
함수 flt_tags($text)
{
$badwords=array("Fuck you","fuck") //단어 필터 목록
$text=rtrim($text);
foreach($badwords as $badword) //여기서 어휘를 필터링합니다.
{
if(stristr($text,$badword)==true){ die("오류: 제출한 콘텐츠에 민감한 단어가 포함되어 있습니다. 민감한 콘텐츠를 제출하지 마세요.") }
}
$text=htmlspecialchars($text); //HTML 교체
//이 두 줄은 캐리지 리턴을
$text=str_replace("r","
로 대체합니다.
",$text);
$text=str_replace("n","",$text);
$text=str_replace("&line;","│",$text); //텍스트 데이터베이스 구분 기호 "&line;"을 전체 너비 "│"로 바꿉니다.
$text=preg_replace("/s{ 2 }/"," ",$text);
$text=preg_replace("/t/"," ",$text) // 여전히 공백 바꾸기
if(get_magic_quotes_gpc()){ $text=stripslashes($text) } //magic_quotes가 활성화된 경우 '를 교체합니다.
$text를 반환합니다.
}
$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];
//모든 입력을 필터링합니다.
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
일부 교체 및 필터링 후에는 데이터를 텍스트나 데이터베이스에 안전하게 쓸 수 있습니다.
관리자의 판단이 불완전하다
1. 취약점의 원인:
우리는 PHP를 사용하여 일반적으로 관리자 권한이 필요한 스크립트를 작성합니다. 일부 스크립트는 관리자 권한에 대해 "예" 판단만 내리고 "아니오" 판단을 무시하는 경우가 많습니다. PHP 구성 파일에서 Register_globals가 켜져 있으면(4.2.0 이후 버전에서는 기본적으로 꺼져 있지만 편의상 많은 사람들이 켜는 매우 위험한 동작입니다.) 변수가 가장을 위해 제출되는 상황이 발생합니다. 관리자. 예제 코드를 살펴보겠습니다.
$cookiesign="admincookiesign"; //관리자의 쿠키 변수 여부를 확인합니다.
$adminsign=$_COOKIE["sign"]; //사용자의 쿠키 변수를 가져옵니다.
if($adminsign==$cookiesign)
{
$admin=참;
}
if($admin){ echo "이제 관리자이십니다.";
매우 안전해 보이네요, 하하. 이제 PHP 구성 파일에서 Register_globals가 켜져 있다고 가정합니다. "test.php?admin=true"라는 주소를 제출했는데, 결과를 보셨나요? 올바른 쿠키가 없더라도 Register_globals가 켜져 있기 때문에 제출한 admin 변수가 자동으로 true로 등록됩니다. 게다가 스크립트에는 "아니요" 판단이 없기 때문에 admin=true를 통해 관리자 권한을 성공적으로 얻을 수 있습니다. 이 문제는 대부분의 웹사이트와 포럼에 존재합니다.
2. 취약점 해결:
이 문제를 해결하려면 스크립트에서 관리자에게 "아니오" 판단을 추가하기만 하면 됩니다. 우리는 여전히 PHP 구성 파일에서 Register_globals가 켜져 있다고 가정합니다. 코드를 살펴보세요:
$cookiesign="admincookiesign"; //관리자의 쿠키 변수 여부를 확인합니다.
$adminsign=$_COOKIE["sign"]; //사용자의 쿠키 변수를 가져옵니다.
if($adminsign==$cookiesign)
{
$admin=참;
}
또 다른
{
$admin=거짓;
}
if($admin){ echo "이제 관리자이십니다.";
이런 방식으로 공격자가 올바른 쿠키 없이 admin=true 변수를 제출하더라도 스크립트는 향후 판단에서 $admin을 False로 설정합니다. 이것은 문제의 일부를 해결합니다. 하지만 $admin은 변수이기 때문에 향후 다른 스크립트 참조에 허점이 발생하여 $admin을 다시 할당하게 되면 새로운 위기가 발생하게 됩니다. 따라서 관리자 권한 결정을 저장하려면 상수를 사용해야 합니다. Define() 문을 사용하여 관리자 권한을 기록하기 위한 관리 상수를 정의합니다. 이후에 다시 할당하면 오류가 발생하므로 보호 목적이 달성됩니다. 다음 코드를 보세요:
$cookiesign="admincookiesign"; //관리자의 쿠키 변수 여부를 확인합니다.
$adminsign=$_COOKIE["sign"]; //사용자의 쿠키 변수를 가져옵니다.
if($adminsign==$cookiesign)
{
정의(관리자,참);
}
또 다른
{
정의(관리자,거짓);
}
if(admin){ echo "이제 관리자 상태입니다.";
참고로 Define 문을 사용하므로 Admin 상수를 호출할 때 습관적으로 변수 기호 $를 앞에 추가하지 말고 Admin 및 !admin을 사용하십시오.
텍스트 데이터베이스가 노출됨
1. 취약점의 원인:
앞서 언급했듯이 텍스트 데이터베이스의 뛰어난 유연성으로 인해 외부 지원이 필요하지 않습니다. 또한 PHP는 매우 강력한 파일 처리 기능을 갖추고 있으므로 텍스트 데이터베이스는 PHP 스크립트에서 널리 사용됩니다. 텍스트 데이터베이스를 사용하는 좋은 포럼 프로그램도 몇 가지 있습니다. 그러나 이익과 손실이 있으며 텍스트 데이터베이스의 보안은 다른 데이터베이스보다 낮습니다.
2. 취약점 해결:
텍스트 데이터베이스는 MDB처럼 다운로드할 수 있는 일반 파일 역할을 합니다. 따라서 MDB와 동일한 방식으로 텍스트 데이터베이스를 보호해야 합니다. 텍스트 데이터베이스의 접미사 이름을 .PHP로 변경합니다. 데이터베이스의 첫 번째 행에 조인합니다. 이렇게 하면 텍스트 데이터베이스가 PHP 파일로 처리되고 실행이 첫 번째 줄에서 종료됩니다. 즉, 텍스트 데이터베이스 보호 목적을 달성하기 위해 빈 페이지가 반환됩니다.
잘못된 경로가 유출되었습니다
1. 취약점의 원인:
PHP에서 오류가 발생하면 오류 스크립트의 위치, 줄 번호 및 이유를 제공합니다. 예:
주의 사항: 정의되지 않은 상수 테스트 사용 - 3행의 D:interpubbigflytest.php에서 'test'로 가정합니다.
많은 사람들이 별 문제가 아니라고 말합니다. 그러나 실제 경로 유출의 결과는 상상할 수 없는 침입자에게는 이 정보가 매우 중요합니다. 실제로 현재 많은 서버에서 이 문제가 발생합니다.
일부 네트워크 관리자는 단순히 PHP 구성 파일의 display_errors를 Off로 설정하여 문제를 해결하기도 하지만 이 방법은 너무 부정적이라고 생각합니다. 때로는 디버깅을 위해 오류 정보를 반환하기 위해 PHP가 꼭 필요한 경우도 있습니다. 그리고 문제가 발생하면 사용자에게 설명을 제공하거나 다른 페이지로 이동해야 할 수도 있습니다.
2. 취약점 해결:
PHP는 4.1.0부터 사용자 정의 오류 처리 핸들 함수 set_error_handler()를 제공했지만 이를 아는 스크립트 작성자는 거의 없습니다. 많은 PHP 포럼 중에서 이러한 상황을 처리하는 포럼은 소수에 불과했습니다. set_error_handler의 사용법은 다음과 같습니다.
문자열 set_error_handler( 콜백 error_handler [, int error_types])
이제 사용자 정의 오류 처리를 사용하여 실제 경로를 필터링합니다.
//Admin은 관리자의 신원 확인이며, true는 관리자입니다.
//사용자 정의 오류 처리 함수에는 $errno, $errstr, $errfile, $errline 네 가지 입력 변수가 있어야 합니다. 그렇지 않으면 유효하지 않습니다.
함수 my_error_handler($errno,$errstr,$errfile,$errline)
{
//관리자가 아닌 경우 실제 경로를 필터링합니다.
만약(!관리자)
{
$errfile=str_replace(getcwd(),"",$errfile);
$errstr=str_replace(getcwd(),"",$errstr);
}
스위치($errno)
{
사례 E_ERROR:
echo "오류: [ID $errno] $errstr (라인: $errfile의 $errline)
N";
echo "프로그램 실행이 중지되었습니다. 관리자에게 문의하세요.";
//오류 수준 오류가 발생하면 스크립트를 종료합니다.
출구;
휴식;
케이스 E_WARNING:
echo "경고: [ID $errno] $errstr (라인: $errfile의 $errline)
N";
휴식;
기본값:
//공지 수준 오류를 표시하지 않음
부서지다;
}
}
//오류 처리를 my_error_handler 함수로 설정합니다.
set_error_handler("my_error_handler");
…
이러한 방식으로 보안과 디버깅 편의성 간의 모순을 잘 해결할 수 있습니다. 또한 웹사이트 스타일에 맞게 오류 메시지를 더욱 아름답게 만드는 방법도 생각할 수 있습니다. 그러나 두 가지 점에 유의하십시오.
(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING은 이 핸들로 처리되지 않습니다. 즉, 가장 독창적인 방식으로 표시됩니다. 그러나 이러한 오류는 컴파일 또는 PHP 커널 오류로 인해 발생하며 일반적인 상황에서는 발생하지 않습니다.
(2) set_error_handler()를 사용한 후에는 error_reporting()이 유효하지 않습니다. 즉, 위에서 언급한 오류를 제외한 모든 오류는 처리를 위해 사용자 정의 함수로 전달됩니다.
set_error_handler()에 대한 기타 내용은 공식 PHP 매뉴얼을 참고하세요.
POST 취약점
1. 취약점의 원인:
앞서 언급했듯이, 변수를 등록하기 위해 Register_globals에 의존하는 것은 나쁜 습관입니다. 일부 방명록 및 포럼 프로그램에서는 페이지 획득 방법과 제출 간 시간 간격을 엄격하게 확인하는 것이 더욱 필요합니다. 스팸 게시물 및 외부 제출을 방지합니다. 방명록 프로그램에 대한 다음 코드를 살펴보겠습니다.
...
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);
$fd=fopen("data.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
...
당연히 "post.php?text1=testhaha&text2=testhaha&text3=testhaha"라는 URL을 제출하면 됩니다. 데이터는 정상적으로 파일에 기록됩니다. 이 프로그램은 변수의 소스와 브라우저가 페이지를 획득한 방법을 감지하지 못합니다. 이 페이지에 여러 개의 제출물을 제출하면 홍수가 발생할 수 있습니다. 또한 이 취약점을 이용하여 포럼이나 방명록에 광고를 게시하는 소프트웨어도 있는데 이는 부끄러운 행위입니다(제 친구의 방명록은 일주일 만에 10페이지가 넘게 넘쳐 무기력했습니다).
2. 취약점 해결:
데이터를 처리하고 저장하기 전에 먼저 브라우저가 페이지를 얻는 방법을 결정하십시오. 페이지를 얻는 브라우저의 방법을 얻으려면 $_SERVER["REQUEST_METHOD"] 변수를 사용하십시오. "POST"인지 확인하세요. 사용자가 일반 채널(즉, 제출 콘텐츠가 채워지는 페이지)을 통해 데이터를 제출하는지 여부를 기록하려면 스크립트에서 세션을 사용하세요. 또는 $_SERVER["HTTP_REFERER"]를 사용하여 이를 감지하지만 이는 권장되지 않습니다. 일부 브라우저는 REFERER를 설정하지 않기 때문에 일부 방화벽은 REFERER도 차단합니다. 또한 제출된 콘텐츠를 확인하여 데이터베이스에 중복된 콘텐츠가 있는지도 확인해야 합니다. 방명록을 예로 들어 세션을 사용하여 결정합니다.
검색 내용을 입력하는 페이지의 프런트 엔드에 다음을 추가합니다.
$_SESSION["allowgbookpost"]=time(); //등록이 완료되는 시간. 메시지 데이터를 받아들이고 저장하는 페이지에서는 데이터 처리 전 다음과 같은 처리도 Session을 이용하여 수행합니다.
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("오류: 외부로 제출하지 마세요.") } //페이지 획득 방법이 POST인지 확인하세요.
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("오류: 외부에 제출하지 마십시오.") } //메시지 확인 작성시간
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("오류: 두 메시지 제출 사이의 간격은 2분 이상이어야 합니다. "); } //메시지 간격 확인
unset($_SESSION["allowgbookpost"]); //여러 제출이 동시에 채우기 페이지에 들어가는 것을 방지하기 위해 Allowgbookpost 변수 등록을 취소합니다.
$_SESSION["gbookposttime"]=time(); //스팸이나 악의적인 공격을 방지하기 위해 메시지를 보낼 시간을 등록합니다.
...
데이터 처리 및 저장
...
이러한 여러 번의 검토를 거친 후에는 귀하의 프로그램이 훨씬 더 안전해질 것입니다.