Eval é mau ... Então, o que eu deveria usar em vez disso?
-
22-07-2019 - |
Pergunta
uma solicitação do Ajax me retorna uma matriz JSON padrão preenchido com entradas do meu usuário. A entrada foi higienizado, e usando a função eval (), eu posso facilmente criar meu objeto javascript e atualizar minha página ...
Então aqui está o problema. Não importa o quanto eu tente para higienizar as entradas, eu prefiro não usar a função eval (). Eu verifiquei no google por maneiras de usar "JSON em AJAX sem eval" e corri accross um monte de diferentes métodos ...
Qual deles devo usar? Existe um padrão, comprovada segura maneira de fazer isso?
Solução
json.org tem um bom biblioteca javascript
uso simples:
JSON.parse('[{"some":"json"}]');
JSON.stringify([{some:'json'}]);
Editar : Como foi salientado nos comentários, isso usa eval se você olhar através de sua fonte (embora pareça ser higienizado primeiro)
para evitá-lo completamente, olhada json_parse ou JSON-sans-eval
json2.js é inseguro, json_parse.js é lento, JSON-sans-eval.js é não-validação
Outras dicas
Existe um padrão, comprovada segura maneira de fazer isso?
Há uma maneira padrão proposto de fazer isso, na próxima versão ECMAScript 3.1 do JavaScript: JSON.parse .
Será apoiado no IE8, Firefox 3.1 / 3.5 e, provavelmente, os outros browsers populares no futuro. Enquanto isso, você pode cair de volta para, ou utilizar exclusivamente, eval (). Mal ele pode ou não ser; certamente será mais lento do que JSON.parse. Mas essa é a maneira usual para analisar JSON hoje.
Se um atacante é capaz de injetar malcious JavaScript no conteúdo que você está cuspindo via JSON, você tem problemas maiores para se preocupar do que eval-é-o mal.
Eu diria que, uma vez que a entrada é higienizado, eval é o melhor caminho a percorrer. Se o servidor for comprometida, as pessoas serão capazes de enviar o que roteiros que eles querem para o cliente de qualquer maneira. Então, colocar um eval não é um grande risco à segurança. Se você está preocupado com as pessoas que manipulam os pacotes antes de chegar ao cliente, em seguida, mais uma vez, os scripts si pode ser modificado.
Não se preocupe com eval. Mas certifique-se de envolvê-lo em um bloco try ... catch para que seus usuários não obter erros JS se o seu JSON fica mutilado.
:)
Para converter com segurança JSON para um JS objeto que você deve usar um analisador JSON como a função JSON.parse () fornecida pelo esta biblioteca .
Compare com o padrão de design de comando: http://en.wikipedia.org/wiki/Command_pattern . Diante disso, você pode definir com precisão as operações de um cliente pode executar e sua aplicação vai ser tão seguro quanto a interpretação subjacente.
Depende do que você está tentando realizar com o saneamento. Eu tive grande sucesso w / a protótipo apoio da estrutura para JSON e avaliação de segurança.
Se você está certo, não há risco de injeção, e você não está eval()ing
em um loop, em seguida, usar eval()
. Ele vai se comparam favoravelmente com outras opções que certamente será mais lento, pode quebrar, e vai exigir o cliente para baixar o código adicional.
"roubada" do jQuery
// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
window.JSON.parse( data ) :
(new Function("return " + data))();
Issue: As poses problema eval é que ele executa no escopo global
eval.call(document, "console.log(this)")
eval.call(navigator, "console.log(this)")
eval.call(window, "console.log(this)")
(function(){eval.call(document, "console.log(this)")})()
>Window
Cenário:
Suponha que você está usando atributos individuais no código de marcação de vários documentos-elementos tais como um atributo onvisible
<img src="" onvisible="src='http://www.example.com/myimg.png';">
Você gostaria de obter todos os elementos com este atributo, gire o onvisible-content-string em um fechamento e colocá-lo em uma fila EventHandler. Este é o lugar onde o construtor Função JS entra em jogo.
Function === 0..constructor.constructor
>true
Function('return [this, arguments]').call(window, 1,2,3)
>Window, Arguments[3]]
Function('return [this, arguments]').call(document, 1,2,3)
>Document, Arguments[3]]
Function('return [this, arguments]').call(navigator, 1,2,3)
>Navigator, Arguments[3]]
Juntando tudo:
var eventQueue = [];
var els = document.querySelectorAll('[onvisible]');
for (var el in els) {
var jscode = els[el].getAttribute('onvisible');
eventQueue.push( {el:els[el], cb:Function(jscode)} )
}
//eventQueue[0].cb.call(scope, args);