>  기사  >  백엔드 개발  >  프레임워크와 CMS의 이상한 PHP 코드

프레임워크와 CMS의 이상한 PHP 코드

Barbara Streisand
Barbara Streisand원래의
2024-11-12 07:56:02633검색

Ese extraño código PHP en frameworks y CMS

참고: 이 게시물을 따르려면 PHP에 대한 최소한의 프로그래밍 지식이 있다고 가정합니다.

이 게시물은 여러분이 즐겨 사용하는 CMS 또는 프레임워크의 상단에서 본 PHP 코드 조각에 관한 것입니다. 보안을 위해 모든 PHP 파일의 헤더에 항상 포함해야 한다는 내용을 읽었을 것입니다. 이유에 대한 명확한 설명은 없지만 개발됩니다. 나는 다음 코드를 언급하고 있습니다:

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

이러한 유형의 코드는 WordPress 파일에서 매우 일반적이지만 실제로는 거의 모든 프레임워크와 CMS에 나타납니다. 예를 들어 CMS Joomla의 경우 변경되는 유일한 점은 ABSPATH 대신 JEXEC가 사용된다는 것입니다. 그렇지 않으면 논리는 동일합니다. 이 CMS는 비슷한 코드를 사용했지만 _VALID_MOS를 상수로 사용하는 Mambo라는 또 다른 CMS에서 탄생했습니다. 시간을 더 거슬러 올라가면 이러한 유형의 코드를 사용한 최초의 CMS는 PHP-Nuke(일부에서는 PHP의 최초 CMS로 간주됨)라는 것을 알 수 있습니다.

PHP-Nuke(및 오늘날 대부분의 CMS 및 프레임워크)의 실행 흐름은 웹에서 사용자나 방문자가 수행한 작업에 함께 응답하는 여러 파일을 순차적으로 로드하는 것으로 구성되었습니다. 즉, example.net 도메인에 이 CMS가 설치된 당시의 웹사이트를 상상해 보세요. 홈 페이지가 로드될 때마다 시스템은 순서대로 일련의 파일을 실행했습니다(이 경우 실제 순서가 아닌 단지 예일 뿐입니다). index.php => load_modules.php => module.php. 즉, 이 순서에서는 index.php가 먼저 로드된 다음 이 스크립트가 load_modules.php를 로드하고 이것이 다시 module.php를 로드했습니다.

이 실행 체인은 항상 첫 번째 파일(index.php)에서 시작되지 않았습니다. 실제로 누구나 URL(예: http://example.net/load_modules.php 또는 http://example.net/modules.php)로 다른 PHP 파일 중 하나를 직접 호출하여 이 흐름의 일부를 건너뛸 수 있습니다. , 앞으로 살펴보겠지만 많은 경우 위험할 수 있습니다.

이 문제는 어떻게 해결되었나요? 각 파일의 시작 부분에 다음과 유사한 코드를 추가하는 보안 조치가 도입되었습니다.

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}

기본적으로 module.php라는 파일의 헤더에 있는 이 코드는 URL을 통해 module.php에 직접 접근하고 있는지 확인하는 코드입니다. 그렇다면 실행이 중지되고 "이 파일에 직접 액세스할 수 없습니다..."라는 메시지가 표시됩니다. $HTTP_SERVER_VARS['PHP_SELF']에 module.php가 포함되어 있지 않다면 이는 정상적인 실행 흐름에 있으며 계속할 수 있다는 의미입니다.

그러나 이 코드에는 몇 가지 제한 사항이 있었습니다. 첫째, 삽입된 파일마다 코드가 달라서 복잡해졌습니다. 또한 특정 상황에서는 PHP가 $HTTP_SERVER_VARS['PHP_SELF']에 값을 할당하지 않아 효율성이 제한되었습니다.

그래서 개발자들은 무엇을 했나요? 그들은 모든 코드 조각을 더 간단하고 효율적인 버전으로 대체했습니다.

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

이미 PHP 커뮤니티에서 흔히 볼 수 있었던 이 새로운 코드에서는 상수의 존재가 확인되었습니다. 이 상수는 흐름의 첫 번째 파일(index.php, home.php 또는 유사한 파일)에서 정의되고 값이 할당되었습니다. 따라서 이 상수가 스트림의 다른 파일에 존재하지 않는다면 누군가가 index.php 파일을 건너뛰고 다른 파일에 직접 액세스하려고 했다는 의미입니다.

