使用 Http 和 Secure 将 Jwt 令牌存储在 Cookie 中,而不是 Javascript 中的 LocalStorage

Posted

技术标签:

【中文标题】使用 Http 和 Secure 将 Jwt 令牌存储在 Cookie 中,而不是 Javascript 中的 LocalStorage【英文标题】:Storing Jwt Token in Cookie with Http and Secure instead of LocalStorage in Javascript 【发布时间】:2019-03-20 15:15:29 【问题描述】:

大家好,

我正在开发一个具有 Web API (RestAPI) 和 SPA(单页应用程序)解决方案的项目。

根据我在 Udemy 上关注的视频,他将 jwt 令牌存储在本地存储中,但后来我发现存储在本地存储中有点风险,因为攻击者可以复制实际令牌并在未来发出请求.

我读过一些博客,在 cookie 中存储令牌很好,因为您可以将 cookie 设置为 httpOnly 和安全。但问题是,我不知道如何实现。

这是我在用户具有有效登录时的示例代码:

axios.post('api/login/', this.account).then(response=>
    if(response)
        localStorage.setItem('token', response.data.token); // will successfully save to localstorage
        // navigation here
    
).catch(error=> console.log(error); );

如何使用安全设置将其存储在 cookie 中?

【问题讨论】:

您在学习哪个 Udemy 课程?我注意到 Traversy 的 MERN 课程和 Mosh 的 Node 课程都有这个问题。但很可能还有更多的课程存在这个问题。 【参考方案1】:

这看起来类似于:Set a cookie to HttpOnly via javascript

添加到答案this source引号:

为防止跨站点脚本 (XSS) 攻击,HttpOnly cookie JavaScript 的 Document.cookie API 无法访问

为了使用 httpOnly 和安全标志保存令牌,服务器必须在标头中对此进行响应(再次取自上述来源):

Set-Cookie: id=a3fWa;过期=格林威治标准时间 2015 年 10 月 21 日星期三 07:28:00;安全的; HttpOnly

所以,如果服务器没有使用 Set-Cookie 标头响应,我认为您不能安全地保存 cookie,而是将令牌作为响应正文返回。

【讨论】:

您有使用该设置将令牌保存到 cookie 的示例代码吗? 将令牌从您从 REST API 收到的响应中保存到 cookie,或者服务器发送 Set-Cookie 标头?【参考方案2】:

您不能从客户端代码(如 Javascript)设置 HttpOnly cookie。因此,此类 cookie 不得使用 Javascript 读取。您必须从服务器设置此类 cookie。您可以发送带有服务器响应的 cookie,浏览器将从标题中读取它们来存储它们。之后,浏览器会将该 cookie 发送到服务器,每个请求都会发送到服务器,直到 cookie 过期。

你可以从服务器设置cookie如下..

Cookie cookie = new Cookie(name, value); //name and value of the cookie
cookie.setMaxAge(expire); //expire could be 60 (seconds)
cookie.setHttpOnly(true);
cookie.setPath("/");
response.addCookie(cookie);

【讨论】:

【参考方案3】:

我读过一些博客,认为在 cookie 中存储令牌很好,因为 您可以将 cookie 设置为 httpOnly 且安全。但问题是,我 不知道怎么实现。

你需要在服务器上实现这个,不是在客户端上。

以下是登录端点的服务器代码示例:

// If the passwords match, generate a new jwt for this user
const token = user.generateAuthToken();

// Set the options for the cookie
let cookieOptions = 
    // Delete the cookie after 90 days
    expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000 ),
    // Set the cookie's HttpOnly flag to ensure the cookie is 
    // not accessible through JS, making it immune to XSS attacks  
    httpOnly: true,
;
// In production, set the cookie's Secure flag 
// to ensure the cookie is only sent over HTTPS
if( process.env.NODE_ENV === 'production') 
    cookieOptions.secure = true;


// Send a success response to the client
// including the jwt in a cookie
return res
    .cookie('jwt', token, cookieOptions)
    .status(200)
    .json(
        msg: 'Successfully logged in',
    );

【讨论】:

以上是关于使用 Http 和 Secure 将 Jwt 令牌存储在 Cookie 中,而不是 Javascript 中的 LocalStorage的主要内容,如果未能解决你的问题,请参考以下文章

使用刷新令牌和访问令牌如何比仅使用 1 个 JWT 更“安全”?

Java Angular JWT 实现

我们如何将 JWT 令牌存储在仅限 Http 的 cookie 中?

Rails:使用敲门对 JWT 令牌进行身份验证

JWT 刷新和访问令牌

如何将JSON Web令牌(JWT)传递给get请求