JavaScript의 eval ()은 언제 사악하지 않습니까?


263

스프레드 시트와 같은 기능을 위해 사용자가 입력 한 함수를 구문 분석하기 위해 JavaScript 코드를 작성하고 있습니다. 나는 수식 구문 분석하는 데 수있는 자바 스크립트로 변환하고 실행 eval()결과를 산출하는 데에있다.

그러나, 나는 eval()그것이 악하기 때문에 피할 수 있다면 항상 사용 하지 말았습니다. ).

그렇다면 언제 사용해도 되나요?


5
대부분의 JSON 라이브러리는 실제로 보안 위험으로부터 정확히 보호하기 위해 실제로 eval을 사용하지 않습니다.
Sean McMillan

11
@Sean-JQuery와 프로토 타입 모두 eval 사용 (JQuery는 새로운 기능을 통해 사용)
plodder

5
@plodder-어디에서 정보를 얻습니까? jQuery는 1.4부터 네이티브 JSON.parse ()를 사용했습니다 (1/2010으로 거슬러 올라갑니다)! 직접보기 : code.jquery.com/jquery-1.4.js
ken

3
"분명히 eval ()을 사용하여 JSON을 구문 분석해야합니다." -이것은 사실이 아닙니다. 반대로 JSON을 구문 분석하기 위해 eval을 사용해서는 안됩니다! json.org 의 Douglas Crockfords (JSON 생성자) json2.js 스크립트를 사용 하십시오 !
TMS

11
@sons json2.js가 eval을 사용하여 JSON을 구문 분석한다는 아이러니를 토마스
tobyodavies

답변:


262

귀하의 질문의 전제를 해결하기 위해 잠시 시간을 내고 싶습니다-eval ()은 " "입니다. 프로그래밍 언어 사용자가 사용하는 " " 이라는 단어 는 일반적으로 "위험한"또는보다 정확하게는 "단순한 명령으로 많은 해를 입힐 수 있음"을 의미합니다. 언제 위험한 것을 사용해도 되나요? 위험이 무엇인지, 적절한 예방 조치를 취할 때.

지금까지 eval ()을 사용할 때의 위험을 살펴 보자. 아마도 다른 모든 것과 마찬가지로 작은 숨겨진 위험이 많을 수도 있지만, eval ()이 악하다고 여겨지는 두 가지 큰 위험은 성능과 코드 삽입입니다.

  • 성능-eval ()은 인터프리터 / 컴파일러를 실행합니다. 코드가 컴파일되면 런타임 중에 무거운 컴파일러를 호출해야하기 때문에 큰 타격입니다. 그러나 JavaScript는 여전히 대부분 통역 언어이므로 eval ()을 호출하는 것이 일반적인 경우에 큰 영향을 미치지는 않습니다 (그러나 아래의 특정 설명 참조).
  • 코드 삽입-eval ()은 높은 권한으로 잠재적으로 코드 문자열을 실행합니다. 예를 들어, 관리자 / 루트로 실행중인 프로그램은 입력이 "rm -rf / etc / important-file"이상일 수 있으므로 사용자 입력을 eval ()하기를 원하지 않습니다. 프로그램이 사용자의 계정에서 실행되고 있기 때문에 브라우저의 JavaScript에는 문제가 없습니다. 서버 측 JavaScript에 문제가있을 수 있습니다.

당신의 특정한 경우에. 내가 이해 한 바에 따르면, 문자열을 직접 생성하고 있으므로 "rm -rf something-important"와 같은 문자열이 생성되지 않도록주의를 가정하면 코드 삽입 위험이 없습니다 (그러나 매우 중요합니다. 일반적인 경우에는 이것을 보장하기 어렵다 ). 또한 브라우저에서 실행하는 경우 코드 삽입이 매우 위험합니다.

성능에 관해서는 코딩의 용이성에 대해 가중치를 부여해야합니다. 수식을 구문 분석하는 경우 다른 구문 분석기 (eval () 내부의 구문 분석기)를 실행하지 않고 구문 분석 중에 결과를 계산할 수도 있다고 생각합니다. 그러나 eval ()을 사용하여 코딩하는 것이 더 쉬울 수 있으며 성능 저하는 눈에 띄지 않을 것입니다. 이 경우 eval ()은 시간을 절약 할 수있는 다른 함수보다 더 나쁘지 않습니다.


78
eval을 사용하여 디버깅하기 어려운 코드 문제는 다루지 않습니다.
bobobobo

48
코드 삽입은 사용자 데이터에 전혀 관심이있는 경우 자바 스크립트에서 매우 심각한 문제입니다. 삽입 된 코드는 마치 사이트에서 온 것처럼 브라우저에서 실행되므로 사용자가 수동으로 수행 할 수있는 모든 종류의 shenanigan을 수행 할 수 있습니다. (타사) 코드가 귀하의 페이지에 들어가도록 허용하면 고객을 대신하여 주문하거나 Gravatar를 변경하거나 사이트를 통해 할 수있는 모든 작업을 수행 할 수 있습니다. 정말 조심하세요. 해커가 고객을 소유하게하는 것은 서버를 소유하게하는 것만 큼 나쁩니다.
Sean McMillan

