【问题标题】:How to convert anything to a String safely in JavaScript如何在 JavaScript 中安全地将任何内容转换为字符串
【发布时间】:2010-11-30 04:28:10
【问题描述】:

如果我有:

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

如何将test 转换为字符串?不调用 test.toString() 并且不使用 typeof x == "string" 检查,因为我想允许非字符串。

注意:这是用于处理来自内容页面的 js 范围的对象的 FF 扩展。

【问题讨论】:

  • 如果不致电toString(),您希望返回什么?
  • 嗯,总是有 JSON 序列化器...
  • 我已经修正了示例语法。
  • 任何东西都可以转换成字符串吗?您希望 JSON 类如何表示为“安全字符串”?

标签: javascript security firefox-addon gecko


【解决方案1】:

JavaScript 允许您修改脚本可访问的几乎任何对象的属性,包括 Object.prototype 本身,这意味着 任何 对象都容易受到“恶意代码”的攻击解释。

只有原语才能保证是安全的,所以确保“恶意代码”永远不会执行的唯一方法是执行以下操作:

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

【讨论】:

  • 对于需要更多粒度的人(例如,仍希望将[1,2,3] 转换为'1,2,3' CSV),使用类似Lodash array/object detection 的东西可以放在对象案例中:return _.isArray(x) && !_.some(x, _.isObject) ? _.toString(x) : 'object';
【解决方案2】:

遗憾的是,@Matthew Flaschen(目前已接受)的答案不适用于 ES6 / ES2015 中的 Symbol 类:

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/

(我不知道为什么,因为Symbol 有一个非常好的toString() 方法:)

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

https://jsfiddle.net/v1rqfhru/

不过有一个解决方案:String() 函数似乎能够将任何值(至少在我尝试过的值中)转换为String。如果存在,它甚至会调用toString()

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/

所以,将任何你喜欢的东西传递给String(),你会得到一个不错的结果。

【讨论】:

  • "将任何你喜欢的东西传递给String(),你会得到一个很好的结果。"不完全的。 String([Symbol('AAAA')]) 给出“未捕获的类型错误:无法将符号值转换为字符串”。
【解决方案3】:

一个选项是:

Object.prototype.toString.call(test)

这给出了:

"[object Object]"

在测试的情况下。基本上,它只提供类型信息。但是,我想知道这里的确切情况是什么。邪恶对象是如何加载到页面中的?如果他们可以在页面上执行任意代码,那么您基本上就不走运了。除此之外,还可以重新定义Object.prototype.toString

【讨论】:

  • 即使这也不是万无一失的,因为它可以覆盖Object.prototype.toString
  • @casa,真的。只有当他们所能做的就是将一个自包含的对象传递到页面中时,这才真正有帮助。如果他们可以修改全局变量的属性,那么所有的赌注都没有了。
  • 这里有一个问题,恶意代码是在与我的代码不同的范围内创建的。这是一个处理内容页面范围的FF ext。所以来自那个范围的对象应该有不同的 Object.prototype,所以使用Object.prototype.toString 应该是安全的。
  • 我认为结合这个答案和卡萨布兰卡的开关应该可以解决问题。
  • Object.prototype.toString.call(123) 返回字符串 "[object Number]"。可能不是您想要使用的,因为数据 (123) 丢失了...
【解决方案4】:

您的(toString: function(){alert("evil code"); return "test";}) 甚至没有在这里被解析,它会引发语法错误。我认为您想使用{} 而不是()

通常您可以使用空字符串和加号运算符来执行强制转换:

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

但是在这里,没有真正的方法可以安全地转换对象。

您可以使用delete test.toString 摆脱被覆盖的方法,之后它将回退到返回'[object Object]' 的普通toString 方法。您还可以通过test.toString.toString()toString 方法本身转换为字符串。

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

这取决于你究竟想在这里做什么。

【讨论】:

  • 这仍然会隐式调用“邪恶”toString
  • @Matthew 确实是早上 5:30,他的示例代码也坏了,要更新它。
  • 恶意代码可能是附加到原型链的 toString 的一部分,因此delete test.toString() 并不总是有效。
【解决方案5】:

您只能检查 undefined 案例并将其转换为使用 String 构造函数 像这样。

let a = [1,2,3]

String(a)

例外情况:String(undefined) --> "undefined"

希望对你有帮助

【讨论】:

    【解决方案6】:

    你可以使用 lodash toString 方法。

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

    Link to documentation

    【讨论】:

      猜你喜欢
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2014-06-27
      相关资源
      最近更新 更多