PHP 파일을 직접 실행하는 사람의 위험

분명히 이 시점에서 당신은 처형의 사슬을 끊는 것이 세상에서 가장 심각한 일임에 틀림없다고 생각하고 있을 것입니다. 그러나 현실은 일반적으로 심각한 위험을 초래하지는 않습니다.

PHP 오류로 인해 파일 경로가 노출되면 위험이 발생할 수 있습니다. 서버에 오류 억제 기능이 구성되어 있으면 걱정할 필요가 없습니다. 오류가 숨겨지지 않더라도 노출되는 정보는 최소화되어 공격자에게 단 몇 가지 단서를 제공할 뿐입니다.

누군가 HTML 조각이 포함된 파일에 액세스하여(뷰에서) 콘텐츠의 일부가 노출되는 경우도 발생할 수 있습니다. 대부분의 경우 이는 걱정할 필요가 없습니다.

마지막으로 개발자의 부주의나 경험 부족으로 인해 실행 흐름 중간에 외부 종속성 없이 위험한 코드를 삽입하는 경우가 발생할 수 있습니다. 이는 일반적으로 프레임워크나 CMS의 코드가 실행을 위해 다른 클래스, 함수 또는 외부 변수에 의존하기 때문에 매우 이례적입니다. 따라서 URL을 통해 직접 스크립트를 실행하려고 하면 이러한 종속성을 찾지 못하고 실행이 계속되지 않습니다.

그렇다면 우려할만한 원인이 거의 없다면 상수 코드를 추가하는 이유는 무엇입니까? 그 이유는 다음과 같습니다. "이 방법은 또한 전역 등록에 대한 공격을 통해 실수로 변수를 삽입하는 것을 방지하여 PHP 파일이 실제로는 그렇지 않은데도 애플리케이션 내부에 있다고 가정하는 것을 방지합니다.

전역 등록

PHP 초기부터 URL(GET)이나 폼(POST)을 통해 전달되는 모든 변수는 자동으로 전역으로 변환되었습니다. 즉, download.php?filepath=/etc/passwd 파일에 액세스한 경우 download.php 파일(및 실행 흐름에서 이에 의존하는 파일)에서 echo $filepath를 사용할 수 있습니다. 결과는 /etc/passwd가 됩니다.

download.php 내에서는 $filepath 변수가 실행 흐름의 이전 파일에 의해 생성되었는지 또는 누군가가 URL이나 POST를 통해 이를 스푸핑했는지 알 수 있는 방법이 없었습니다. 이로 인해 큰 보안 허점이 발생했습니다. download.php 파일에 다음 코드가 포함되어 있다고 가정하고 예제를 통해 살펴보겠습니다.

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

개발자는 아마도 프론트 컨트롤러 패턴으로 자신의 코드를 구현하는 것을 고려했을 것입니다. 즉, 모든 웹 요청이 단일 입력 파일(index.php, home.php 등)을 통과하도록 만드는 것입니다. 이 파일은 세션 초기화, 공통 변수 로드, 마지막으로 요청을 특정 스크립트(이 경우 download.php)로 리디렉션하여 파일을 다운로드하는 역할을 합니다.

그러나 공격자는 앞서 언급한 것처럼 download.php?filepath=/etc/passwd를 호출하기만 하면 계획된 실행 순서를 우회할 수 있습니다. 따라서 PHP는 /etc/passwd 값을 사용하여 전역 변수 $filepath를 자동으로 생성하여 공격자가 시스템에서 해당 파일을 다운로드할 수 있도록 합니다. 심각한 실수입니다.

이것은 빙산의 일각에 불과합니다. 최소한의 노력으로 훨씬 더 위험한 공격을 수행할 수 있기 때문입니다. 예를 들어, 프로그래머가 미완성 스크립트로 남겨둘 수 있는 다음과 같은 코드에서는:

<?php

if (!eregi("modules.php", $HTTP_SERVER_VARS['PHP_SELF'])) {
    die ("You can't access this file directly...");
}

