任何前端应用都不可能被安全保护? - kuzzle


尝试使用低效技术保护前端应用程序可能很危险。
我从不同的来源(Callstack、Jscrambler、Tabris、Nativescript、Reactnativecode)看到了许多文章,详细介绍了使用混淆、自定义加密(XORing与重复使用密钥等......)等技术来保护前端应用程序的安全。
事实上,应用程序的源代码由客户端支配,它可以随意研究和修改,它会了解App内部机制或恢复设备上存储的所有数据。
因此:

  • 不要相信前端应用程序
  • 不要推出你自己的加密技术
  • 不要使用可预测的加密密钥
  • 不要重复使用相同的密钥
  • 混淆是不安全的
  • 确保你的后端安全

认证
发送认证信息是通过SSL连接安全进行的,因此在大多数情况下,通信的保密性得到了保证。

由于以下原因,没有必要为每个客户的认证添加一个简单的XOR和重复使用的密钥的基本密码加密层。

  • 为每个客户和每个请求重复使用密钥使加密变得脆弱,因为通过频率分析有可能猜出信息。
  • 由于密钥存储在设备中,你只需要下载应用程序就可以知道它。

添加一个加密层可能是一个好主意,以避免在中间人用假SSL证书攻击的情况下数据被泄露。

但是,为了实现强大的加密,至少有必要:

  • 使用与密码大小相当的密钥
  • 为每个用户和每个请求使用一个不同的密钥
  • 用Diffie Helman类型的非对称加密算法来协商这个密钥。

这或多或少与在你的应用程序中实现一个自定义版本的SSL相同,但请记住,统治你自己的加密技术永远不是一个好主意。
使用其他安全技术(如SSL Pining)来防止MITM攻击要容易得多。

存储敏感数据
当需要在前端应用程序中存储敏感数据时,最好使用开发环境的创建者所提供的机制。 

例如,在使用React Native的移动应用程序中,开发人员可以使用苹果的Keychain或Android的Keystore。这些机制使得从设备上提取敏感数据更加困难,但也不能认为它们是完全安全的(例如,苹果的钥匙链被利用)。

在任何情况下,都没有必要增加一个用可预测的密钥制作的额外加密层,因为攻击者可以逆向工程应用程序并重新生成密钥。
或者更简单,直接访问存储在内存中的密钥。

此外,在前端应用程序中添加一个自定义的加密层是适得其反的,会消耗不必要的CPU资源进行加密/解密,从而消耗电池。

混淆源代码
虽然我可以理解开发者可能想让源代码的逆向工程更加困难,但混淆决不能被视为一种安全做法。

它最多可以阻止一些攻击者,但有动机的人总是可以对代码进行反向工程。
特别是在使用开源混淆器的情况下,因为它是已知的,而去混淆器肯定已经存在。

此外,混淆将使代码很难被不同的Javascript运行系统解释和优化,并将导致应用程序的性能大幅下降。

保护你的后端
正如我们所看到的,一个前端应用程序是不安全的。因为不可能控制客户的设备,所以不可能确保它不被破坏。 
大部分的安全元素必须在后端落实到位。
确保后端安全并没有什么神奇的秘方,是一套良好的编程实践使你能达到最佳效果。

永远不要相信用户的输入
从HTTP请求的正文,到头文件或cookies,所有可以被用户操纵的信息都不能被信任。
对用户输入的天真利用会导致各种攻击的发生。

  • SQL注入和NoSQL注入
  • 远程代码执行
  • 特权升级

在应用程序中使用输入数据之前,总是有必要对其进行检查和消毒。

限制DoS
拒绝服务攻击试图使一个应用程序不可用。
例如,有可能发送非常大的JSON有效载荷,这可能阻碍甚至冻结你的应用程序。
缓解攻击:在最低层限制有效载荷的大小,最好是直接在网络层限制。

如果你的后端是用Node.js编写的,那么在创建新的Promises时也有必要提高警惕。
事实上,一个Promise会被自动发送到事件循环中,然后就不可能在它被解决或拒绝之前撤回它。
因此,攻击者有可能在一条路线上发送大量的请求,产生Promises,使事件循环达到饱和。

缓解攻击:实现一个只使用回调的并发请求限制系统。使用回调进行开发并不有趣,但回调只是方法的指针,在调用之前不使用资源。只在请求限制系统之后使用Promises。

防止暴力攻击
为了防止对用户认证的暴力攻击,有必要对连接尝试的次数进行限制。
这种限制可以采取在认证途径中加入X次尝试后的阻止形式。

安全地存储密码
在2019年,仍有一些公司以纯文本方式存储用户的密码。

必须不惜一切代价避免这种做法,以便在你的应用程序发生数据泄漏时保护你的用户。不仅是你自己的应用程序:大多数用户在许多账户中重复使用同一个密码。密码泄漏的影响可能是灾难性的,无论是对你的用户还是对你公司的形象。

 密码必须使用单向加密函数或哈希函数来存储。

哈希函数的选择应该基于一个强大的算法,例如bcrypt。如果可以的话,通过使用密钥拉伸使弱的密码变得更强,为了增加安全层,你也可以对密码加盐加胡椒。

还有更多
后台有很多可能的攻击,而且大部分都是鲜为人知或不为人知的。
例如,两个字符串的简单比较会导致定时攻击的漏洞,并允许攻击者猜测密码或令牌。
但是,使用一个众所周知的正则表达式库也容易受到ReDoS攻击。

 这就是为什么保障后端安全不是一项轻而易举的任务,必须委托安全专家对开发人员进行培训,但也要对代码进行审计,以确保有尽可能少的漏洞,因为完美的安全是不存在的。

结束语
在开发一个应用程序时,必须自始至终考虑到安全问题,反思必须涵盖从后端到前端的整个应用程序范围,包括通信渠道和托管。 
安全是昂贵的,因此常常被忽视。这就是为什么最好使用由具有必要技能和知识的工程师设计的框架和后端,以确保终端用户的充分安全。
我要感谢协助我写这篇文章的整个Kuzzle团队,特别是Sebastien Cottinet和Yannick Combes在安全和密码学方面的专业知识。


所有的客户都是潜在的恶意的。保护你的后端。
前端有一些安全问题,大多归结为:

  • (JS)使用JS作用域,使你的应用程序的功能与用户的脚本隔离。
  • 不要暴露你的用户信息。
  • 尽可能少地保留支付信息居民。这意味着在销毁前清除表单字段,并且永远不要记录原始PCI数据。
  • 不要暴露你自己的密码密钥。使用用户特定的令牌,并在后端解决它们。
  • 我不应该这样说,但在传递所有输入之前,要对它们进行消毒。