71
데이터가 서버 및 사용자가 생성 한 데이터에서 오는 경우 eval ()을 사용하면 아무런 해가 없습니다. 진짜 해는 당신이 읽는 모든 것을 산다는 것입니다. 많은 사람들이 eval ()이 악하다고 말하고 어딘가에서 읽은 것을 제외하고는 이유를 모릅니다.
Vince Panuccio

42
@Sean McMillan : 당신을 믿기를 원하지만 누군가가 eval()귀하의 서버에서 자바 스크립트를 가로 채서 변경하려고 한다면 페이지 소스를 먼저 변경하고 사용자 정보를 제어 할 수도 있습니다. . . 차이가 보이지 않습니다.
Walt W

20
"코드 삽입-... 다시 말하지만, 브라우저의 JavaScript에는 그런 문제가 없습니다."& "또한 브라우저에서 실행중인 경우 코드 삽입은 매우 사소한 위험입니다." 브라우저에서 코드 삽입이 문제가 아니라고 제안하고 있습니까? XSS는 몇 년 동안 OWASP의 상위 10 개 목록에서 3 위를 차지했습니다.
Mike Samuel

72

eval()악하지 않다. 또는 다른 언어에서는 리플렉션, 파일 / 네트워크 I / O, 스레딩 및 IPC가 "악"인 것과 같은 방식으로 악합니다.

, 경우 당신의 목적을 위해 , eval()수동 해석보다 빠르게, 또는 코드가 간단하고, 또는 더 명확하게 ... 당신은 그것을 사용해야합니다. 둘 다 아니라면 안됩니다. 그렇게 간단합니다.


5
그러한 목적 중 하나는 손으로 작성하기에는 너무 길거나 반복적 인 최적화 된 코드를 생성하는 것입니다. LISP에서 매크로를 요구하는 것들.
wberry

5
이것은 문자 그대로 존재하는 모든 코드 블록에 적용될 수 있다는 일반적인 조언입니다. 실제로이 질문에는 아무 것도 추가하지 않습니다. 특히, 여기에 오는 사람은 자신의 특정 사용에 문제가 있는지 여부를 판단하는 데 도움이되지 않습니다.
jpmc26

2
더 빠르고 간단하고 명확합니다 ...이 답변은 보안 관련 내용을 충분히 다루지 않습니다.
Ruud Helderman

55

출처를 신뢰할 때

JSON의 경우 소스를 제어하는 ​​웹 서버에서 제공되므로 소스를 변경하기가 다소 어렵습니다. JSON 자체에 사용자가 업로드 한 데이터가 없으면 eval을 사용하는 데 큰 결점이 없습니다.

다른 모든 경우에는 eval ()에 공급하기 전에 사용자가 제공 한 데이터가 내 규칙을 준수하는지 확인하기 위해 많은 시간을 할애합니다.


13
json 문자열은 eval ()에서 사용하기 전에 항상 json 문법에 대해 테스트해야합니다. 따라서 "alert ( 'XSS')"이 올바른 값이 아니므로 json 문자열 "{foo : alert ( 'XSS')}"이 전달되지 않습니다.
Gumbo

3
그렇다면 HTTPS를 사용하십시오. OTOH : 중간자 (man-in-the-middle)는 가든 버라이어티 웹 앱의 일반적인 공격 시나리오는 아니지만 크로스 사이트 스크립팅입니다.
Tomalak

7
eval모든 유효한 JSON 문자열을 올바르게 구문 분석하지는 않습니다. 예를 들어 JSON.parse(' "\u2028" ') === "\u2028"있지만, eval(' "\u2028" ')U + 2028은 자바 스크립트에서 줄 바꿈하지만 그것은 멀리 JSON에 관한 한 줄 바꿈이 아니기 때문에 예외를 발생시킵니다.
Mike Samuel

1
@Justin-프로토콜이 손상되면 일반적으로 초기 페이지로드가 동일한 프로토콜을 통해 전송 된 것이므로 클라이언트가 이미 가능한 한 손상 되었기 때문에 문제가됩니다.
antinome

1
@Tomalak이 아름답게 말했다, 나는 지금 내 대답에서 이것을 언급했다! 대박!
NiCk Newman 오전

25

진짜 사람들을 만나자 :

  1. 모든 주요 브라우저에는 이제 해커가 풍부하게 사용할 수있는 콘솔이 내장되어 있습니다. 가능한 경우에도 eval 문을 사용하는 이유가 무엇입니까?

  2. 2000 줄의 JavaScript를 컴파일하는 데 0.2 초가 걸리는 경우 4 줄의 JSON을 평가하면 성능이 어떻게 저하됩니까?

'eval is evil'에 대한 Crockford의 설명조차 약합니다.

eval은 악, eval 함수는 JavaScript에서 가장 많이 사용되는 기능입니다. 피하세요

Crockford 자신도 "이러한 진술은 비이성적 인 신경증을 유발하는 경향이 있습니다. 그것을 사지 마십시오."

평가를 이해하고 언제 유용한 지 아는 것이 더 중요합니다. 예를 들어, eval은 소프트웨어에서 생성 된 서버 응답을 평가하는 데 유용한 도구입니다.

BTW : Prototype.js는 eval을 직접 5 번 호출합니다 (evalJSON () 및 evalResponse () 포함). jQuery는 parseJSON에서 (함수 생성자를 통해) 사용합니다.


