JSON安全最佳实践?

79

在研究JSON与XML之争的问题时,我看到了这个问题。其中一个支持JSON的原因是其易于使用Javascript进行转换,特别是使用eval()函数。从安全角度来看,这立即引起了我的注意。

因此,我开始研究JSON的安全方面,并发现了这篇关于人们对JSON的安全性估计过高的博客文章。这部分内容引起了我的注意:

更新:如果您完全正确地处理JSON,则顶级应该只有对象。数组、字符串、数字等都将被包装。JSON对象将无法执行eval(),因为JavaScript解释器会认为它正在查看一个块而不是一个对象。这很大程度上有助于防止这些攻击,但最好还是使用不可预测的URL来保护您的安全数据。

好的,这是一个不错的开始规则:JSON对象在顶层应该始终是对象,而不是数组、数字或字符串。听起来对我来说是个不错的规则。

在处理与JSON和AJAX相关的安全性时,还有其他需要注意或避免的事情吗?

上面引用中的最后一部分提到了不可预测的URL。有人有更多关于此的信息吗,特别是如何在PHP中实现?我比较熟悉Java而不是PHP,而在Java中很容易(您可以将整个URL映射到一个单独的servlet),而我做过的所有PHP都将一个单独的URL映射到PHP脚本。

此外,使用不可预测的URL确切地如何增强安全性?


我完全不明白这个!无论浏览器发出的请求是什么(无论是否可预测),都可以通过控制台或一些高级GM脚本向用户报告... - James
"JSON 不像人们想象的那样安全" 已经过时了。 - Stephan Dollberg
3个回答

56

JSON存在许多安全攻击,尤其是XSRF。

当Web服务使用Cookie进行身份验证,并响应GET请求时,返回包含敏感数据的JSON数组,就会出现漏洞。

如果攻击者可以欺骗已登录naive-webapp.com服务的用户访问他们的网站(或任何嵌入了他们控制的IFRAME的网站,例如通过嵌入广告),则可以插入一个SRC到naive-webapp.com的<script>标签,并潜在地窃取用户的数据。这取决于JavaScript中Array构造函数的一个小问题,如下所示:

 <script>
   // Overload the Array constructor so we can intercept data
   var stolenArrays = [];
   var RealArray = Array;
   Array = function () {
     var arr = RealArray.apply(arguments);
     stolenArrays.push(arr);
     return arr;
   }
 </script>
 <!-- even though the attacker can't access the cookies,
   - he can cause the browser to send them to naive-webapp.com -->
 <script src="//naive-webapp.com/..."></script>
 <script>
   // now stolenArrays contains any data from the parsed JSON
 </script>

EcmaScript 5修复了令人困惑的行为,导致[]在全局对象上查找Array,许多现代浏览器不再容易受到这种攻击。

顺便提一句,Oil错误地认为URL是不可预测的。在URL中使用加密安全的随机标识符是保护资源的好方法。像Oil建议的那样,基于身份的安全措施并非万能药。 请参阅http://waterken.sourceforge.net/,以了解基于在URL中使用加密安全标识符的安全分布式应用程序方案的示例,该方案不需要身份的概念。

编辑:

在考虑JSON与XML时,您也应该注意XML特定的攻击向量。

XXE,即XML外部实体攻击,使用精心制作的XML通过防火墙访问文件系统和网络资源。

<!DOCTYPE root 
[
<!ENTITY foo SYSTEM "file:///c:/winnt/win.ini">
]>
...
<in>&foo;</in>

The Application embeds the input (parameter "in", which contains the win.ini file) to the web service response.


我明白了,所以如果Web服务器在响应GET请求时发送的数据仅针对已登录用户,即使该数据是JSON,它也应该记住攻击者可以使用<script>标签获取和解析该数据。那么解决方案是什么呢?您的Web应用程序应小心,不要发送任何可以解析为Javascript的内容,即使是JSON,作为对GET请求的响应。它应该仅限于POST(可能需要与服务器设置的cookie匹配的令牌)。我认为这与其他威胁的解决方案类似,比如GIFAR? - thomasrutter
1
或者说,仅依赖于最外层是一个对象并且解析器因{}被解释为块而中断,这样安全吗? - thomasrutter
如果您知道最外层始终是一个对象,并且正确引用属性名称,则解析器应该会停止。 - Mike Samuel

19

博客中的主要安全漏洞(CSRF)并不是JSON特有的。即使使用XML,这个漏洞也同样严重。实际上,如果没有任何异步调用,常规链接同样容易受到攻击。

当人们谈论唯一的URL时,通常不是指http://yourbank.com/json-api/your-name/big-long-key-unique-to-you/statement。相反,更常见的做法是使请求中的其他内容唯一;例如,在FORM提交中添加一个值或URL参数。

通常,这涉及在服务器端插入一个随机令牌,然后在请求发出时进行检查。

数组/对象的事情对我来说是新闻:

脚本标签:攻击者可以嵌入指向远程服务器的脚本标签,浏览器将有效地对回复进行eval(),但它会丢弃响应,由于JSON全是响应,因此您是安全的。

在这种情况下,您的网站根本不需要使用JSON就会受到攻击。但是,如果攻击者可以向您的网站插入随机HTML,那么您的网站就会遭受攻击。


3
仍然最好使用不可预测的URL来保护您的安全数据。重点是保护您的安全数据需要适当的身份验证和可能的加密。JSON交换仍然可以使用现有的身份验证技术(例如通过cookie的会话)和SSL。仅仅依靠别人猜测URL(他们实际上正在谈论的内容)只有在您使用JSON将数据导出到匿名第三方(例如Web服务)时才是合理的技术(即使是这样,也只是勉强可以接受的)。一个例子是Google的各种Web服务API,其中匿名用户通过其他网站访问Google数据。他们使用域引荐和API密钥来确保中间人网站被允许提供Gooogle数据。如果您只是使用JSON向已知的用户代理发送私有数据,请使用一些真正的身份验证和加密。如果您试图提供Web服务,则取决于这些数据的“安全性”如何。如果它只是公共数据,并且您不介意谁可以阅读它,那么我认为制作散列URL没有意义。编辑:为了证明他们的意思,请考虑以下情况。想象一下,您的银行提供了一个JSON API来获取对账单。如果我只能输入http://yourbank.com/json-api/your-name/statement,您可能不会很高兴。他们可以为您的帐户生成一个唯一的字符串,该字符串在任何JSON请求中都是必需的,例如:http://yourbank.com/json-api/your-name/big-long-key-unique-to-you/statement。我猜测的机会会少得多。但是,您真的希望这是您的真正安全数据和潜在身份盗窃者之间唯一的缓冲吗?不。

2
我认为你需要阅读博客的其余部分:他并不支持除不可预测的URL之外的任何安全措施。他说的是仅通过Cookie来保障安全是不够的,并且他演示了原因。 - cletus
4
认证并不起作用——这就是问题的重点。例如,如果用户已经登录到target.com(也就是说,他们有一个会话cookie),attacker.com可能尝试像 <script type="text/javascript" src="http://target.com/secret-data-with-predictable-url.json"/> 这样的东西,并使用Mike描述的数组构造器技巧来获取数据,如果顶层元素是一个数组的话。 - Jo Liss
3
你混淆了身份验证和授权这两个问题,然后错误地假设密码不容易被猜测。哪个更容易被猜测:通常具有128位到1024位熵的随机生成标识符,还是平均具有18位熵的人工生成密码? URL的主要问题是用户没有习惯保密URL,需要一些工作来防止通过引用等方式泄露。Waterken试图解决这两个问题。 - Mike Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接