为什么 Rails' `HashWithIndifferentAccess` 将键存储为字符串而不是符号?

Why does Rails' `HashWithIndifferentAccess` store keys as strings and not symbols?

我正在使用 enum 将数据库中的整数映射到 ruby 代码中的语义值,但是我注意到它使用的键是字符串。检查hash的类型时,发现是ActiveSupport::HashWithIndifferentAccess,不是标准的Hash,这倒是有道理,但又引出了一个问题,为什么Rails选择存储和在内部将值作为字符串而不是符号进行比较。

documentation 状态:

Internally symbols are mapped to strings when used as keys in the entire writing interface

哈希中通常使用符号,因为它们的比较速度快,但 Rails 选择使用字符串来代替。他们为什么选择这样做,性能差异有多大?

Why have they chosen to do this

ActiveSupport::HashWithIndifferentAccess主要用来处理来自外部的参数。符号存储在 ruby 堆中,通常,它们永远不会释放回系统。

在从外部获取密钥的东西中使用符号作为密钥会导致针对 OutOfMemory 攻击的漏洞([D]DoS,使用随机生成的参数名称发送查询。)这就是选择字符串的原因, AFAIU。如需 100% 的保证,请咨询 DHH。

how significant is the difference in performance?

使用Benchmark检查。此站点不应该是“请为我做基准测试”的站点。

过去有一些实现无法收集符号。 IOW,一个符号,一旦创建,将保留在内存中,直到 time 进程结束(对于像 Rails 应用程序这样的服务器进程,可能是几个月)。直到三周前,最流行的实现 YARV 恰好是其中之一。

因此,您可以通过生成大量符号来拒绝 Ruby 系统 运行 那些易受攻击的实现之一,并且由于 Rails 使用 HWIA 作为请求参数(完全在攻击者的控制),除其他外,这样做是微不足道的。

现在,每个单独的实现都支持收集符号(JRuby 和 Rubinius 多年前就支持它,YARV 从 2.4.0 开始支持它),该实现策略可能会改变……或不会:永远不会改变 运行系统.