10
JQuery는 사용 가능한 경우 브라우저의 내장 JSON.parse 함수를 사용하며 (더 빠르고 안전합니다) 평가 메커니즘을 폴백 메커니즘으로 만 사용합니다. "평가는 악하다"라는 말은 합리적으로 좋은 지침입니다.
jjmontes

30
"모든 주요 브라우저에는 이제 콘솔이 내장되어 있습니다 ...". 코드 삽입은 한 사용자가 다른 사용자의 브라우저에서 실행되는 코드를 입력 할 수있는 경우 문제입니다. 브라우저 콘솔 자체는 한 사용자가 다른 사용자 브라우저에서 코드를 실행할 수 없으므로 코드 삽입으로부터 보호 할 가치가 있는지 여부를 결정할 때 관련이 없습니다.
Mike Samuel

28
"모든 주요 브라우저에는 이제 콘솔이 내장되어 있습니다. 왜 eval 문을 사용하겠습니까?" -당신은 표를 벗어났습니다. 나는 당신이 대답을 편집하는 것이 좋습니다. 한 사용자가 다른 사용자의 브라우저에서 실행할 수있는 코드를 삽입 할 수있는 능력은 중요한 문제입니다. 그리고 이것은 당신이 정말로 현실이되어야하는 곳입니다.
akkishore

5
@akkishore, 위에서 언급 한 진술을 뒷받침하는 실제 사례를 생각해 내면 감사하겠습니다.
Akash Kava

7
@AkashKava 당신이 깨닫지 못하는 것은 내 코멘트 상자에 자바 스크립트를 제출하면 그 자바 스크립트가 데이터베이스에 그것을 만든다는 것입니다. 다른 사용자가 해당 주석 (자바 스크립트를 넣은)을 볼 때 eval은 렌더링 될 때 해당 자바 스크립트를 가져 와서 인터프리터를 사용하여 평가하여 내 임베디드 자바 스크립트가 다른 사용자의 브라우저에서 실행되도록합니다. 이렇게하면 모든 종류의 정보를 볼 수 있습니다. 사용자 이름, 데이터베이스의 사용자 ID, 전자 메일 주소 등. 이것은 어려운 답변이 아닙니다. Googled XSS를 가지고 있다면 약 10 초 후에 왜 문제인지 알 수 있습니다.
Kyle Richter

18

에 대한 Crockford의 조언 을 따르는 경향이 eval()있습니다. 그것을 요구하는 것처럼 보이는 방법조차도 필요하지 않습니다. 예를 들어, setTimeout()eval 대신 함수를 전달할 수 있습니다.

setTimeout(function() {
  alert('hi');
}, 1000);

그것은 경우에도 신뢰할 수있는 소스 JSON에 의해 반환 된 코드는 기껏 뭔가 남았습니다가, 최악의, 뭔가 나쁜 노출 할 수있는 왜곡 될 수 있기 때문에, 나는 그것을 사용하지 마십시오.


2
서버 측의 JSON 포맷터 버그는 분명히 문제라고 생각합니다. 서버의 응답은 사용자가 제출 한 모든 종류의 텍스트에 의존합니까? 그런 다음 XSS를 감시해야합니다.
swilliams

3
웹 서버가 HTTPS를 통해 인증되지 않으면 다른 호스트가 요청을 가로 채고 자체 데이터를 보내는 일종의 중간자 공격이 발생할 수 있습니다.
벤 콤비

11
누군가 중간자 공격을 수행 할 수 있으면 스크립트에 무엇이든 쉽게 주입 할 수 있습니다.
el.pescado

10
당신은 전혀 자바 스크립트 코드에 의존해서는 안됩니다 ... 당신은 클라이언트 측에서 실행되는 것에 의존하지 않습니다 ... 누군가가 중간자 공격을하는 경우 왜 json 객체를 망칠 것입니까? 그는 당신과 다른 js 파일에 다른 웹 페이지를 제공 할 수 있습니다 ...
Calmarius

5
저는 개인적으로 "언제나 다른 방법이 있습니다"라는 주장을 싫어합니다. 예를 들어, 객체 지향 프로그래밍을 피할 수있는 방법이 항상 있다고 말할 수도 있습니다. 그렇다고 훌륭한 옵션은 아닙니다. eval을 이해하고 위험을 이해한다면 올바른 상황에서 사용하기에 좋은 도구가 될 수 있습니다.
dallin

4

나는 사람들이 있기 때문에, 평가를 사용하지 옹호했다 , 그러나 나는 그들이 평가를 사용하므로 같은 사람이 동적으로 기능과의 setTimeout을 사용했다 후드 아래 : D를

BTW, 샌드 박스가 확실하지 않은 경우 (예 : 코드 삽입을 허용하는 사이트에서 작업중인 경우) eval이 마지막 문제입니다. 보안의 기본 규칙은 모든 입력이 악의적이지만 JavaScript의 경우 JavaScript 자체도 악의적 일 수 있습니다. JavaScript에서는 모든 기능을 덮어 쓸 수 있고 실제 기능을 사용하고 있는지 확신 할 수 없기 때문입니다. 악성 코드가 시작되기 전에 JavaScript 내장 기능을 신뢰할 수 없습니다 : D

