一年前互联网货代公司Flexport为了提高其客户数据的安全性,与我们HackerOne平台建立了合作关系。HackerOne作为全球知名的bug赏金平台之一,允许所有安全爱好者或专业的渗透测试人员,来提交他们的漏洞报告并给予相应的奖励。从与Flexport合作至今,我们已经收到了近200份的漏洞报告,包括从nginx头移除服务器令牌到XSS漏洞。以下是我们在这200份报告中挑选出的最有意思的6个漏洞。
1.删除按钮中的XSS
在启动我们的这个bug赏金计划时,我们并没有想到会收到任何关于XSS的有效报告。毕竟,React有内置的安全防护策略。但事实并非如此,我们收到的第一个报告就让我们感到非常震惊,这是一个关于存储型XSS的漏洞。
形成原因
当时我们使用Bootbox来显示错误消息并创建确认对话框。而Bootbox独立于React管理其DOM元素,并未受到React的XSS保护。因此,当用户直接将输入放在确认对话框中就会形成一个存储型的XSS漏洞。
修复
短期修复:在将任何用户输入传递给Bootbox之前,先过滤所有可能的XSS标签(例如可以使用JSXSS模块)。
长期修复:将Bootbox转移到基于React的确认模式。
吸取的教训
React虽然可以在一定程度上为我们防护XSS,但并不意味着所有的代码都是安全的。我们不能轻易信任在React之外运行的库文件,最好是减少或者避免使用那些未知的库文件。
2. Markdown处理中的XSS
在修复Bootbox并对其它类似库进行检查后不久,我们又收到了另一份关于XSS漏洞的报告。这次的问题是出在我们的Markdown渲染中。
形成原因
我们在文本框中支持Markdown,并使用了。回想起来,这显然是一个不明智的做法。
修复
将所有传入dangerouslySetInnerHtml的文本内容,使用XSS过滤器进行过滤,并创建一个Lint规则来规范和强制执行该操作。
吸取的教训
在使用任何可能会带来潜在安全问题的元素代码时,一定要谨慎考虑。
3. Target=“_blank”
在我们从HackerOne收到的所有报告中,这是最令我们感到惊讶的一个问题。
形成原因
当你在新窗口中打开一个链接()时,带有 target=”_blank” 跳转的网页则拥有了浏览器window.opener对象赋予的对原网页的部分权限。然后,攻击者就可以利用该权限将原始页面设置为登录页面或其他任何内容。而对于这个问题,我们只能通过在标签中添加rel=”noopener noreferrer”来解决。
修复
我们通过为target=”_blank” 加上 rel=”noopener noreferrer” 属性,从而使新窗口无法更改原始内容。此外,我们向ESLint提交了一个Lint规则,以防止我们和其他人在将来犯同样的错误。
吸取的教训
在信任HTML标签的同时,也要保持时刻的警惕。
4. WordPress的烦恼
在修复上述漏洞后,我们并没有再收到更多关于前端的相关漏洞报告。但关于我们的漏洞报告却从未停止,我们运行在Wordpress的公司网站也相继收到了许多漏洞报告。
形成原因
对于同样使用WordPress程序的站点而言,最多的原因就是使用了一些过时的插件导致的。例如,JetPack是一款被广泛使用(300万次安装)和推荐的插件,虽然它承诺可以为WordPress站点提供更好的安全性,并增加流量吸引读者。但在过去的几年间,已经有许多的XSS及其它漏洞被曝出。
修复
及时的更新那些已安装的Wordpress插件,对于一些不经常使用的插件应当及时的清理。订阅https://wpvulndb.com/跟进Wordpress相关的最新漏洞报告。
5. 2FA爆破将目标转到我们的Ruby on Rails后端,我们收到了两份关于双因素身份验证的漏洞报告。首先,我们收到的一份报告显示攻击者可以通过暴力攻击的手段,获取对非授权帐户的访问权限。
形成原因
我们选择使用了Authy作为我们的2FA合作伙伴,但他们的rails gem并未对验证速率做任何限制。
修复
我们在程序中添加了相应的速率限制,一旦输入频率超过我们的限制,我们就会对账户进行锁定。
6. 2FA绕过
另外份报告显示攻击者可以绕过我们的2FA,使我们的第二个认证因素完全失效。攻击者只需忽略2FA页面,直接在浏览器地址栏输入需要导航的到页面地址即可成功绕过2FA。
形成原因
这是本文所提及的漏洞中,最难以被追踪的一个漏洞。Authy rails gem hook至Devise,并在登录后使用以下代码要求2FA:
def check_request_and_redirect_to_verify_token
...
id = warden.session(resource_name)[:id]
warden.logout
warden.reset_session!
session["#{resource_name}_id"] = id
...
redirect_to verify_authy_path_for(resource_name)
end
从理论上讲,这串代码在成功登录后会将用户重定向到第二个因素身份验证页面。然而事实并非如此,而是直接将用户重定向到了其导航的页面。
def authenticate?(*args)
result = !!authenticate(*args) # Try to log the user in
yield if result && block_given?
result
end
修复
将warden.logout行更改为sign_out即可。我们在本地修复了这个问题,并向Authy发起了一个pull request希望为更多的人修复这个问题。
吸取的教训
对于一个企业而言即使安全做的再好,也难免会出现一些疏忽。而解决这个问题的最好方法,就是与类似于HackerOne这类的漏洞众测平台建立合作,借助大家的力量来共同维护我们的企业安全。
|