我一直在尝试为Next.js项目实现可靠的身份验证流程,但现在我完全迷失了。我已经看过Next.js的示例存储库。但是对于完整的解决方案,我还有很多问题。
我有一个express.js API和一个单独的Next.js前端项目。所有数据和身份验证均由API处理。前端仅使用SSR呈现页面。如果我只创建一个整体项目,其中渲染页面和所有数据都由单个服务器处理(我的意思是使用Next.js的自定义服务器选项),那么我将只使用express-session和csurf。这将是管理会话并针对CSRF创建安全性的传统方式。
Express.js API不是必需的。这只是一个例子。它可以是Django API或.Net Core API。要点是,它是一个单独的服务器和一个单独的项目。
我如何拥有一个简单但可靠的结构?我检查了一些我最喜欢的网站(netlify,zeit.co,heroku,spectrum.chat等)。其中一些使用本地存储来存储访问和刷新令牌(易受XSS攻击)。其中一些使用cookie,甚至不使用HTTPOnly(XSS和CSRF都容易受到攻击)。诸如Spectrum.chat之类的示例使用了我上面提到的方式(cookie会话+防止csrf)。
我知道JWT令牌周围有巨大的炒作。但是我发现它们太复杂了。大多数教程只是跳过所有过期,令牌刷新,令牌吊销,黑名单,白名单等。
许多Next.js的会话cookie示例几乎从未提及CSRF。老实说,身份验证始终是我的大问题。有一天,我读到应该使用HTTPOnly cookie,第二天,我看到一个受欢迎的大型站点甚至没有使用它们。或者他们说“永远不要将令牌存储到localStorage”,而繁荣一些大型项目就只是使用这种方法。
有人可以告诉我这种情况的方向吗?
答案 0 :(得分:6)
免责声明:我是以下免费开源软件包的维护者,但我认为这是适当的,因为这是一个普遍的问题,没有一个很好的答案,因为许多流行的解决方案都具有特定的安全性。问题中出现的缺陷(例如不适当使用CSRF并将Session Token或Web Token暴露给客户端JavaScript)。
NextAuth.js软件包试图使用免费的开源软件解决上述问题。
httpOnly
一起使用secure
cookie。__HOST-
或__Secure
)。例如page/api/auth/[...nextauth.js]
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
const options = {
providers: [
// OAuth authentication providers
Providers.Apple({
clientId: process.env.APPLE_ID,
clientSecret: process.env.APPLE_SECRET
}),
Providers.Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET
}),
// Sign in with email (passwordless)
Providers.Email({
server: process.env.MAIL_SERVER,
from: '<no-reply@example.com>'
}),
],
// MySQL, Postgres or MongoDB database (or leave empty)
database: process.env.DATABASE_URL
}
export default (req, res) => NextAuth(req, res, options)
例如pages/index.js
import React from 'react'
import {
useSession,
signin,
signout
} from 'next-auth/client'
export default () => {
const [ session, loading ] = useSession()
return <p>
{!session && <>
Not signed in <br/>
<button onClick={signin}>Sign in</button>
</>}
{session && <>
Signed in as {session.user.email} <br/>
<button onClick={signout}>Sign out</button>
</>}
</p>
}
即使您不选择使用它,也可能会找到有用的代码作为参考(例如,JSON Web Tokens的处理方式和how they are rotated in sessions的使用方式。
答案 1 :(得分:3)
对于我当前的项目,我也必须考虑这一点。我使用相同的技术:ExpressJS API和NextJS服务器端渲染的前端。
我选择做的是在ExpressJS API中使用passport.js。 YouTube上的TheNetNinja拥有21集的播放列表,非常好。他向您展示了如何在您的API中实现Google OAuth 2.0,但是这种逻辑会转移到任何其他策略(JWT,电子邮件+密码,Facebook身份验证等)。
在前端,我会从字面上将用户重定向到Express API中的url。该网址将向用户显示Google OAuth屏幕,用户单击“允许”,API会做更多的事情,为特定用户制作Cookie,然后重定向回前端的网址。现在,用户已通过身份验证。
关于HTTPOnly cookie:我选择关闭此功能,因为我将信息存储在前端所需的cookie中。如果启用了此功能,则前端(javascript)无法访问这些cookie,因为它们是HTTPOnly。
以下是我正在谈论的播放列表的链接: https://www.youtube.com/watch?v=sakQbeRjgwg&list=PL4cUxeGkcC9jdm7QX143aMLAqyM-jTZ2x
希望我已为您提供指导。
编辑: 我尚未回答您有关CSURF的问题,但这是因为我不熟悉它。
答案 2 :(得分:0)
我终于找到了解决方法!
现在我正在使用csrf npm软件包,而不是csurf。 csurf只是将csrf转换为快速的中间件。
因此,我在_app的getInitialProps中创建了一个csrfSecret。它创建秘密,并将其设置为httpOnly cookie。稍后,它将创建一个csrfToken并将其与pageProps一起返回。因此,我可以使用window。 NEXT_DATA .props.csrfToken访问它。如果用户刷新页面,则csrfSecret保持不变,但csrfToken被续订。
当我向代理的“ / api / graphql API路由”发出请求时,它首先从x-xsrf-token头获取csrf令牌,并使用csrfSecret cookie值进行验证。 之后,它将提取authToken cookie的值,并将其传递给实际的GraphQL API。
API都是基于令牌的。它只需要一个非过期的访问令牌。 (顺便说一句,它不必是JWT。可以使用任何具有加密强度的随机令牌。这表示参考/不透明令牌。)
实际的API不需要CSRF检查,因为它不依赖Cookie进行身份验证。它仅检查授权标头。 authToken和csrfSecret都是httpOnly cookie。而且我什至从未将它们存储在客户端内存中。
我认为这是安全的。现在,我对这种解决方案感到满意。