이제이 게시물의 서사시는 다음과 같습니다.

당신이 정말로 그것을 필요로하고 (시간의 80 %가 필요 하지 않음 ) 당신이하고있는 일을 확신한다면, eval (또는 더 나은 기능;)을 사용하십시오. 폐쇄와 OOP는 80/90 %의 다른 종류의 논리를 사용하여 eval을 대체 할 수있는 경우 나머지는 동적으로 생성 된 코드 (예 : 인터프리터를 작성하는 경우)이며 이미 JSON을 평가한다고 말했듯이 (여기서는 Crockford 안전 평가를 사용할 수 있습니다.)


그리고 크록 포드 혼자서 뾰족한 아웃으로 , 현재 웹 브라우저가 내장 된 기능이 JSON.parse .
Ruud Helderman

4

Eval은 코드 템플릿에 사용되는 컴파일을 보완합니다. 템플릿을 사용하면 개발 속도를 높이는 유용한 템플릿 코드를 생성하는 단순화 된 템플릿 생성기를 작성합니다.

개발자가 EVAL을 사용하지 않는 프레임 워크를 작성했지만 프레임 워크를 사용하므로 템플릿을 생성하려면 EVAL을 사용해야합니다.

다음 방법을 사용하여 EVAL의 성능을 향상시킬 수 있습니다. 스크립트를 실행하는 대신 함수를 반환해야합니다.

var a = eval("3 + 5");

그것은 다음과 같이 구성되어야합니다

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

캐싱 f는 확실히 속도를 향상시킵니다.

또한 Chrome에서는 이러한 기능을 매우 쉽게 디버깅 할 수 있습니다.

보안과 관련하여 eval 사용 여부는 거의 차이가 없습니다.

  1. 우선, 브라우저는 샌드 박스에서 전체 스크립트를 호출합니다.
  2. EVAL에서 사악한 코드는 브라우저 자체에서 사악합니다. 공격자 또는 누구나 DOM에 스크립트 노드를 쉽게 주입하고 평가할 수 있으면 무엇이든 할 수 있습니다. EVAL을 사용하지 않으면 아무런 차이가 없습니다.
  3. 유해한 서버 측 보안은 대부분 열악합니다. 쿠키 유효성 검사가 불량하거나 서버에서 ACL을 잘못 구현하면 대부분의 공격이 발생합니다.
  4. Java의 네이티브 코드에는 최근 Java 취약점 등이있었습니다. 자바 스크립트는 샌드 박스에서 실행되도록 설계되었으며 애플릿은 인증서 등을 사용하여 샌드 박스 외부에서 실행되도록 설계되어 취약점 및 기타 여러 가지 사항을 초래합니다.
  5. 브라우저를 모방하기위한 코드 작성은 어렵지 않습니다. 즐겨 사용하는 사용자 에이전트 문자열을 사용하여 서버에 HTTP 요청을하면됩니다. 모든 테스트 도구는 브라우저를 조롱합니다. 공격자가 당신에게 피해를 입히고 싶다면 EVAL이 최후의 수단입니다. 서버 측 보안을 처리하는 다른 많은 방법이 있습니다.
  6. 브라우저 DOM은 사용자 이름이 아닌 파일에 액세스 할 수 없습니다. 실제로 eval이 액세스 할 수있는 시스템은 없습니다.

서버 측 보안이 어느 곳에서나 공격 할 수있을 정도로 견고하다면 EVAL에 대해 걱정할 필요가 없습니다. 앞에서 언급했듯이 EVAL이 존재하지 않으면 공격자는 브라우저의 EVAL 기능에 관계없이 서버를 해킹 할 수있는 많은 도구를 가지고 있습니다.

Eval은 미리 사용되지 않은 것을 기반으로 복잡한 문자열 처리를 수행하기 위해 일부 템플릿을 생성하는 데만 적합합니다. 예를 들어 선호합니다

"FirstName + ' ' + LastName"

반대로

"LastName + ' ' + FirstName"

내 표시 이름으로 데이터베이스에서 가져올 수 있고 하드 코딩되지 않았습니다.


eval-대신 function을 사용할 수 있습니다 function (first, last) { return last + ' ' + first }.
Konrad Borowski

열 이름은 데이터베이스에서 가져옵니다.
Akash Kava

3
의 위협 eval은 대부분 다른 사용자 입니다. 설정 페이지가 있고 이름이 다른 사람에게 표시되는 방식을 설정할 수 있다고 가정 해 봅시다. 또한 글을 쓸 때 명확하게 생각하지 않았다고 가정하면 선택 상자에 다음과 같은 옵션이 있습니다 <option value="LastName + ' ' + FirstName">Last First</option>. 개발 도구를 열고 value옵션을로 alert('PWNED!')변경하고 변경된 옵션을 선택한 다음 양식을 제출합니다. 이제 다른 사람이 내 표시 이름을 볼 수있을 때마다 해당 코드가 실행됩니다.
cHao

@ cHao, 당신이 말하고있는 것은 나쁜 서버 측 보안의 예입니다. 서버는 다른 사람의 브라우저에서 코드로 실행될 수있는 데이터를 절대 받아 들여서는 안됩니다. 다시 한 번, 서버 측 보안 불량 개념을 이해하지 못했습니다.
Akash Kava

