如何使用Apollo和GraphQL在Nextjs中实现CSRF保护

在Nextjs存储库中的此示例之后,我想实现CSRF保护(也许使用csurf程序包),因为我正在使用带有Express-Session的会话ID Cookie。

我尝试在自定义服务器中设置csurf并将生成的令牌保存在res.locals.csrfToken中,该页面在第一次加载时就可以通过示例中/lib/withApollo.js中的静态方法“ getInitialProps”获取链接。一旦我尝试更改页面(带有链接)或尝试使用apollo(例如登录)发出发布请求,服务器便更改了csrf令牌,因此Apollo使用的令牌不再有用,因此我得到了“ csrf无效”错误。

具有csurf配置的自定义服务器

const csrf = require('csurf');
const csrfProtection = csrf();
////express-session configuration code////
app.use(csrfProtection);
app.use((req, res, next) => {
    res.locals.csrfToken = req.csrfToken();
next();
})

/lib/initApollo.js

function create(initialState, { getToken, cookies, csrfToken }) {
  const httpLink = createHttpLink({
    uri: "http://localhost:3000/graphql",
    credentials: "include"
  });

    const authLink = setContext((_, { headers }) => {
    const token = getToken();
    return {
      headers: {
        ...headers,
        authorization: token ? `Bearer ${token}` : "",
        Cookie: cookies ? cookies : "",
        "x-xsrf-token": csrfToken ? csrfToken : ""
      }
    };
  });

/lib/withApollo.js

static async getInitialProps(ctx) {
  const {
    Component,
    router,
    ctx: { req, res }
  } = ctx;
  const apollo = initApollo(
    {},
    {
      getToken: () => parseCookies(req).token,
      cookies: req ? req.headers.cookie : "",
      csrfToken: res ? res.locals.csrfToken : document.cookie
    }
  );

使用此配置,可以保护每条路由免受csrf的侵害,但是服务器上创建的令牌通常会更改,并且Apollo无法在需要时立即检索更新的令牌,因此第一次加载成功,但是随后的页面更改(链接)或任何发布请求失败,因为令牌已更改。

LStafan2020/03/24 11:15:00

更新资料

经过如此多的浏览,我终于能够发送csrf cookie。我认为问题在于单词return。当您使用return时,它会排除cookie。这是我通过编辑所做的/lib/initApollo.js


函数create(initialState,{getToken,Cookies,csrfToken}){
  const httpLink = createHttpLink({
    uri:“ http:// localhost:3000 / graphql”,
    凭据:“包括”
  });

    const authLink = setContext((_,{headers})=> {
    const token = getToken();
    返回{
      标头:{
        ...标题
        授权:令牌?`Bearer $ {token}`:“”,
        “ x-xsrf-token”:csrfToken?csrfToken:“”
      }
      饼干: {
        ...饼干
      }
    };
  });

e!但是,SSR没有cookie。我认为我们应该有两个来自客户端的端点,另一个应该是SSR。SSR网址可以被csrf豁免。

宝儿Near2020/03/24 11:15:00

这可能不是您要寻找的答案。我在这里读到,如果您使用的是JWT,则不需要CSRFToken。尚不确定,但目前唯一可行的方法。

本杰明M解释如下:

我发现了一些关于CSRF +不使用cookie进行身份验证的信息:

https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/ “由于您不依赖Cookie,因此无需防御跨站点请求”

http://angular-tips.com/blog/2014/05/json-web-tokens-introduction/ “如果我们采用cookie方式,则确实需要执行CSRF以避免跨站点请求。这是我们可以做到的事情就会忘记使用JWT的时间。” (JWT = Json Web令牌,这是针对无状态应用程序的基于令牌的身份验证)

http://www.jamesward.com/2013/05/13/securing-single-page-apps-and-rest-services “在不冒CSRF漏洞风险的情况下进行身份验证的最简单方法是避免使用Cookie来识别用户”

http://sitr.us/2011/08/26/cookies-are-bad-for-you.html “ CSRF的最大问题是cookie绝对无法抵御此类攻击。如果您使用cookie身份验证,您还必须采取其他措施来防止CSRF。您可以采取的最基本的预防措施是,确保您的应用程序永远不会响应GET请求而产生任何副作用。”

还有很多页面,如果您不使用Cookie进行身份验证,则表明您不需要任何CSRF保护。当然,您仍然可以将Cookie用于其他所有内容,但要避免在其中存储诸如session_id之类的内容。

全文在这里:使用Stateless(= Sessionless)身份验证时需要CSRF令牌吗?