2010-11-30 847 views
8

Si tengo:Cómo convertir cualquier cosa en una cadena segura en JavaScript

var test = {toString: function(){alert("evil code"); return "test";}}; 

cómo puedo convertir test a una cadena? sin llamar test.toString() y sin necesidad de utilizar un cheque typeof x == "string" ya que quiero permitir a los no cuerdas.

Nota: esto es para una extensión FF se trata de objetos de una página de contenido alcance de JS.

+2

¿Qué esperas para volver sin llamar 'toString()'? – casablanca

+1

Bueno, siempre hay serializadores JSON ... – cdhowie

+1

He corregido la sintaxis de ejemplo. –

Respuesta

5

JavaScript le permite modificar las propiedades de casi cualquier objeto que se puede acceder a la secuencia de comandos, incluyendo Object.prototype en sí, es decir, cualquier objeto es vulnerable a "código maligno" de la manera que usted explicó.

Sólo primitivas están garantizados para estar seguro, por lo que la única manera de asegurar que el "código maligno" nunca se ejecuta es hacer algo como esto:

function safeToString(x) { 
    switch (typeof x) { 
    case 'object': 
     return 'object'; 
    case 'function': 
     return 'function'; 
    default: 
     return x + ''; 
    } 
} 
+0

Para personas que necesitan más granularidad (por ejemplo, aún desean traducir '[1,2,3]' a ''1,2,3'' CSV) usando algo como [Lodash array] (https://lodash.com/ docs/4.17.4 # isArray)/[detección de objetos] (https://lodash.com/docs/4.17.4#isObject) podría colocarse en el caso del objeto: 'return _.isArray (x) &&! _. some (x, _.isObject)? _.toString (x): 'object'; ' – jmmygoggle

5

Su (toString: function(){alert("evil code"); return "test";}) ni siquiera conseguir analiza aquí, que arroja un error de sintaxis. Creo que quería utilizar en lugar de {}().

Normalmente podría utilizar una cadena vacía y el operador además de realizar un reparto:

""+test; 
""+2; // "2" 
""+4.5 // "4.5" 
""+[1, 2, 3] // "1,2,3" 
""+{} // '[object Object]' 

Pero aquí, no hay forma real de convertir el objeto en forma segura.

Puede utilizar delete test.toString para deshacerse del método reemplazado, después de que caiga de nuevo al método normal toString que devuelve '[object Object]'. También puede convertir el método toString en una cadena a través del test.toString.toString().

"function() { alert("evil code"); return "test"; }" 

Depende de usted exactamente lo que quiere hacer aquí.

+1

Esto todavía llamará implícitamente el "mal" 'toString'. –

+0

@Matthew De hecho, son las 5:30 a.m. aquí y su código de ejemplo está roto también, va a actualizarlo. –

+0

Actualiza la respuesta. –

4

Una opción es:

Object.prototype.toString.call(test) 

Esto da:

"[object Object]" 

en el caso de prueba. Básicamente, solo da información tipo. Sin embargo, me pregunto cuál es el escenario exacto aquí. ¿Cómo se carga el objeto malvado en la página? Si pueden ejecutar código arbitrario en la página, básicamente no tienes suerte. Entre otras cosas, es posible redefinir Object.prototype.toString.

+1

Incluso esto no es infalible porque es posible anular 'Object.prototype.toString'. – casablanca

+0

@casa, cierto. Esto realmente solo ayuda si todo lo que pueden hacer es pasar un objeto autónomo a la página. Si pueden modificar propiedades de globales, todas las apuestas están desactivadas. –

+0

aquí está la trampa, el código malvado se crea en un ámbito diferente al de mi código. Es una extensión FF que trata con el alcance de una página de contenido. Por lo tanto, los objetos que provienen de ese ámbito deben tener un Object.prototype diferente, por lo que usar 'Object.prototype.toString' debe ser seguro. – erikvold

1

Lamentablemente, (actualmente aceptada) La respuesta de @Matthew Flaschen no funciona con la clase de Symbol ES6/ES2015:

console.log("" + Symbol("foo")); 
// results in an exception: 
// `Uncaught TypeError: Cannot convert a Symbol value to a string` 
// (at least in Chrome as of this writing). 

https://jsfiddle.net/L8adq9y4/

(no tengo ni idea de por qué, como Symbol tiene un perfecto toString() método :)

console.log(Symbol("foo").toString()); 

https://jsfiddle.net/v1rqfhru/

Hay una solución sin embargo: la función String() parece ser capaz de convertir cualquier valor (al menos de los que probé) en un String . Incluso se llamará toString() si existe:

console.log(String("A String")); 
console.log(String(undefined)); 
console.log(String(null)); 
console.log(String({value: "An arbitrary object"})); 
console.log(String({toString: function(){return "An object with a toString() method";}})); 
console.log(String(function(){return "An arbitrary function"})); 

https://jsfiddle.net/6uc83tsc/

Así, pase lo que quiera en String() y obtendrá un resultado bastante bueno.

+0

" Pase lo que quiera en 'String()' y obtendrá un resultado bastante bueno. " No exactamente. 'String ([Symbol ('AAAA')])' da "TypeError no capturado: no se puede convertir un valor de Symbol en una cadena". –

0

Puede usar el método lodash toString.

_.toString(null); 
// => '' 

_.toString(-0); 
// => '-0' 

_.toString([1, 2, 3]); 
// => '1,2,3' 

Link to documentation

Cuestiones relacionadas