1
원하는 경우 서버 측 보안에 대해 걱정할 수 있지만 요점은 eval작성한 스크립트의 일부가 아닌 코드를 실행하는 것입니다. 그렇게 할 힘이 필요하지 않은 경우 (거의 전혀하지 않아도되는 경우) 피 eval하면 전체 범주의 문제를 해결할 수 있습니다. 서버 측 코드가 완벽하지 않은 경우에 좋습니다.
cHao

4

Chrome (v28.0.1500.72)에서 디버깅 할 때 변수가 클로저를 생성하는 중첩 함수에서 사용되지 않으면 클로저에 바인딩되지 않습니다. 나는 그것이 JavaScript 엔진의 최적화라고 생각합니다.

그러나 : eval()클로저를 일으키는 함수 내에서 사용될 때 , 외부 함수의 모든 변수는 전혀 사용되지 않더라도 클로저에 바인딩됩니다. 누군가 메모리 누수로 인해 테스트 할 시간이 있다면 아래에 의견을 남겨주세요.

내 테스트 코드는 다음과 같습니다.

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

내가 여기서 지적하고 싶은 것은 eval ()이 반드시 기본 eval()함수를 참조해서는 안된다는 것입니다. 그것은 모두 함수의 이름에 달려 있습니다 . 따라서 eval()별칭 이름 (예 var noval = eval;: 내부 함수 noval(expression);)으로 네이티브 를 호출 expression할 때 클로저에 포함되어야하지만 실제로는 그렇지 않은 변수를 참조 할 때 평가 가 실패 할 수 있습니다.



3

결론

당신이 코드를 만들었거나 위생 처리했다면 eval결코 악할 수 없습니다 .

약간 더 자세한

eval이다 악마 된 클라이언트에 의해 제출 된 입력을 사용하여 서버에서 실행중인 경우 개발자가 작성되지 또는 한 개발자에 의해 살균 없습니다 .

eval이다 악하지 클라이언트에서 실행중인 경우 클라이언트에 의해 만들어진 unsanitized 입력을 사용하는 경우에도 .

분명히 코드가 소비하는 것을 약간 제어하기 위해 항상 입력을 위생 처리 해야 합니다.

추리

클라이언트는 개발자가 코드를 작성하지 않더라도 원하는 임의의 코드를 실행할 수 있습니다. 이뿐만 아니라 마찬가지입니다 무엇 evaled되지만 를 호출 eval자체 .


2

eval ()을 사용해야하는 유일한 경우는 동적 JS를 즉시 실행해야하는 경우입니다. 서버에서 비동기 적으로 다운로드하는 JS에 대해 이야기하고 있습니다 ...

... 10 회 중 9 회는 리팩토링을 통해이를 피할 수 있습니다.


요즘 서버에서 JavaScript를 비동기식으로로드하는 다른 방법이 있습니다. w3bits.com/async-javascript
Ruud Helderman

1

eval거의 올바른 선택이 아닙니다. 연관 배열 표기법 (: 당신은 당신이 함께 스크립트을 연결하고 즉석에서 그것을 실행하여 달성하기 위해 필요한 수행 할 수있는 다양한 경우가있을 수 있지만, 일반적으로 훨씬 더 강력하고 귀하의 처분에 유지 관리 기술이 obj["prop"]와 동일 obj.prop) , 클로저, 객체 지향 기술, 기능적 기술-대신 사용하십시오.


1

클라이언트 스크립트가 진행되는 한, 보안 문제는 논란의 여지가 있다고 생각합니다. 브라우저에로드 된 모든 내용은 조작이 가능하므로 처리해야합니다. 브라우저의 URL 표시 줄과 같이 DOM에서 JavaScript 코드를 실행 및 / 또는 객체를 조작하는 훨씬 쉬운 방법이있는 경우 eval () 문을 사용할 위험이 없습니다.

javascript:alert("hello");

누군가 자신의 DOM을 조작하고 싶다면 스윙을 멀리하십시오. 모든 유형의 공격을 방지하는 보안은 항상 서버 응용 프로그램의 책임입니다.

실용적인 관점에서 볼 때 상황이 다른 경우 eval ()을 사용하면 이점이 없습니다. 그러나 eval을 사용해야하는 특정한 경우가 있습니다. 그렇다면 페이지 폭파 위험없이 확실히 수행 할 수 있습니다.

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

6
"DOM에서 자바 스크립트를 실행하거나 객체를 조작하는 훨씬 쉬운 방법이있을 때 eval () 문을 사용할 위험이 전혀 없습니다" 코드 삽입은 한 사용자가 다른 사용자의 브라우저에서 실행되는 코드를 입력 할 수있는 경우 문제입니다. 브라우저 콘솔 자체는 한 사용자가 다른 사용자 브라우저에서 코드를 실행할 수 없으므로 코드 삽입으로부터 보호 할 가치가 있는지 여부를 결정할 때 관련이 없습니다.
Mike Samuel

<head></head>비어 있어도 필요 하지 않습니까?
피터 Mortensen

2
이 답변은 XSS 의 위험을 완전히 무시합니다 .
Ruud Helderman

1

서버 측 eval은 sql 또는 influxdb 또는 mongo와 같은 외부 스크립트를 처리 할 때 유용합니다. 서비스를 다시 배포하지 않고 런타임시 사용자 지정 유효성 검사를 수행 할 수있는 위치

