Xyp*_*riL 11 cookies node.js jwt reactjs redux
我目前正在开发一个 MERN 堆栈应用程序,我使用的身份验证是 JWT 并将其保存在我的 cookie 中。这就是我在用户登录后发送 cookie 的方式。
res
.cookie("token", token, {
httpOnly: true,
secure: true,
sameSite: "none",
})
.send();
Run Code Online (Sandbox Code Playgroud)
我通过在后端获取“令牌”cookie 来登录用户。然而,我用这个应用程序实现了 Redux,每次刷新页面时,它都会自动注销。我想要的是在我的前端(React)中检测浏览器中的“令牌”cookie,但我无法获取它。我尝试过使用 npm js-cookie 但仍然无法得到它。有没有办法获得“令牌”cookie?或者根据我读过的内容使用 redux-persist ?请帮忙,谢谢。
fab*_*ian 17
就像其他答案已经解释的那样,您无法通过 JS 访问 httpOnly cookie。
我个人建议您使用不同的方法。当然,cookie 和 httpOnly 听起来是个好主意,您可能会认为 cookie 比 localStorage 好一千倍,但最终,将令牌存储在 localStorage 还是 cookie 中并不重要。您可能会争论 cookie 与 localStorage 几个小时,但两者都有各自的漏洞(例如:cookie:CSRF-Attacks(https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html),localStorage:XSS)。
现在,虽然理论上您可以在这里使用 localStorage,但我并不提倡使用它。我建议您放弃 cookie 和 localStorage 并将 JWT 存储在您的应用程序状态中(无论是与 context-api、redux 等),然后发送带有身份验证标头的 JWT 以及您从前面发出的所有请求到后端。当然,您的后端需要验证该令牌。例如,您可以仅实现一个身份验证中间件,将其添加到所有需要身份验证的路由中。过期也非常简单,因为您不必再同步 JWT 和 cookie 的过期时间。只需在 JWT 上设置过期时间,身份验证中间件中该令牌的验证就会捕获该过期时间。如果您想知道为什么此方法可以安全地抵御 CSRF 攻击,请查看此处:Where to store JWT in browser? 如何防范CSRF?
这里有一些不错的文章,我真的建议您阅读第一篇文章: https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/ https://medium.com /@ryanchenkie_40935/react-authentication-how-to-store-jwt-in-a-cookie-346519310e81
虽然 JWT 一直是用户身份验证的流行选择,但有几个因素有利于使用传统的仅 HTTP cookie 会话。
主要考虑因素:
如果攻击者获得 JWT,则没有简单的方法可以撤销他们的访问权限。相反,使用 cookie,可以使会话无效。虽然将 JWT 存储在 React 状态可能比使用 localStorage 提供一些安全性,但攻击者可能获得令牌访问权限的风险仍然存在。即使您选择将 JWT 存储在服务器端并执行验证,这也会抵消使用 JWT 的无状态优势,从而引发一个问题:为什么不简单地使用传统会话呢?
JWT 本质上是为短期令牌而设计的,其生命周期通常为 5 分钟或更短。出于会话管理的目的,这个持续时间证明是不够的。此外,还存在与 JWT 相关的安全问题。您可以在这里阅读更多相关内容。
总之,无状态 JWT 缺乏失效或更新的能力,并且可能会带来安全问题,具体取决于其存储位置。相反,有状态 JWT 在功能上类似于会话 cookie,但可能缺乏经过验证和严格审查的实现以及强大的客户端支持。
你不能。“httpOnly”的意思是“JavaScript 无法访问它”。
使用 Redux-Persist 也不能真正帮助您确定您是否仍在登录或会话是否超时。该数据可能在几周前就已保留,或者令牌可能已被撤销。
您可以做的最明智的事情是在服务器上设置一个/whoami端点,并将其作为应用程序初始化向那里发送请求时的第一个操作。有关您的用户的信息返回 -> 很好,保存并显示它。否则,您会收到“401 未经授权”,这意味着用户未登录并且需要登录。
尽管您无法在前端使用 httpOnly cookie 执行任何操作,但肯定有一种方法可以处理前端发送的 httpOnly cookie 并从该 cookie 中提取 JWT,所有这些都在 MERN 堆栈应用程序的后端。
至于保留用户并防止“刷新时注销”问题,您将必须创建一个 useEffect 挂钩来不断检查令牌是否存在 - 我们稍后会讨论这一点。
首先,我建议在后端使用 Cors:
const cors = require("cors");
app.use(
cors({
origin: ["http://...firstOrigin...", ...],
credentials: true,
})
);
Run Code Online (Sandbox Code Playgroud)
准备就绪后,在创建 httpOnly cookie 时设置以下选项。另外,创建一个非 httpOnly cookie 来跟踪具有相同到期日期和布尔值的 httpOnly cookie,而不是 JWT。这将允许您使用“universal-cookie”库并实际读取前端中的非 httpOnly cookie:
res
.cookie("token", token, {
origin: "http://...firstOrigin..."
expires: // set desired expiration here
httpOnly: true,
secure: true,
sameSite: "none",
})
.cookie("checkToken", true, {
origin: "http://...firstOrigin..."
expires: // same as above
secure: true,
sameSite: "none",
})
Run Code Online (Sandbox Code Playgroud)
创建了一个模仿我们实际“令牌”的“checkToken”cookie 后,我们可以使用它来设置状态(useState 挂钩)并通过 useEffect 挂钩保留用户(如果存在且未过期)。
然而,为了正确发送,我们必须首先指定一些事情。在这个例子中,我将使用 axios 在前端进行此类 API 调用。
请注意,每个 API 调用的请求标头都将包含我们的 httpOnly cookie 及其内容 - 我们可以通过打开 chrome 开发工具的网络选项卡来确认这一点,进行 API 调用,然后检查“请求标头”中的“Cookie”...
const cookies = new Cookies();
const checkToken = cookies.get("checkToken");
const AuthUser = () => {
const [user, setUser] = useState(checkToken);
useEffect(() => {
async function checkToken() {
await axios
.post("http://...yourBackend.../authToken", {
withCredentials: true, // IMPORTANT!!!
})
.then((res) => {
// handle response - if successful, set the state...
// to persist the user
)}
.catch((err) => {
// handle error
)}
};
checkToken();
}, []);
// Implement your login behavior here
}
Run Code Online (Sandbox Code Playgroud)
完成后,我们可以确认我们在后端 API 调用的请求正文中获取了此类令牌(无论在何处处理),在控制台中记录 cookie 以检查它,然后将 cookie 的值存储在变量中启用对所述 cookie 的验证:
app.post(".../authToken", (req, res) => {
// Get all cookies from request headers
const { cookie } = req.headers;
// Check to see if we got our cookies
console.log(cookie);
// Handle this as you please
if (cookie == undefined) return;
const token = cookie.split("token=")[1].split(";")[0]; // Yep, it's a string
console.log(token); // Check to see if we stored our cookie's JWT
// Some middleware:
jwt.verify(token, process.env.TOKEN, (err, user) => {
// if success upon verification,
// issue new 'token' and 'checkToken'
});
});
Run Code Online (Sandbox Code Playgroud)
完毕。
请注意,这是一个一般实现,仅作为了解 httpOnly cookie 功能的指南。OP从未提供过原始代码。
我希望这有帮助。祝你好运。
小智 6
在提高使用 React/Django 创建的项目的身份验证工作流程的安全性时,我们遇到了类似的问题
问题是:存储 JWT 的最佳位置是什么?
经过研究,我们最终实现了 Oauth2 协议,这里有一篇文章可以帮助您理解刷新令牌轮换的逻辑
我们的实施是
Ps:按照这种逻辑,您无法访问前端的刷新令牌,因此当您的访问令牌不再有效时,您告诉服务器检查存储在 HttpOnly Cookie 中的刷新令牌是否仍然有效,然后重新生成其他有效令牌
我希望这能激励你
| 归档时间: |
|
| 查看次数: |
44949 次 |
| 最近记录: |