보안이 중요하다는 것은 누구나 알고 있지만, 마지막 순간까지 보안을 추가하지 않는 것이 업계 추세입니다. 웹 애플리케이션을 완벽하게 보호하는 것은 불가능하기 때문에 굳이 귀찮게 할 이유가 있을까요? 잘못된. 몇 가지 간단한 단계만 수행하면 PHP 웹 애플리케이션의 보안을 크게 향상시킬 수 있습니다.
시작하기 전에
이 튜토리얼에서는 PHP 웹 애플리케이션에 보안을 추가하는 방법을 알아봅니다. 이 튜토리얼에서는 사용자가 PHP 웹 애플리케이션 작성 경험이 1년 이상 있다고 가정하므로 PHP 언어(규칙 또는 구문)에 대한 기본 지식은 여기서 다루지 않습니다. 목표는 귀하가 구축하는 웹 애플리케이션을 보호하는 방법에 대한 아이디어를 제공하는 것입니다.
목적
이 튜토리얼에서는 SQL 주입, GET 및 POST 변수 조작, 버퍼 오버플로 공격, 사이트 간 스크립팅 공격, 브라우저 내 데이터 조작, 원격 양식 제출 등 가장 일반적인 보안 위협으로부터 보호하는 방법을 설명합니다. .
전제 조건
이 튜토리얼은 프로그래밍 경험이 1년 이상인 PHP 개발자를 위해 작성되었습니다. PHP의 구문과 규칙을 이해해야 합니다. 여기서는 설명하지 않습니다. Ruby, Python 및 Perl과 같은 다른 언어를 사용한 경험이 있는 개발자도 이 튜토리얼의 이점을 누릴 수 있습니다. 여기서 논의된 많은 규칙은 다른 언어 및 환경에도 적용되기 때문입니다.
시스템 요구사항
PHP V4 또는 V5 및 MySQL을 실행하는 환경이 필요합니다. Linux, OS X 또는 Microsoft Windows를 사용할 수 있습니다. Windows를 사용하는 경우 WAMPServer 바이너리를 다운로드하고 컴퓨터에 Apache, MySQL 및 PHP를 설치하십시오.
보안에 대한 간략한 소개
웹 애플리케이션에서 가장 중요한 부분은 무엇인가요? 이 질문에 대한 대답은 누가 대답하느냐에 따라 달라질 수 있습니다. 비즈니스 사람들에게는 안정성과 확장성이 필요합니다. IT 지원 팀에는 강력하고 유지 관리가 가능한 코드가 필요합니다. 최종 사용자는 작업 수행 시 아름다운 사용자 인터페이스와 높은 성능을 요구합니다. 그러나 대답이 "보안"이라면 이것이 웹 애플리케이션에 중요하다는 데 모두가 동의할 것입니다.
그러나 대부분의 논의는 여기서 그칩니다. 보안은 프로젝트 체크리스트에 있지만 프로젝트가 전달될 때까지 해결되지 않는 경우가 많습니다. 이 접근 방식을 사용하는 웹 애플리케이션 프로젝트의 수는 엄청납니다. 개발자들은 웹 애플리케이션을 대중에게 공개하기 위해 마지막에 보안 기능을 추가하면서 몇 달 동안 작업했습니다.
보안 기능이 추가되기 전에 코드를 검사하고, 단위 테스트하고, 더 큰 프레임워크에 통합했기 때문에 결과가 엉망이거나 재작업이 필요한 경우가 많습니다. 보안을 추가한 후 주요 구성 요소의 작동이 중지될 수 있습니다. 보안 통합은 원활하지만 안전하지 않은 프로세스에 추가 부담이나 단계를 추가합니다.
이 튜토리얼은 보안을 PHP 웹 애플리케이션에 통합하는 훌륭한 방법을 제공합니다. 몇 가지 일반적인 보안 주제를 논의한 다음 주요 보안 취약점과 이를 연결하는 방법을 자세히 살펴봅니다. 이 튜토리얼을 마치면 보안에 대해 더 잘 이해하게 될 것입니다.
주제:
SQL 주입 공격
GET 문자열 조작
버퍼 오버플로 공격
교차 사이트 스크립팅 공격(XSS)
브라우저 내 데이터 조작
원격 양식 제출
웹 보안 101
보안 구현의 세부 사항을 논의하기 전에 높은 수준의 관점에서 웹 애플리케이션 보안을 논의하는 것이 가장 좋습니다. 이 섹션에서는 어떤 종류의 웹 애플리케이션을 생성하든 염두에 두어야 할 몇 가지 기본 보안 철학을 소개합니다. 이러한 아이디어 중 일부는 Chris Shiflett(PHP 보안에 관한 책이 귀중한 보고임), 일부는 Simson Garfinkel(참고자료 참조), 일부는 수년간 축적된 지식에서 나왔습니다.
규칙 1: 외부 데이터나 입력을 절대 신뢰하지 마세요.
웹 애플리케이션 보안에 대해 가장 먼저 깨달아야 할 것은 외부 데이터를 신뢰해서는 안 된다는 것입니다. 외부 데이터에는 프로그래머가 PHP 코드에 직접 입력하지 않은 모든 데이터가 포함됩니다. 다른 소스(예: GET 변수, 양식 POST, 데이터베이스, 구성 파일, 세션 변수 또는 쿠키)의 모든 데이터는 보안을 보장하기 위한 조치를 취할 때까지 신뢰할 수 없습니다.
예를 들어 다음 데이터 요소는 PHP에서 설정되므로 안전하다고 간주할 수 있습니다.
목록 1. 안전하고 완벽한 코드
$myUsername = 'tmyer'
$arrayUsers = array('tmyer', 'tom', 'tommy'); >define("GREETING", 'hello there' . $myUsername)
?> 그러나 다음 데이터 요소에는 결함이 있습니다.
목록 2. 안전하지 않고 결함이 있는 코드
$myUsername = $_POST['username'] //tainted!
$arrayUsers = array($myUsername, ' tom', 'tommy'); //tainted!
define("GREETING", 'hello 거기' . $myUsername); //tainted!
?> ? POST 형식에서 직접 제공되기 때문입니다. 사용자는 파일을 정리하거나 이전에 업로드한 파일을 실행하기 위한 악성 명령을 포함하여 이 입력 필드에 임의의 문자열을 입력할 수 있습니다. "A-Z 문자만 허용하는 클라이언트측(JavaScript) 양식 유효성 검사 스크립트를 사용하면 이러한 위험을 피할 수 없나요?"라고 물을 수 있습니다. 예, 이는 항상 유익한 단계이지만 나중에 살펴보겠지만 누구나 어떤 양식이든 컴퓨터에 다운로드하여 수정하고 필요한 것을 다시 제출할 수 있습니다.
해결책은 간단합니다. 삭제 코드는 $_POST['username'] 에서 실행되어야 합니다. 이렇게 하지 않으면 $myUsername을 사용할 때마다(예: 배열 또는 상수에서) 이러한 개체를 오염시킬 수 있습니다.
사용자 입력을 삭제하는 간단한 방법은 정규식을 사용하여 처리하는 것입니다. 이 예에서는 문자만 허용됩니다. 문자열을 특정 문자 수로 제한하거나 모든 문자를 소문자로 요구하는 것도 좋은 생각일 수 있습니다.
목록 3. 사용자 입력을 안전하게 만들기
$myUsername = cleanInput($_POST['username']) //clean!
$arrayUsers = array($myUsername , ' tom', 'tommy'); //clean!
define("GREETING", '안녕하세요' . $myUsername) //clean!
function cleanInput($input){
$ clean = strtolower($input);
$clean = preg_replace("/[^a-z]/", "", $clean)
$clean = substr($clean,0,12) > return $clean;
}
?>
규칙 2: 보안 구현을 어렵게 만드는 PHP 설정을 비활성화합니다.
이제 사용자 입력을 신뢰할 수 없다는 것을 알았습니다. 기계를 신뢰하지 않습니다. PHP를 구성하는 방법. 예를 들어, Register_globals가 비활성화되어 있는지 확인하십시오. Register_globals가 활성화된 경우 $variable을 사용하여 동일한 이름의 GET 또는 POST 문자열을 바꾸는 것과 같은 부주의한 작업을 수행할 수 있습니다. 이 설정을 비활성화하면 PHP는 올바른 네임스페이스에서 올바른 변수를 참조하도록 강제합니다. POST 형식의 변수를 사용하려면 $_POST['variable']을 인용해야 합니다. 이렇게 하면 이 특정 변수를 쿠키, 세션 또는 GET 변수로 잘못 해석하지 않습니다.
두 번째로 확인해야 할 설정은 오류 보고 수준입니다. 개발 중에는 가능한 한 많은 오류 보고서를 얻고 싶지만, 프로젝트를 전달할 때는 오류가 화면에 표시되지 않고 로그 파일에 기록되기를 원합니다. 왜? 악의적인 해커가 오류 보고 정보(예: SQL 오류)를 사용하여 애플리케이션이 수행하는 작업을 추측할 수 있기 때문입니다. 이러한 종류의 정찰은 해커가 애플리케이션을 침해하는 데 도움이 될 수 있습니다. 이 취약점을 해결하려면 php.ini 파일을 편집하여 error_log 항목에 적합한 대상을 제공하고 display_errors를 Off로 설정하십시오.
규칙 3: 이해하지 못하면 보호할 수 없습니다
어떤 개발자는 이상한 구문을 사용하거나 문장을 매우 촘촘하게 구성하여 짧지만 모호한 코드를 만듭니다. 이 접근 방식은 효율적일 수 있지만 코드가 수행하는 작업을 이해하지 못하면 코드를 보호하는 방법을 결정할 수 없습니다.
예를 들어, 다음 두 가지 코드 중 어떤 코드가 마음에 드시나요?
목록 4. 코드를 보호하기 쉽게 만드세요
//난독화된 코드
$input = (isset($_POST['username']) ? $_POST['username' ] :'');
//난독화되지 않은 코드
$input = '';
if (isset($_POST['username'])){
$input = $_POST['username ' ];
$input = '';
}
?>
두 번째 명확한 코드 조각에서는 $input에 결함이 있음을 쉽게 알 수 있습니다. 안전하게 폐기하기 전에 청소해야 합니다.
규칙 4: "심층 방어"는 새로운 마법 무기입니다.
이 튜토리얼에서는 예제를 사용하여 온라인 양식을 보호하는 동시에 양식을 처리하는 PHP 코드에서 필요한 조치를 취하는 방법을 설명합니다. 마찬가지로, PHP 정규식을 사용하여 GET 변수가 완전히 숫자인지 확인하는 경우에도 SQL 쿼리가 이스케이프된 사용자 입력을 사용하도록 조치를 취할 수 있습니다.
심층 방어는 단순히 좋은 생각이 아니라 심각한 문제에 빠지지 않도록 보장합니다.
이제 기본 규칙에 대해 논의했으니 첫 번째 위협인 SQL 주입 공격을 살펴보겠습니다.
SQL 주입 공격 방지
SQL 주입 공격에서는 사용자가 양식이나 GET 쿼리 문자열을 조작하여 데이터베이스 쿼리에 정보를 추가합니다. 예를 들어 간단한 로그인 데이터베이스가 있다고 가정합니다. 이 데이터베이스의 각 레코드에는 사용자 이름 필드와 비밀번호 필드가 있습니다. 사용자가 로그인할 수 있도록 로그인 양식을 작성하십시오.
목록 5. 간단한 로그인 양식