예를 들어 다음 메타 데이터가 포함 된 업적 서비스

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

그런 다음 허용

  • JSON에서 리터럴 문자열을 통해 객체 / 값을 직접 주입하여 텍스트 템플릿에 유용

  • CMS에서 퀘스트 또는 이벤트의 유효성을 검사하는 방법을 규칙이라고 말하면 비교기로 사용할 수 있습니다.

이것의 단점 :

  • 완전히 테스트되지 않은 경우 코드에 오류가 발생하여 서비스의 문제가 발생할 수 있습니다.

  • 해커가 시스템에 스크립트를 작성할 수 있다면 거의 망할 수 있습니다.

  • 스크립트의 유효성을 검사하는 한 가지 방법은 스크립트 해시를 안전한 곳에 보관하여 실행하기 전에 확인할 수 있습니다.


좋은. 질문을 할 때 서버 쪽 JS에 대해서는 생각조차하지 않았습니다.
Richard Turner

1

나는 eval이 정당화되는 경우는 거의 없다고 생각한다. 실제로 정당화 될 때 사용하는 것보다 정당하다고 생각하여 사용할 가능성이 높습니다 .

보안 문제가 가장 잘 알려져 있습니다. 그러나 JavaScript는 JIT 컴파일을 사용하며 eval과는 잘 작동하지 않습니다. Eval은 컴파일러의 블랙 박스와 다소 비슷하며 JavaScript는 성능 최적화 및 범위 지정을 안전하고 올바르게 적용하기 위해 코드를 어느 정도 미리 예측할 수 있어야합니다. 경우에 따라 성능 영향은 평가 외부의 다른 코드에도 영향을 줄 수 있습니다.

자세한 내용을 보려면 https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval


0

eval함수에 전달 된 코드를 완전히 제어 할 수 있으면이를 사용하는 것이 좋습니다 .


2
전달하는 내용을 완전히 제어 할 수 있다면 eval큰 질문이됩니다. 실제 JS가 아닌 문자열이되는 것이 언제 합리적입니까?
cHao

@cHao 예를 들어, 큰 Game-Application (5-10MB Javascript)을 사용하는 경우 먼저 빠른 기본 로딩 AJAX-Preloader (1kb)를 빌드하는 것이 좋습니다. 바 또는 비슷한 것. 다운로드 후 "eval (source)"또는 더 나은 "new Function (source)"을 사용하여로드 된 Game-Application-Script를 실행할 수 있습니다. 이렇게하면 게임을 시작할 수있을 때까지 응용 프로그램을 다운로드 할 시간이 필요하다는 것을 시각적으로 볼 수 있습니다. 그렇지 않으면 사용자는 시각적 피드백없이 전체 애플리케이션이로드 될 때까지 기다려야합니다.
SammieFox

@SammieFox이 작업을 수행하는 다른 (더 나은) 방법이 <script async="true" src="...">있습니다. 참조 : w3bits.com/async-javascript
루드 Helderman에게

대답은 위험한 조언입니다. 너무 많은 개발자들이 통제에 대한 잘못된 감각을 가지고 있습니다. 조언는 않습니다 더 이상 적극적으로 유지되지 않은 소프트웨어에 대한 약간의 이해가. 그러나 그러한 소프트웨어는 죽은 것으로 간주해야합니다.
Ruud Helderman

0

가능하면 테스트 중에 만 가능합니다. 또한 eval ()은 다른 특수 JSON 등 평가 기보다 훨씬 느립니다.


0

코드 소스가 사용자 또는 실제 사용자로부터 온 것임을 확신 할 수있는 한 eval ()을 사용하지 않는 이유는 없습니다. eval () 함수로 전송 된 내용을 조작 할 수 있지만 웹 사이트의 소스 코드를 조작 할 수 있고 JavaScript 코드 자체를 변경할 수 있기 때문에 보안 문제는 아닙니다.

그렇다면 ... eval ()을 사용하지 않을 때? Eval ()은 타사가 변경할 수있는 경우에만 사용해서는 안됩니다. 클라이언트와 서버 간의 연결을 가로채는 것처럼 (문제가있는 경우 HTTPS 사용) 포럼에서와 같이 다른 사람들이 작성한 코드를 구문 분석하기 위해 eval ()을 사용해서는 안됩니다.


Re "코드의 소스가 본인이나 실제 사용자로부터 온 것임을 확신 할 수있는 한 eval ()을 사용하지 않는 이유는 없습니다." 이것은 단일 사용자가 있다고 가정합니다. 그 전제는 OP에 명시되어 있지 않습니다. 여러 명의 사용자가있는 경우 eval한 사용자의 컨텐츠로 구성된 문자열에주의하여 해당 사용자가 다른 사용자의 브라우저에서 코드를 실행할 수 있습니다.
Mike Samuel

@ MikeSamuel, eval은 다른 사용자의 브라우저에서 코드를 실행할 수 있습니다. 브라우징 기록에서는 이런 일이 발생하지 않았습니다. 예를 보여 주시겠습니까?
Akash Kava

@AkashKava, 문자열은 하나의 사용자 에이전트에서 시작하여 데이터베이스에 저장된 다음 다른 브라우저에 제공 될 eval수 있습니다. 항상 일어난다.
Mike Samuel

