实时搜索:如何用Javascript客户端保证安全

301 查看

实时性是我们的根本,所以当我们创建Algolia的时候,首先考虑的是创建一个可以在毫秒内返回相关查询结果的搜索后端。但是,后端部分只是影响实时性公式的一部分因素。事实上,用户所能察觉到的反应时间是从他们敲击键盘到显示结果的时间。所以非常快速的搜索后端只是把解决该公式的问题就落在了处理忘了延迟上了。我们通过下面两步来解决这个问题:

首先:我们在三个不同的地方都有数据中心,这些数据中心可以使我们在100ms内回答来自北美、欧洲和亚洲的查询。

其次:为了减少这种用户感知时延,用户的查询应该直接通过用户的浏览器或者移动手机发送到我们的服务器,同时,避免中间媒介比如你自己的服务器。这就是我们为网站提供javascript客户端,为手机应用提供Objc/Android/C#客户端的原因。

JavaScript的安全挑战

使用这个客户端意味着你需要在你的javascript(或者手机APP)中包括API KEY。使用这种方式的安全问题是任何人可以简单地通过查看页面的源代码来查看用户的API密钥,潜在地允许这个用户修改网站/移动应用程序。为了解决这个问题,我开始提供只允许查询的API KEY来保护你的索引免受未授权的修改。

限制抓取你数据的能力:你可能不想人通过重复的查询获取你所有的数据。简单的解决方法是限制在指定时间内用户可以调用API的次数。我们通过限制每个IP的比率实现了。然而,这种方法是不能接受的如果很多的用户都是受全局防火墙的保护。这种情况在企业用户中是很有可能发生的。

安全的访问控制:你可能需要限制用户对特定内容的查询。例如,你可能有些重要用户应该比其他用户可以访问更多的内容。做这件事的简单办法就是使用过滤。问题是在javaScript中设置简单的过滤,人们可以弄明白如何修改这些过滤条件,访问他们不应该访问的内容。

我们是如何解决这些问题:

现在,大多数的网站和应用都需要用户创建用户并且登录以获得个人的信息(考虑下CRM应用、Facebook和NetFix)。我们决定使用这些用户的ID来创建签名的API密钥来解决这个问题。比如说你只有查询权限的API密钥,
想要在两组人内容上对某一个指定的用户(id=42)使用过滤。

你可以在后端生成一个安全的由三个元素组成的哈希定义的API密钥:

比如,如果你是使用Rails,那么后端的代码应该是:

你可以使用安全的API密钥和相关信息初始化你的JavaScript代码。

使用用户标识(通过设置用户访问券定义)而不是使用IP地址来进行比率限制,并且这个安全过滤(通过设置安全标签定义)被自动的应用到查询。

实际上,如果用户想要超越他的权限,她需要修改她的安全标签并且弄明白新的哈希。

我们的后端通过你所有可能的查询索引的API密钥和查询中定义的安全标和用户标识(如果设置)来检验查询是否合法。

如果查询的哈希值和我们计算的不匹配,我们会返回无权访问(403)。不用担心,通过暴力破解来反解API密钥需要几年和数万内核。

你可能希望使用安全过滤但是不关心查询比率的限制,所以如果你需要这些特性,你只可以只用一个。

几周前我们推出这个新的特性,并且目前受到很好的反馈。我们的客户不需要再安全和查询速度中作出选择。

如果你看到任何可以改善这个方法的方法,我们将很乐意听到你们的反馈。