PHP는 대부분의 서버 시스템에서 파일 및 디렉토리 권한과 관련된 보안 메커니즘을 준수합니다. 이를 통해 관리자는 파일 시스템 내에서 읽을 수 있는 파일을 제어할 수 있습니다. 전역적으로 읽을 수 있는 파일에 특별한 주의를 기울여야 하며 모든 승인된 사용자가 이러한 파일을 안전하게 읽을 수 있도록 보장해야 합니다.
PHP는 사용자 수준에서 파일 시스템에 액세스하도록 설계되었으므로 /etc/passwd와 같은 시스템 파일 읽기, 네트워크 연결 변경, 대량 전송 등의 PHP 코드 작성이 전적으로 가능합니다. 인쇄 작업 등 따라서 PHP 코드가 적절한 파일을 읽고 쓰고 있는지 확인해야 합니다.
아래 코드를 보세요. 사용자가 자신의 홈 디렉터리에 있는 파일을 삭제하려고 합니다. 이 시나리오에서는 파일 시스템이 웹 인터페이스를 통해 관리되므로 Apache 사용자에게 사용자 디렉터리의 파일을 삭제할 수 있는 권한이 있다고 가정합니다.
예제 #1 변수에 대한 보안 검사를 수행하지 않으면...
<?php // 从用户目录中删除指定的文件 $username = $_POST['user_submitted_name']; $userfile = $_POST['user_submitted_filename']; $homedir = "/home/$username"; unlink ("$homedir/$userfile"); echo "The file has been deleted!"; ?>
사용자 이름 및 파일 이름 변수는 사용자 양식을 통해 제출할 수 있으므로 다른 사람의 변수를 제출할 수 있습니다. 사용자 이름과 파일 이름, 애초에 삭제하면 안 되는 파일도 삭제할 수 있습니다. 이 경우 다른 인증 방법을 고려해야 합니다. 제출된 변수가 "../etc/" 및 "passwd"인 경우 어떤 일이 발생할지 생각해 보세요. 위의 코드는 다음과 같습니다.
예제 #2... 파일 시스템 공격
<?php // 删除硬盘中任何 PHP 有访问权限的文件。如果 PHP 有 root 权限: $username = $_POST['user_submitted_name']; // "../etc" $userfile = $_POST['user_submitted_filename']; // "passwd" $homedir = "/home/$username"; // "/home/../etc" unlink("$homedir/$userfile"); // "/home/../etc/passwd" echo "The file has been deleted!"; ?>
이런 문제를 방지하려면 두 가지 중요한 조치가 필요합니다.
PHP 웹 사용자에게 매우 제한된 권한만 부여합니다.
제출된 변수를 모두 확인하세요.
개선된 스크립트는 다음과 같습니다.
예제 #3 더 안전한 파일 이름 확인
<?php // 删除硬盘中 PHP 有权访问的文件 $username = $_SERVER['REMOTE_USER']; // 使用认证机制 $userfile = basename($_POST['user_submitted_filename']); $homedir = "/home/$username"; $filepath = "$homedir/$userfile"; if (file_exists($filepath) && unlink($filepath)) { $logstring = "Deleted $filepath\n"; } else { $logstring = "Failed to delete $filepath\n"; } $fp = fopen("/home/logging/filedelete.log", "a"); fwrite ($fp, $logstring); fclose($fp); echo htmlentities($logstring, ENT_QUOTES); ?>
그러나 여기에는 여전히 결함이 있습니다. 인증 시스템에서 사용자가 자신의 로그인 사용자 이름을 만들 수 있도록 허용하고 사용자가 "../etc/"를 사용자 이름으로 사용하도록 선택하면 시스템이 다시 실패합니다. 따라서 검사 강화가 필요합니다:
예시#4 더욱 안전한 파일명 검사
<?php $username = $_SERVER['REMOTE_USER']; // 使用认证机制 $userfile = $_POST['user_submitted_filename']; $homedir = "/home/$username"; $filepath = "$homedir/$userfile"; if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) { die("Bad username/filename"); } //后略…… ?>
운영 체제에 따라 관련 파일을 포함하여 주의가 필요한 다양한 파일이 있습니다. 시스템 장치(/dev/ 또는 COM1), 구성 파일(/ect/ 파일 및 .ini 파일), 일반적으로 사용되는 저장 영역(/home/ 또는 내 문서) 등에 이러한 이유로 모든 권한을 비활성화하고 명시적으로 허용된 권한만 활성화하는 정책을 설정하는 것이 더 쉬운 경우가 많습니다.