@MikeSamuel 데이터베이스? 어디? 누가 잘못된 문자열을 제공합니까? 서버 쪽의 데이터베이스를 비난하지 않습니까? 우선 서버 측 코드를 잘못 작성했다고 EVAL을 비난하지 마십시오. jsfiddle을 사용하여 세계에 해를 끼칠 수있는 실제 사례를 보여주십시오.
Akash Kava

2
@AkashKava, 나는 당신의 질문을 이해하지 못합니다. 우리는 특정 응용 프로그램에 대해 이야기하고 있지 않지만 사용하지 않는 이유를 설명합니다 eval. 서버를 비난하는 것이 어떻게 유용합니까? 누군가를 비난해야 할 경우 공격자가되어야합니다. 책임에 관계없이 서버의 버그에도 불구하고 XSS에 취약하지 않은 클라이언트는 취약한 클라이언트보다 낫습니다.
Mike Samuel

0

실제로 필요한 경우 평가는 악이 아닙니다. 그러나 내가 우연히 발견 한 eval 사용의 99.9 %는 필요 하지 않습니다 (setTimeout을 포함하지 않음).

나에게 악은 성능이나 보안 문제가 아닙니다 (간접적으로 둘 다입니다). eval을 불필요하게 사용하면 유지 보수가 더 어려워집니다. 리팩토링 도구가 폐기되었습니다. 코드 검색이 어렵습니다. 이러한 회피의 예기치 않은 영향은 군단입니다.


5
setTimeout에는 eval이 필요하지 않습니다. 함수 참조도 사용할 수 있습니다.
Matthew Crumley

0

JavaScript의 eval ()은 언제 사악하지 않습니까?

나는 항상 eval 사용권장하지 않습니다 . 거의 항상 더 깨끗하고 유지 보수가 쉬운 솔루션을 사용할 수 있습니다. JSON 구문 분석에도 Eval 이 필요하지 않습니다 . Eval 은 유지 보수 지옥에 추가합니다 . 이유없이, 더글러스 크로포드 (Duglas Crockford)와 같은 주인이 눈살을 찌푸립니다.

그러나 사용해야하는 한 가지 예를 찾았습니다 .

식을 전달해야 할 때.

예를 들어, 나는 google.maps.ImageMapType나를 위해 일반적인 객체를 구성하는 함수를 가지고 있지만, 레시피를 알려 주어야합니다. zoom그리고 and coord매개 변수 에서 타일 URL을 어떻게 구성해야합니까 ?

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

3
이것은 eval ()이 필요하지 않도록 리팩토링 될 수있는 것처럼 보입니다-tileURLexpr은 단순한 템플릿이므로 replace ()를 신중하게 사용하면 작업을 수행합니다. 여전히 질문을 제출했을 때 염두에 두었던 예를 상기시켜줍니다. 이는 스프레드 시트 기능과 유사하게 사용자가 수학 공식을 평가할 수 있도록하는 것과 관련이 있습니다. 물론 대답에 영향을주고 싶지 않기 때문에 당시에는 언급하지 않았습니다!
Richard Turner

8
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Casey Chu

0

내 사용 예 eval: import .

일반적으로 수행되는 방법

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

그러나 eval작은 도우미 기능을 사용하면 훨씬 더 잘 보입니다.

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable 이 버전은 콘크리트 멤버 가져 오기를 지원하지 않습니다.

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

2
아이디어에 +1하지만 버그가 있습니다 : .replace(/name/g, name).replace('path', path). name문자열 이 포함되어 있으면 "path"놀라실 수 있습니다.
wberry

1
각 속성에 대해 하나의 변수를 선언 components하면 코드 냄새가 발생할 수 있습니다. 코드를 리팩토링하면 '문제'가 완전히 사라질 수 있습니다. 현재 솔루션은 단지 구문 설탕입니다. 당신이 그렇게 주장한다면, 배포 전에 실행되도록 자신의 전처리기를 작성하는 것이 좋습니다. eval프로덕션 코드와 거리를 두어야 합니다.
Ruud Helderman

0

평가는 악한 것이 아니라 잘못 사용 된 것입니다.

코드를 작성했거나 신뢰할 수 있다면 괜찮습니다. 사람들은 평가가 어떻게 사용자 입력이 중요하지 않은지 계속 이야기합니다. 잘 ~

서버로 이동하는 사용자 입력이 있으면 클라이언트로 돌아와 해당 코드는 위생 처리되지 않고 평가판에서 사용됩니다. 축하합니다. 사용자 데이터를 누구에게나 보낼 수있는 판도라 상자를 열었습니다.

eval의 위치에 따라 많은 웹 사이트에서 SPA를 사용하므로 eval을 사용하면 쉽지 않은 응용 프로그램 내부에보다 쉽게 ​​액세스 할 수 있습니다. 이제 그들은 해당 브라우저에 가짜 브라우저 확장을 만들어 데이터를 훔칠 수 있습니다.

eval을 사용하는 요점을 파악해야합니다. 코드를 생성하는 것은 단순히 그런 종류의 작업을 수행하거나 객체를 사용하는 등의 방법을 만들 수있는 경우에는 이상적이지 않습니다.