공격자는 RFI(원격 파일 포함) 공격을 사용하여 모든 코드를 실행할 수 있습니다. 따라서 공격자가 실행하려는 코드를 사용하여 자신의 사이트 https://mysite.net에 My.class.php 파일을 생성한 경우 해당 파일에 자신의 도메인인 codigo_inutil.php?base_path=를 전달하여 취약한 스크립트를 호출할 수 있습니다. https://mysite.net, 공격이 완료되었습니다.

또 다른 예: 다음 코드를 사용하는 Remove_file.inc.php라는 스크립트에서:

<?php

if (!defined('MODULE_FILE')) {
    die ("You can't access this file directly...");
}

공격자는 Remove_file.inc.php?filename=/etc/hosts와 같은 URL을 사용하여 이 파일을 직접 호출할 수 있으며 따라서 시스템에서 /etc/hosts 파일을 삭제하려고 시도할 수 있습니다(시스템이 허용하는 경우 또는 다른 방법으로) 삭제 권한이 있는 파일).

내부적으로 전역 변수를 사용하는 WordPress와 같은 CMS에서는 이러한 유형의 공격이 치명적이었습니다. 그러나 지속적인 기술 덕분에 이러한 스크립트와 기타 PHP 스크립트는 보호되었습니다. 마지막 예를 통해 살펴보겠습니다.

<?php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

이제 누군가가 Remove_file.inc.php?filename=/etc/hosts에 액세스하려고 하면 상수가 액세스를 차단합니다. 변수라면 당연히 공격자가 주입할 수 있으므로 상수여야 합니다.

이 시점에서 여러분은 PHP가 이 기능을 그렇게 위험했는데 왜 유지했는지 궁금해하실 것입니다. 또한, 다른 스크립트 언어(JSP, Ruby 등)를 알고 있다면 유사한 것이 없다는 것을 알 수 있습니다(그래서 상수 기술을 사용하지 않습니다). PHP는 C의 템플릿 시스템으로 탄생했으며 이러한 동작이 개발을 촉진했다는 점을 기억하세요. 좋은 소식은 PHP 관리자가 이 기능을 비활성화할 수 있도록 php.ini에 Register_globals(기본적으로 활성화됨)라는 지시문을 도입하기로 결정했다는 것입니다.

그러나 문제가 지속되었기 때문에 기본적으로 비활성화되었습니다. 그럼에도 불구하고 많은 호스트는 클라이언트의 프로젝트가 작동을 멈출 것을 두려워하여 이를 계속 활성화했습니다. 당시 코드의 대부분은 GET/POST/... 값에 액세스하기 위해 권장되는 HTTP_*_VARS 변수를 사용하지 않았기 때문입니다. 오히려 전역 변수입니다.

마침내 상황이 변하지 않는다는 점을 확인한 그들은 과감한 결정을 내렸습니다. 이러한 모든 문제를 피하기 위해 PHP 5.4에서 이 기능을 제거하는 것입니다. 따라서 오늘날 우리가 본 것과 같은 스크립트(상수를 사용하지 않음)는 특정 경우에 무해한 경고/알림을 제외하고는 더 이상 일반적으로 위험을 초래하지 않습니다.

오늘 사용

오늘날에도 꾸준한 기술이 일반적입니다. 그러나 슬픈 점과 이 게시물을 올리게 된 이유는 이 기능을 사용하는 실제 이유를 아는 개발자가 거의 없다는 것입니다.

과거의 다른 모범 사례(예: 호출 시 참조로 인한 위험을 피하기 위해 함수의 매개변수를 로컬 변수에 복사하거나 개인 변수에 밑줄을 사용하여 구분)와 마찬가지로 많은 사람들이 여전히 누군가가 한 번 현재 시대에 실제로 가치를 더하는지 여부를 고려하지 않고 좋은 관행이라고 말했습니다. 현실은 대다수의 경우에 이 기술이 더 이상 필요하지 않다는 것입니다.

