내가 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()의 실제 사용에 관한 주요 문제는 다음 중 하나입니다.
- 충분히 고려하지 않고 사용하는 경험이 없는 개발자.
경험에 비추어 볼 때, 저는 다음과 같은 것을 따르는 경향이 있습니다.
- eval()이 유일한/올바른 솔루션일 수 있습니다.
- 대부분의 경우 다른 것을 시도해야 합니다.
- 확실하지 않으면 2번으로 이동합니다.
- 그렇지 않으면, 아주, 아주 조심해요.
평가된 문자열에 사용자 입력이 포함될 가능성이 극히 적은 경우 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()
단, 모든 입력을 검증/화이트리스트로 해야 합니다.