이제 eval을 사용하는 좋은 예입니다. 서버가 작성한 swagger 파일을 읽고 있습니다. 많은 URL 매개 변수가 형식으로 만들어 {myParam}집니다. 따라서 엔드 포인트가 많으므로 URL을 읽고 복잡한 대체 작업없이 템플릿 문자열로 변환하려고합니다. 그래서 당신은 이런 식으로 할 수 있습니다. 이것은 매우 간단한 예입니다.

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

-1

코드 생성. 필자는 최근 virtual-domhandlebars 의 격차를 해소하는 Hyperbars 라는 라이브러리를 작성했습니다 . 핸들 바 템플릿을 파싱하고 하이퍼 스크립트 로 변환하여이를 수행 합니다. 하이퍼 스크립트는 먼저 문자열로 생성되며 반환하기 전에 실행 코드로 변환합니다. 나는 찾았다eval()eval() 이 특정한 상황에서 악의 정반대를 했다.

기본적으로

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

이에

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

의 성능 eval()생성 된 문자열을 한 번만 해석 한 다음 실행 가능한 출력을 여러 번 재사용해야하기 때문에 이와 같은 상황에서도 문제가되지 않습니다.

당신은 당신이 궁금하면 코드 생성이 달성 방식을 볼 수 있습니다 여기에 .


"하이퍼 스크립트는 먼저 문자열로 생성됩니다 (...)"빌드 단계에서 모든 코드 생성을 수행하고 결과 하이퍼 스크립트 코드를 별도의 실행 파일 (.js) 파일에 쓴 다음 해당 파일을 배포하여 테스트 및 생산. 코드 생성 방식을 좋아합니다. eval컴파일 타임에 속하는 일부 책임이 런타임으로 이동했다는 힌트 일뿐입니다 .
Ruud Helderman

-1

내 생각은 eval은 클라이언트 측 웹 응용 프로그램에 매우 강력한 기능이며 안전합니다 ... JavaScript만큼 안전하지는 않습니다. :-) Firebug와 같은 도구를 사용하면 모든 JavaScript 응용 프로그램을 공격 할 수 있으므로 보안 문제는 본질적으로 서버 측 문제입니다.


1
evalXSS 공격에 대비하여 사용을 보호해야합니다. 항상 올바른 것은 아닙니다.
Benjamin

-1

Eval은 매크로가 없을 때 코드 생성에 유용합니다.

(멍청한) 예제의 경우, Brainfuck 컴파일러를 작성하는 경우 명령 시퀀스를 문자열로 수행하는 함수를 구성하고이를 평가하여 함수를 반환하려고 할 수 있습니다.


컴파일러를 작성하거나 (생성되는 코드를 실행하는 대신 저장) 인터프리터 (각 명령에 사전 컴파일 된 구현이 있음)를 작성하십시오. 의 사용 사례도 아닙니다 eval.
Ruud Helderman

자바 스크립트 코드를 생성하고 즉시 실행하려는 경우 (직접 해석에 비해 성능상의 이점을 말하십시오) eval의 유스 케이스입니다.
Erik Haliewicz

좋은 지적; 이 기사 에서 Blockly에 대한 예를 보았습니다 . eval대안 ( Function )이 더 빠르고 ( MDN에 설명 된 것처럼 ) 더 안정적 일 때 (생성 된 코드와 동일한 웹 페이지의 다른 '지원'코드 사이의 격리가 향상되어 예측할 수없는 버그가 발생하지 않도록) Google은 권장 합니다.
Ruud Helderman

-5

구문 분석 함수 (예 : jQuery.parseJSON)로 JSON 구조를 구문 분석하면 JSON 파일의 완벽한 구조가 필요합니다 (각 특성 이름은 큰 따옴표로 묶임). 그러나 JavaScript는 더 유연합니다. 따라서 eval ()을 사용하여 피할 수 있습니다.


4
맹목적으로 사용하지 마십시오 eval. 타사 소스에서 JSON 데이터를 가져올 때 JSON을 참조하십시오 . 속성에 따옴표없이 Stringify? "따옴표없는 키 이름이없는 JSON"을 구문 분석하는 올바른 접근 방법.
Rob W

2
속성 이름에 큰 따옴표를 사용하지 않으면 객체 리터럴의 문자열 표현 일 수 있지만 JSON 은 아닙니다 . JSON은 같은 속성 이름을 정의 string하고 정의 string백 슬래시 이스케이프를 사용하여, 큰 따옴표로 감싸 0 개 이상의 유니 코드 문자의 순서.
쓸모없는 코드

Nikolas Zakas의 기사를보십시오- "eval ()은 악이 아니라 오해 만합니다
vitmalina

@vitmalina Zakas의 기사에서 : "이것은 사용자 입력을 취하여 eval ()을 통해 실행하는 경우 위험 할 수 있습니다. 그러나 입력이 사용자가 아닌 경우 실제 위험이 있습니까?" 정확히 문제입니다. 코드가 'hello world'비율을 넘어 서면 사용자 입력이로 유출되지 않는다는 것을 증명하는 것은 불가능합니다 eval. 수십 명의 개발자가 동일한 코드 기반으로 작업하는 심각한 다중 테넌트 웹 응용 프로그램에서는 허용되지 않습니다.
Ruud Helderman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.