이 관행이 관련성을 잃은 몇 가지 이유는 다음과 같습니다.

  • *register globals의 사라짐: PHP 5.4부터 GET 및 POST 변수를 PHP 전역 변수로 등록하는 기능은 더 이상 존재하지 않습니다. 우리가 본 것처럼 *전역 등록 없이 개별 스크립트의 실행은 무해해지며 이러한 관행의 주된 이유가 제거됩니다.

  • 현재 코드의 더 나은 디자인: PHP 5.4 이전 버전에서도 최신 코드는 더 나은 디자인으로 클래스와 함수로 구조화되어 있어 외부 변수를 통한 액세스나 조작이 복잡합니다. 전역 변수를 자주 사용하는 WordPress에서도 이러한 위험은 최소화됩니다.

  • *전면 컨트롤러 사용: 요즘 대부분의 웹 애플리케이션은 잘 설계된 *전면 컨트롤러를 사용합니다. 실행 체인이 주 진입점에서 시작하는 경우에만 실행됩니다. 따라서 누군가가 독립적으로 파일을 업로드하려고 해도 문제가 되지 않습니다. 흐름이 ​​올바른 지점에서 시작되지 않으면 논리가 활성화되지 않습니다.

  • 클래스 자동 로딩: 현재 개발에서는 클래스 자동 로딩을 사용하기 때문에 include 또는 require 사용이 크게 줄었습니다. 이는 초보 개발자가 아닌 이상 위험을 초래할 수 있는 포함 또는 요구(예: 원격 파일 포함 또는 )이 없어야 함을 의미합니다. 로컬 파일 포함).

  • 공개 코드와 비공개 코드의 분리: 많은 최신 CMS 및 프레임워크에서 공개 코드(예: 자산)는 비공개 코드(프로그래밍 코드)와 분리됩니다. 이 조치는 서버에서 PHP가 실패하는 경우 PHP 파일의 코드(상수 기술 사용 여부에 관계없이)가 노출되지 않도록 보장하므로 특히 중요합니다. 이는 전역 등록을 완화하기 위해 특별히 구현되지는 않았지만 다른 보안 문제를 피하는 데 도움이 됩니다.

  • 친숙한 URL의 확장된 사용: 요즘에는 항상 프로그래밍에 대한 단일 진입점을 강제하는 친숙한 URL을 사용하도록 서버를 구성하는 것이 일반적입니다. 이로 인해 누구든지 PHP 파일을 독립적으로 업로드하는 것이 거의 불가능해졌습니다.

  • 프로덕션에서 오류 출력 억제: 대부분의 최신 CMS 및 프레임워크는 기본적으로 오류 출력을 차단하므로 공격자는 다른 유형을 용이하게 할 수 있는 애플리케이션의 내부 작동에 대한 단서를 찾을 수 없습니다. 공격합니다.

이 기술은 대부분의 경우 더 이상 필요하지 않지만 이것이 결코 유용하지 않다는 의미는 아닙니다. 전문 개발자로서 각 사례를 분석하고 지속적인 기술이 작업 중인 특정 상황과 관련이 있는지 결정하는 것이 중요합니다. 이는 모범 사례라고 생각하는 경우에도 항상 적용해야 하는 기준입니다.

의심이 듭니까? 다음은 몇 가지 팁입니다.

지속적인 기술을 언제 적용해야 할지 아직 확실하지 않은 경우 다음 권장 사항을 참고하세요.

  • 항상 이 기술을 사용하세요 귀하의 코드가 PHP 5.4 이전 버전에서 실행될 수 있다고 생각한다면
  • 파일에 클래스 정의만 포함된 경우 사용하지 마세요.
  • 파일에 기능만 포함된 경우 사용하지 마세요.
  • HTML이 어떤 유형의 중요한 정보를 노출하지 않는 한, 파일에 HTML/CSS만 포함된 경우 사용하지 마세요.
  • 파일에 상수만 포함된 경우 사용하지 마세요.

그 외 다 궁금하신 분들은 적용해 보세요. 대부분의 경우 이는 해롭지 않아야 하며, 특히 방금 시작한 경우 예상치 못한 상황에서 사용자를 보호할 수 있습니다. 시간과 경험을 통해 이 기술과 다른 기술을 언제 적용해야 하는지 더 잘 평가할 수 있을 것입니다.

Ese extraño código PHP en frameworks y CMS

계속 배우세요...

  • register_globals - MediaWiki
  • PHP: Register Globals 사용 - 매뉴얼
  • 원격 파일 포함 취약점 [LWN.net]
  • Bugtraq: Mambo Site Server 버전 3.0.X의 심각한 보안 허점

위 내용은 프레임워크와 CMS의 이상한 PHP 코드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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