在react.js中存储访问令牌的位置?

时间:2018-02-26 07:49:36

标签: reactjs access-token

我正在Reactjs中构建一个应用程序。在验证access_token之后,我必须进行fetch调用。在注册时,从后端服务器获取access_token。但是,在哪里存储这些access_token。是否有任何方法可以使这些access_token全局,以便所有组件都可以访问它。我使用过本地存储,缓存和会话存储,但这些不可取。 这个问题在过去的几天内得到了解决,任何解决方案。事先提前。

3 个答案:

答案 0 :(得分:13)

可用的选项和限制:

有两种存储令牌的选项:

  1. Web Storage API:提供2种机制:sessionStoragelocalStorage。存储在此处的数据将始终对您的Javascript代码可用,并且无法从后端访问。因此,您将必须手动将其添加到例如标头中的请求中。此存储空间仅对您应用的域可用,而对子域不可用。这两种机制之间的主要区别在于数据有效期:
  • sessionStorage:仅适用于会话的数据(直到浏览器或标签关闭)。
  • localStorage:存储没有到期日期的数据,并且仅通过JavaScript或清除浏览器缓存/本地存储的数据来清除
  1. Cookies:与后续请求一起自动发送到您的后端。您的Javascript代码的有效期和可见性可以控制。可以用于您应用的子域。

在设计身份验证机制时,您必须考虑两个方面:

  • 安全性:访问或身份令牌是敏感信息。始终要考虑的主要攻击类型为Cross Site Scripting(XSS)和Cross Site Request Forgery(CSRF)。
  • 功能要求:关闭浏览器后,用户应该保持登录状态吗?他的课程多长时间?等等

出于安全考虑,OWASP不建议将敏感数据存储在Web存储中。您可以检查其CheatSheetSeries页面。您也可以阅读this detailed article了解更多详细信息。

其原因主要与XSS漏洞有关。如果您的前端没有100%不受XSS攻击的保护,则恶意代码可以在您的网页中执行,并且可以访问令牌。 要完全防XSS是非常困难的,因为它可能是由您使用的一种Javascript库引起的。

如果将Cookie设置为HttpOnly,则Javascript可能无法访问它们。 现在,Cookie的问题在于它们可以使您的网站容易受到CSRF的攻击。 SameSite cookie可以缓解这种类型的攻击。但是,较旧版本的浏览器不支持该类型的Cookie,因此可以使用其他方法,例如使用状态变量。此Auth0文档article中对此进行了详细说明。

建议的解决方案:

为了安全地存储令牌,我建议您结合使用两个cookie,如下所述:

JWT令牌具有以下结构:header.payload.signature

通常,有效负载中会包含有用的信息,例如用户角色(可用于改编/隐藏UI的各个部分)。因此,确保该部分可用于Javascript代码很重要。

一旦完成身份验证流程并在后端创建了JWT令牌,其目的就是:

  1. header.payload部分存储在SameSite Secure Cookie中(因此只能通过https使用,但仍可用于JS代码)
  2. signature部分存储在SameSite Secure HttpOnly Cookie中
  3. 在您的后端中实现中间件,以从这两个cookie中重构JWT令牌,并将其放在标头中:Authorization: Bearer your_token

您可以设置Cookie的有效期,以满足您的应用程序要求。

Peter Locke在this article中提出并很好地描述了这个想法。

答案 1 :(得分:2)

Michael Washburn上有一篇非常不错的文章,关于如何通过Redux here on his webpage

来保持状态

在文章中,他具有Redux的合著者之一Dan Abramov创建的very descriptive video tutorial的链接,我跟着他一起将其添加到我的项目中。 这是我用来使其工作的代码:

store.js

import { createStore, combineReducers } from "redux";
import { UserReducer, CopyReducer } from "../reducers";
import { loadState, saveState } from "../utils/localStorage";

export const giveMeStore = () => {
  const reducers = combineReducers({
    copy: CopyReducer,
    user: UserReducer
  });
  const persistedState = loadState();
  const store = createStore(reducers, persistedState);
  //user contains the TOKEN
  store.subscribe(() => {
    saveState({
      user: store.getState().user
    });
  });
  return store;
};

localStorage.js

export const loadState = () => {
  try {
    const serializedState = localStorage.getItem("state");
    if (serializedState === null) {
      return undefined;
    }
    return JSON.parse(serializedState);
  } catch (err) {
    return undefined;
  }
};
export const saveState = state => {
  try {
    const serializedState = JSON.stringify(state);
    localStorage.setItem("state", serializedState);
  } catch (err) {
    //ignoring write erros
  }
};

并将商店添加到提供者:

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";

import { giveMeStore } from "./store.js";

const Root = () => {
  return (
    <Provider store={giveMeStore()}>
      //... your components
      //...
    </Provider>
  );
};

ReactDOM.render(<Root />, document.querySelector("#root"));

答案 2 :(得分:1)

虽然晚了聚会,但我还是想分享我对这个话题的看法。 Anouar给出了一个很好的答案,其中包括被认为可保存为XSS的仅使用HTTP的cookie,指出了CSRF漏洞,并链接了Peter Locke的文章。

但是,就我而言,我需要应用程序100%无状态,这意味着我不能使用Cookie。

从安全角度考虑,将访问令牌存储在持久位置(如localStorage,window ..)是一种不好的做法。因此,您可以使用redux(或内置在状态/上下文中的react.js)将JWT存储在变量中。这将使令牌免受上述攻击,但在刷新页面后将其设为null。

我要解决的问题是使用刷新令牌,该令牌存储在localStorage中(您可以使用会话存储或类似的存储器)。刷新令牌的唯一目的是获取新的访问令牌,后端确保刷新令牌没有被盗(例如,实现针对其进行检查的计数器)。 我将访问令牌保存在缓存中(我的应用程序中的一个变量),并且由于重新加载而过期或丢失后,我使用刷新令牌来获取新的访问令牌。

显然,这仅在您还构建了后端的情况下才有效(或者至少在后端实现刷新令牌的情况下)。如果您处理的是未实现刷新令牌等的现有API,并且您不可以将访问令牌保存在变量中(由于重新加载时为null),那么您还可以在使用应用程序密钥之前对令牌进行加密将其保存到localStorage(或会话存储,或者...是的,您知道了)。请注意,解密令牌需要花费一些时间,并且可能会使您的应用变慢。因此,您可以将加密的令牌保存到localStorage(或...),并在刷新后仅对其解密一次,然后将其保留在state / redux变量中,直到再次刷新/再次从localStorage对其进行解密等。

关于该主题的最后一句话:Auth是应用程序的关键基础架构,尽管有趣的游戏和在线银行之间存在明显的区别(您可能希望对该银行“偏执”,而仅“关注” (关于游戏),诸如“ localStorage很好”或“在最坏的情况下会发生什么?在1小时后过期”之类的答案是危险的,根本就是错误的。机器可能会在几秒钟内造成很多损坏,而您又不想留下任何空白。如果您懒得不能保护应用程序安全,则可能要使用现有的解决方案,而不是自己构建解决方案。

也就是说,JWT /令牌身份验证对于游戏来说是相当新的东西(几年了,但还不如开发中的其他主题成熟)。找到可行的解决方案需要花费一些时间和精力,但是让我们继续构建安全的软件,而不是通过快速的黑客手段充斥整个网络。

最好,最快乐的编码。