【发布时间】:2021-05-24 17:46:55
【问题描述】:
我会尽量保持它与框架无关,但我会参考我个人使用的框架来提供一些上下文。另外,很抱歉,这是一个很长的问题。
上下文:我正在开发一个在线平台。它由两个不同的服务器组成,一个为公共 REST(ish) API 提供服务的“后端”(比如说 api.example.com),一个使用 Sapper (Svelte) 和 ssr (example.com) 的“前端” .后者基本上服务于一个 API 客户端。
显然,某些端点与特定帐户相关,因此需要身份验证。据我所知,有两种不同的方法,它们具有不同的漏洞:
- 会话身份验证 (cookie),易受 CSRF 攻击
- token认证(header),易受XSS攻击(一般token保存在
localStorage)
直接在后端服务器上使用会话身份验证非常困难,因为该页面由另一台服务器提供服务,并且生成/验证令牌不是那么容易,如果不是不可能的话。
常见解决方案:
人们似乎对使用localStorage 感到非常焦虑,我明白了,因为攻击者可以使用 XSS 窃取令牌并冒充用户。因此the preferred solution seems to be如下:
- 将令牌存储在 httpOnly cookie 中
- 每个请求都转到 example.com/api/[...]
- 这些端点充当“代理”,从 cookie 中获取令牌并将其放入 Authorization 标头中,以将请求转发到 api.example.com 上的实际 API
问题是,由于现在使用 cookie 进行身份验证(至少在“前端”级别),CSRF 攻击又是一个问题。当然,现在处理起来更容易了,因为这都是前端服务器的责任,并且已经有existing CSRF middlewares表示express和polka。
但是,我的观点是,CSRF 令牌和 CSRF 保护通常在存在 XSS 漏洞的情况下是无用的,因此,即使 JS 无法直接访问令牌,该平台仍然存在漏洞。 XSS 保护仍然很重要,我们这样做没有任何收获。另一方面,现在前端服务器对每个后端请求都“忙碌”,这破坏了拥有不同服务器的优势之一。
我想做的基本上是坚持localStorage的方法,但没有实际使用localStorage,以利用ssr。这个想法是我可以使用 Sapper 中间件来读取 cookie 并将令牌存储在 Sapper 会话中:
sapper.middleware({
session: (req, res) => ({
authorization: getCookie(req, 'supersecret') // get supersecret cookie from request
})
})
对于那些不了解 Sapper 的人来说,session 在这种情况下基本上是一块由服务器初始化并与客户端共享的内存。制作 cookie httpOnly 并没有真正发挥作用,因为 JS 仍然可以使用会话存储访问该值。但是由于服务器现在可以在页面重新加载期间访问令牌,我们现在可以利用 ssr(在服务器上呈现从 API 获得的私有信息有多大用处是值得商榷的,但为什么不呢?)。
问题是:这显然不是标准方法,因此我不明白它可能导致(或已经存在)的问题,因为我似乎找不到任何缺点对此。我在想什么/做错了什么?这真的可以吗?
PS:如果我想使用 API 密钥并限制 API 使用,“前端代理”是强制性的,但我认为我真的不需要它(如果我错了,请纠正我)
【问题讨论】:
-
有什么好处?也许只有我一个人,但不清楚你为什么要这样做。我最初的想法是安全方面的,从客户端的角度来看,这与将其存储在类似 localstorage 的东西中是相同的,但是具有额外的依赖项和更大的攻击面,更多潜在的配置错误和更复杂的一般性,这对安全性不利。
-
@GaborLengyel 使用 cookie 允许我将授权令牌传递给服务器以从 API 检索信息并使用服务器端呈现
-
这种方法比将令牌存储在 localStorage 中并将其作为标头添加到每个请求中如何更好?
-
仅供参考,看看 Auth0 如何在浏览器中存储令牌 github.com/auth0/auth0-spa-js/blob/master/src/Auth0Client.ts
-
@pianka 如果在这里失败,请尝试在security.stackexchange.com 上询问。
标签: api security authentication xss csrf