복붙노트

PHP에서 eval 악마는 언제입니까?

PHP

PHP에서 eval 악마는 언제입니까?

PHP에서 개발해온 모든 해에서 eval ()을 사용하는 것이 악하다고 항상 들었습니다.

다음 코드를 고려할 때 두 번째 (더 우아한) 옵션을 사용하는 것이 합리적이지 않습니까? 그렇지 않다면, 왜?

// $type is the result of an SQL statement
// e.g. SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string
$type = "enum('a','b','c')";

// possibility one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);

// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');

해결법

  1. ==============================

    1.

    나는 eval ()을 순수한 악이라고 부르는 것에 신중할 것이다. 동적 평가는 강력한 도구이며 때로는 생명의 은인이 될 수 있습니다. eval ()을 사용하면 PHP의 단점을 해결할 수 있습니다 (아래 참조).

    eval ()의 주요 문제점은 다음과 같습니다.

    eval ()을 실제로 사용하는 주된 문제는 단 하나입니다.

    엄지 손가락의 규칙에 따라 나는 이것을 따르는 경향이있다 :

  2. ==============================

    2.

    eval은 평가 된 문자열에 사용자 입력이 포함될 가능성이 거의 없을 때 악조건입니다. 사용자가 제공 한 컨텐츠없이 eval을 수행 할 때는 안전해야합니다.

    그럼에도 불구하고 eval을 사용하기 전에 적어도 두 번 생각해야합니다. 간단하게 보이지만 오류 처리 (VBAssassins 주석 참조), 디버깅 가능성 등을 염두에두고 더 이상 간단하지 않습니다.

    그래서 엄지 손가락의 규칙으로 : 잊어 버려. eval이 대답 일 때 당신은 틀림없이 잘못된 질문을합니다! ;-)

  3. ==============================

    3.

    eval ()은 항상 똑같이 악합니다.

    "언제 eval ()이 악하지 않습니까?" 내 의견으로는 잘못된 질문입니다. eval ()을 사용하는 데있어서의 단점이 마술 적으로 일부 상황에서는 사라진다는 것을 암시하는 것처럼 보입니다.

    eval ()을 사용하면 일반적으로 코드의 가독성을 떨어 뜨리기 때문에 런타임 전에 코드 경로 (및 가능한 보안 의미)를 예측할 수 있으므로 코드를 디버깅 할 수 있습니다. eval ()을 사용하면 평가 된 코드와이 코드를 둘러싼 코드가 PHP 5.5 이상에 통합 된 Zend Opcache와 같은 opcode 캐시 또는 HHVM에있는 것과 같은 JIT 컴파일러에 의해 최적화되지 않도록 할 수 있습니다.

    게다가, eval ()을 사용하는 것이 절대적으로 필요하지 않은 상황은 없습니다. PHP는 PHP가없는 완벽한 기능의 프로그래밍 언어입니다.

    실제로 이들을 악으로 간주하는지 또는 eval ()을 사용하여 개인적으로 정당화 할 수 있는지 여부는 경우에 따라 다릅니다. 어떤 사람들에게는 악이 정당화하기에 너무 크고 다른 사람들에게는 eval ()이 편리한 지름길입니다.

    그러나 eval ()을 악으로 간주하면 항상 악합니다. 문맥에 따라 마술처럼 악을 잃지 않습니다.

  4. ==============================

    4.

    이 경우 사용자가 임의의 열을 테이블에 생성 할 수없는 한 eval은 충분히 안전합니다.

    정말 더 이상 우아하지 않습니다. 이것은 기본적으로 텍스트 구문 분석 문제이며 PHP 파서를 처리하는 것을 악용하는 것은 약간 해킹 된 것처럼 보입니다. 언어 기능을 남용하고 싶다면 JSON 구문 분석기를 악용하지 않는 이유는 무엇입니까? 최소한 JSON 구문 분석기를 사용하면 코드를 삽입 할 필요가 없습니다.

    $json = str_replace(array(
        'enum', '(', ')', "'"), array)
        '',     '[', ']', "'"), $type);
    $result = json_decode($json);
    

    아마도 정규 표현식이 가장 확실한 방법 일 것입니다. 하나의 정규식을 사용하여이 문자열에서 모든 값을 추출 할 수 있습니다.

    $extract_regex = '/
        (?<=,|enum\()   # Match strings that follow either a comma, or the string "enum("...
        \'      # ...then the opening quote mark...
        (.*?)       # ...and capture anything...
        \'      # ...up to the closing quote mark...
        /x';
    preg_match_all($extract_regex, $type, $matches);
    $result = $matches[1];
    
  5. ==============================

    5.

    외부 데이터 (예 : 사용자 입력)를 평가판 내부에서 사용할 때.

    위의 예에서는 문제가되지 않습니다.

  6. ==============================

    6.

    eval ()은 느리지 만 악이라고하지는 않습니다.

    코드 삽입과 악의로 이어질 수있는 악용 사례입니다.

    간단한 예 :

    $_GET = 'echo 5 + 5 * 2;';
    eval($_GET); // 15
    

    유해한 예 :

    $_GET = 'system("reboot");';
    eval($_GET); // oops
    

    나는 eval ()을 사용하지 말 것을 권할 것이지만 그렇게 할 경우, 모든 입력을 검증 / 화이트리스트해야한다.

  7. ==============================

    7.

    나는 여기서 내용을 훔칠 것입니다 :

    blog.joshuaeichorn.com : using-eval-in-php

  8. ==============================

    8.

    개인적으로, 나는 코드가 아직도하고있는 것에 대해 논평하지 않기 때문에 코드가 여전히 악하다고 생각합니다. 또한 타당성에 대한 입력을 테스트하지 않으므로 매우 취약합니다.

    또한 95 % (또는 그 이상)의 eval 사용이 위험하기 때문에 다른 경우에 제공 할 수있는 잠재적 인 시간 절약은 그다지 좋지 않은 사용에 가치가 없다고 생각합니다. 또한, 나중에 평가를 사용하는 것이 왜 좋고, 나쁜지를 왜 당신의 부하들에게 설명해야합니다.

    물론 PHP는 Perl과 비슷하게 보입니다.)

    eval ()에는 두 가지 주요 문제점이 있습니다 ( "분사 공격"시나리오).

    1) 해를 끼칠 수 있습니다. 2) 단순히 충돌 할 수 있습니다.

    기술적 인 것보다 사회적인 것 중 하나입니다.

    3) 사람들이 그것을 다른 곳의 지름길로 부적절하게 사용하도록 유혹합니다.

    첫 번째 경우에는 알려진 문자열을 평가할 때가 아니라 임의의 코드 실행 위험이 있습니다. 귀하의 의견은 귀하가 생각하는대로 알려지지 않거나 고정 될 수 없습니다.

    (이 경우) 충돌 할 확률이 높아지고 문자열이 불명확 한 오류 메시지로 종료됩니다. IMHO, 모든 코드는 가능한 한 깔끔하게 실패해야합니다. 오류가 발생하면 예외 처리가 가장 많이 발생합니다.

    이 예제에서, 당신은 행동에 코딩하는 것이 아니라 우연히 코딩하는 것이 좋습니다. 예, SQL enum 문 (필드의 열거 형을 확신합니까? - 올바른 데이터베이스 버전의 오른쪽 테이블을 호출 했습니까? 실제로 대답 했습니까?)는 PHP의 배열 선언 구문처럼 보입니다. 하지만 당신이 정말로하고 싶은 것은 입력에서 출력까지의 최단 경로를 찾는 것이 아니라 지정된 작업을 다루는 것입니다 :

    대략 어떤 옵션인지는 모르겠지만 명확성과 안전성을 위해 그 주변에 주석을 달았습니다 (예 : 첫 번째 일치 항목이 일치하지 않거나 예외를 throw하거나 null 결과를 설정 한 경우).

    이스케이프 된 쉼표 나 따옴표에는 여전히 문제가있을 수 있습니다. 따라서 데이터를 압축 해제 한 후 압축을 풀어서 코드로 처리하는 것이 아니라 데이터로 처리해야합니다.

    preg_version을 사용하면 최악의 결과는 $ result = null이 될 수 있습니다. 평가 버전은 최악은 알 수 없지만 적어도 충돌은 발생합니다.

  9. ==============================

    9.

    나는 또한 당신의 코드를 관리하는 사람들에게 약간의 배려를 할 것이다.

    eval ()은 단지 무엇을 봐야 할 지 알기가 쉽지 않다. 예제가 그렇게 나쁘지는 않지만 다른 곳에서는 악몽 일 수있다.

  10. ==============================

    10.

    eval은 문자열을 코드로 평가합니다. 문제는 문자열이 어떤 방식 으로든 "오염되어"엄청난 보안 위협을 노출 할 수있는 경우입니다. 일반적으로 문제는 사용자 입력이 문자열에서 평가되는 경우입니다. 많은 경우 사용자가 eval 내에서 실행되는 코드 (예 : php 또는 ssi)를 입력 할 수 있으며 PHP 스크립트와 동일한 권한으로 실행되고 귀하의 서버에 대한 정보 / 액세스를 얻는 데 사용하십시오. 사용자 입력이 eval에 전달되기 전에 제대로 지워지는 것은 매우 까다로운 일일 수 있습니다. 다른 문제가 있습니다 ... 그 중 일부는 논쟁의 여지가 있습니다

  11. ==============================

    11.

    PHP는 명시 적 evals 대신 call_user_func를 통해 실행될 수있는 방식으로 코드를 작성하도록 조언합니다.

  12. ==============================

    12.

    eval ()은 항상 악합니다.

  13. ==============================

    13.

    eval이 악의가있는 또 다른 이유는 eAccelertor 나 ACP와 같은 PHP 바이트 코드 캐시에 의해 캐시 될 수 없다는 것입니다.

  14. ==============================

    14.

    함수가 아니라 eval ()을 악으로 만드는 나쁜 프로그래밍입니다. 여러 사이트에서 동적 프로그래밍을 할 수 없기 때문에 때때로 사용합니다. 필자가 원했던 것을받지 않기 때문에 한 사이트에서 PHP를 파싱 할 수 없습니다. 나는 다만 결과를 얻을 것입니다! 내 인생을 훨씬 더 쉽게 만들어주는 eval ()이 존재하는 것처럼 행복하다. 사용자 입력? 나쁜 프로그래머들만 해커들에게 매여있다. 나는 그것에 대해 걱정하지 않는다.

  15. ==============================

    15.

    나는 당신이 곧 심각한 문제가 발생할 것이라고 예측합니다 ...

    모든 정직한면에서 PHP와 같은 해석 된 언어에서 eval과 같은 과도한 함수를 사용하는 것은 절대적으로 바람직하지 않습니다. 나는 eval이 다른, 더 안전한 방법을 사용하여 실행할 수 없었던 프로그램 기능을 수행하는 것을 본 적이 없다 ...

    평가는 모든 악의 근원이며, 사용자 입력 테스트가 도움이된다고 생각하는 모든 사람들에게 전적으로 동의합니다. 두 번 생각해보십시오. 사용자 입력은 다양한 형태로 나타날 수 있습니다. 우리가 말하는 것처럼 해커는 충분히 신경 쓰지 않는 기능을 이용하고 있습니다. 내 의견으로는, 그냥 평가 절대로 모두 피하십시오.

    나는 내 자신의 창의력을 능가하는 평가 함수를 남용하기 위해 만들어진 예를 보았다. 보안 입장에서는 모든 비용을 피하십시오. 필자는 '주어진'것이 라기보다 PHP 구성에서 옵션이되도록 요구할 것입니다.

  16. ==============================

    16.

    나는 eval ()을 많이 사용 했었지만 트릭을하기 위해 eval을 사용할 필요가없는 대부분의 경우를 발견했다. PHP에서는 call_user_func ()과 call_user_func_array ()가 있습니다. 정적으로 동적으로 호출하는 것만으로도 충분합니다.

    정적 호출을 수행하려면 콜백을 array ( 'class_name', 'method_name') 또는 'class_name :: method_name'과 같은 간단한 문자열로 구성하십시오. 동적 호출을 수행하려면 array ($ object, 'method') 스타일 콜백을 사용하십시오.

    eval ()을 사용하는 유일한 방법은 맞춤 컴파일러를 작성하는 것입니다. 하나 만들었지 만 eval은 여전히 ​​악마입니다. 왜냐하면 디버깅하기가 너무 어렵 기 때문입니다. 최악의 상황은 evaled 코드에서 치명적인 오류가 발생한 코드를 충돌시키는 것입니다. 구문 분석을 위해 Parsekit PECL 확장을 사용했지만 적어도 기쁨은 없습니다. 알 수없는 클래스와 전체 응용 프로그램 충돌을 참조하려고합니다.

  17. ==============================

    17.

    보안 문제 외에도 eval ()은 컴파일, 최적화 또는 opcode 캐싱 될 수 없으므로 일반 PHP 코드보다 느리게 느려질 것입니다. 따라서 악의가 아니더라도 평가판을 사용하는 것은 비 효과적입니다. (goto는 악마, eval은 나쁜 습관 / smelly code / 추한)

  18. ==============================

    18.

    eval을 사용하지 않고 데이터베이스에서 가져온 PHP 코드를 실행하는 솔루션입니다. 범위 함수 및 예외를 모두 허용합니다.

    $rowId=1;  //database row id
    $code="echo 'hello'; echo '\nThis is a test\n'; echo date(\"Y-m-d\");"; //php code pulled from database
    
    $func="func{$rowId}";
    
    file_put_contents('/tmp/tempFunction.php',"<?php\nfunction $func() {\n global \$rowId;\n$code\n}\n".chr(63).">");
    
    include '/tmp/tempFunction.php';
    call_user_func($func);
    unlink ('/tmp/tempFunction.php');
    

    기본적으로 텍스트 파일에 포함 된 코드로 고유 한 함수를 만들고 파일을 포함하고 함수를 호출 한 다음 완료되면 파일을 제거합니다. 나는 모든 단계에서 처리 할 수있는 고유 코드가 필요한 일일 데이터베이스 수집 / 동기화를 수행하는 데이 방법을 사용하고 있습니다. 이것은 나가 직면하고 있던 모든 문제점을 해결했다.

  19. from https://stackoverflow.com/questions/951373/when-is-eval-evil-in-php by cc-by-sa and MIT lisence