언제 php에서 eval evil이 됩니까?

내가 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')";
// option one $type_1 = preg_replace('#^enums*(s*' 's*)s*$#', '', $type); $result = preg_split('#'s*,s*'#', $type_1);
// option two eval('$result = '.preg_replace('#^enum#','array', $type).';'); 


질문에 대한 답변



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

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

  • 안전하지 않은 입력일 수 있습니다.신뢰할 수 없는 파라미터를 전달하는 것은 실패하는 방법입니다.파라미터(또는 파라미터의 일부)를 완전히 신뢰하는 것은 보통 간단한 작업이 아닙니다.
  • 속임수.eval()을 사용하면 코드가 영리해지기 때문에 따라가기가 어려워집니다.Brian Kernighan의 말을 인용하자면, “디버깅은 애초에 코드를 작성하는 것보다 두 나 더 어렵습니다. 따라서 가능한 한 현명하게 코드를 작성하면 디버깅할 있을 만큼 똑똑하지 않습니다.

eval()의 실제 사용에 관한 주요 문제는 다음 중 하나입니다.

  • 충분히 고려하지 않고 사용하는 경험이 없는 개발자.

경험에 비추어 볼 때, 저는 다음과 같은 것을 따르는 경향이 있습니다.

  1. eval()이 유일한/올바른 솔루션일 수 있습니다.
  2. 대부분의 경우 다른 것을 시도해야 합니다.
  3. 확실하지 않으면 2번으로 이동합니다.
  4. 그렇지 않으면, 아주, 아주 조심해요.



평가된 문자열에 사용자 입력이 포함될 가능성이 극히 적은 경우 eval은 악의적입니다.사용자로부터 받은 콘텐츠가 없는 상태에서 평가를 수행하는 경우 안전해야 합니다.

단, eval을 사용하기 전에 적어도 두 번 생각해야 합니다.이것은 기만적으로 단순해 보이지만, 에러 처리(VBAssassins 코멘트 참조), 디버깅 가능성 등을 염두에 두고 있기 때문에, 이것은 더 이상 간단하지 않습니다.

경험으로 봤을 때:그냥 잊어버려.eval이 정답인 경우 잘못된 질문을 하는 것이 적절합니다.;-)




eval은 항상 똑같이 “악”입니다.

악으로 본다면, 항상 똑같이 악입니다.많은 사람들이 그것을 악으로 묘사하는 이유는 맥락과 함께 사라지지 않는다.

일반적으로 eval()을 사용하면 코드의 가독성이 떨어지기 때문에 실행 시 코드 패스를 예측하는 기능이 저하되고(보안상의 영향이 있을 수 있음) 코드 분석 및 디버깅 기능에 영향을 미칩니다.eval()을 사용하면 평가된 코드와 코드 주변의 코드가 PHP 5.5 이상에 통합된 Zend Opcache와 같은 opcode 캐시나 HHVM과 같은 JIT 컴파일러에 의해 최적화되는 것을 방지할 수 있습니다.

또한 eval()을 사용할 필요가 전혀 없습니다.PHP는 이 기능이 없는 완전한 프로그래밍 언어입니다.eval()을 사용하는 목적에 관계없이 PHP에서는 다른 방법이 있습니다.

이것들을 실제로 악으로 보는지, 아니면 개인적으로 eval()을 사용하는 것을 정당화할 수 있는지 여부는 당신에게 달려 있습니다.어떤 사람들에게는 함정이 너무 커서 그것을 정당화할 수 없고 어떤 사람들에게는 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]; 



eval()느리지만 악하다고는 할 수 없어요.

코드를 주입하고 악하게 만드는 건 우리가 잘못 사용하는 거야

간단한 예:

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

유해한 예:

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

사용하지 않는 것이 좋습니다.eval()단, 모든 입력을 검증/화이트리스트로 해야 합니다.