Session 来自 node-fetch 的 cookie 无效?

Session cookie from node-fetch is invalid?

我正在编写 javascript 程序(用于 github 操作),但是 运行 遇到了问题。
我试图使用我的凭据和 csrf 令牌登录 www.overleaf.com and access the page https://www.overleaf.com/project after generating a session cookie by sending a POST request to https://www.overleaf.com/login
响应按预期在 set-cookie header 中包含请求的令牌,但是,当我尝试访问 https://www.overleaf.com/project via GET, I get redirected back to https://www.overleaf.com/login
时 复制保存在我的浏览器中的 session cookie 时,请求工作正常。

我尝试在命令行中使用 cURL 做同样的事情,它在那里工作。

我相当确定我的身份验证请求已被 Overleaf 的服务器接受,因为我曾尝试故意错误地发送密码或 csrf 令牌,在这两种情况下,响应都没有给我新的 session cookie但发送旧的。

如果有人知道出了什么问题,我将非常感谢您的意见。

这是在终端中起作用的,我试图在 javascript 中用 node-fetch:
复制它 curl -v --header "Content-Type: application/json" --cookie "GCLB=someothercookie;overleaf_session2=firstsessioncookie" --data '{"_csrf":"the_csrf_token", "email": "MYEMAIL", "password":"MYPASSWORD"}' https://www.overleaf.com/login
获取 cookie 和 csrf 令牌和
curl -v https://www.overleaf.com/project --cookie "overleaf_session2=returnedsessioncookie; GCLB=someothercookie" 作为 returns 我项目的 html 页面的请求。

这是我的 javascript 代码,我对其进行了两次、三次、四次检查,但我想我遗漏了什么。

const fetch = require("node-fetch");
const parser = require("node-html-parser");
const scparser = require("set-cookie-parser");
 
async function run() {
 
  const email = process.env.EMAIL;
  const password = process.env.PASSWORD;
 
  var cookies = await login(email, password);
 
  console.log(await all_projects(cookies));
 
}
 
async function login(email, password) {
  const login_get = await fetch("https://www.overleaf.com/login");
 
  const get_cookies = login_get.headers.raw()["set-cookie"];
  const parsed_get_cookies = scparser.parse(get_cookies, {
    decodeValues: false
  });
  const overleaf_session2_get = parsed_get_cookies.find(
    (element) => element.name == "overleaf_session2"
  ).value;
  const gclb = parsed_get_cookies.find(
    (element) => element.name == "GCLB"
  ).value;
  console.log("overleaf_session2_get:", overleaf_session2_get, "gclb:", gclb);
 
  const get_responsetext = await login_get.text();
  const _csrf = parser
    .parse(get_responsetext)
    .querySelector("input[name=_csrf]")
    .getAttribute("value");
 
  login_json = { _csrf: _csrf, email: email, password: password };
  console.log(login_json);
  const login_post = await fetch("https://www.overleaf.com/login", {
    method: "post",
    body: JSON.stringify(login_json),
    headers: {
      "Content-Type": "application/json",
      "Cookie": "GCLB=" + gclb + ";overleaf_session2=" + overleaf_session2_get
    }
  });
 
  const post_cookies = login_post.headers.raw()["set-cookie"];
  const parsed_post_cookies = scparser.parse(post_cookies, {
    decodeValues: false
  });
  const overleaf_session2_post = parsed_post_cookies.find(
    (element) => element.name == "overleaf_session2"
  ).value;
 
  console.log(
    "successful:",
    overleaf_session2_get != overleaf_session2_post ? "true" : "false"
  );
  console.log(await fetch("https://www.overleaf.com/project", {
    headers: {
      "Cookie": "overleaf_session2=" + overleaf_session2_post
    }
  }))
  return "overleaf_session2=" + overleaf_session2_post;
}
 
async function all_projects(cookies) {
  const res = await fetch("https://www.overleaf.com/project", {
    headers: {
      Cookie: cookies
    }
  });
  return res;
}
 
run();

是的,您的身份验证请求可能有效,但这可能是一个安全问题,浏览器不允许您这样做并自由访问其他网站的 cookie。

浏览器不允许您访问其他域的 cookie,如果他们这样做,那么网络将是一个不安全的地方,因为例如 Whosebug 可以访问我的 Facebook 帐户 cookie 并提取我的个人信息。

我通过不使用 node-fetch 并切换到 https 来解决我的问题。

这是有效的方法:

async function login(email, password) {
  //GET login page
  const get = await get_login();
  //get necessary info from response
  const csrf = parser
    .parse(get.html)
    .querySelector(`meta[name="ol-csrfToken"]`)
    .getAttribute("content");
  const session1 = scparser
    .parse(get.headers["set-cookie"], { decodeValues: false })
    .find((cookie) => cookie.name == "overleaf_session2").value;
  const gclb = scparser
    .parse(get.headers["set-cookie"], { decodeValues: false })
    .find((cookie) => cookie.name == "GCLB").value;

  //POST login data
  const post = await post_login(csrf, email, password, session1, gclb);
  //get necessary data from response
  const session2 = scparser
    .parse(post["set-cookie"], { decodeValues: false })
    .find((cookie) => cookie.name == "overleaf_session2").value;

  //GET new csrf token from project page
  const projects = await get_projects(session2, gclb);
  const csrf2 = parser
    .parse(projects.html)
    .querySelector(`meta[name="ol-csrfToken"]`)
    .getAttribute("content");

  //return data
  return {
    session: session2,
    gclb: gclb,
    csrf: csrf2,
    projects: projects.html
  };
}

async function get_login() {
  const url = "https://www.overleaf.com/login";
  return new Promise((resolve) => {
    https.get(url, (res) => {
      var data;
      res.on("data", (chunk) => {
        data += chunk;
      });
      res.on("end", () => {
        resolve({ html: data, headers: res.headers });
      });
    });
  });
}

async function get_projects(session2, gclb) {
  const url = "https://www.overleaf.com/project";
  return new Promise((resolve) => {
    https.get(
      url,
      { headers: { Cookie: `GCLB=${gclb};overleaf_session2=${session2}` } },
      (res) => {
        var data;
        res.on("data", (chunk) => {
          data += chunk;
        });
        res.on("end", () => {
          resolve({ html: data, headers: res.headers });
        });
      }
    );
  });
}

async function post_login(_csrf, email, password, session1, gclb) {
  const url = "https://www.overleaf.com/login";
  const options = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Cookie: `GCLB=${gclb};overleaf_session2=${session1}`
    }
  };
  const postData = {
    _csrf: _csrf,
    email: email,
    password: password
  };
  return new Promise((resolve) => {
    var req = https.request(url, options, (res) => {
      resolve(res.headers);
    });

    req.on("error", (e) => {
      console.error(e);
    });

    req.write(JSON.stringify(postData));
    req.end();
  });
}