Sikau

Security · Day 3 · about 40 min

Sessions and CSRF

Cookies, origins and CSRF tokens — and comparing secrets in constant time.

Your browser, someone else's form

Your session cookie goes with every request to your site — even one triggered by a form on evil.example. That's CSRF (cross-site request forgery): "post this order, using the victim's login". Defences: check the Origin header, set cookies SameSite, and require a secret CSRF token the attacker can't read.

Checking a request

const ALLOWED_ORIGINS = ["https://sikau.com"];

function parseCookies(header = "") {
  const out = {};
  for (const part of header.split(";")) {
    const i = part.indexOf("=");
    if (i > 0) out[part.slice(0, i).trim()] = decodeURIComponent(part.slice(i + 1).trim());
  }
  return out;
}

function safeEqual(a, b) {
  if (typeof a !== "string" || typeof b !== "string" || a.length !== b.length) return false;
  let diff = 0;
  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i); // no early exit
  return diff === 0;
}

function checkRequest(req, sessions) {
  if (req.method === "GET" || req.method === "HEAD") return { ok: true };
  if (!ALLOWED_ORIGINS.includes(req.headers.origin)) return { ok: false, status: 403, error: "Bad origin" };
  const session = sessions[parseCookies(req.headers.cookie).sid];
  if (!session) return { ok: false, status: 401, error: "Not signed in" };
  if (!safeEqual(req.body?.csrf, session.csrf)) return { ok: false, status: 403, error: "Bad CSRF token" };
  return { ok: true, user: session.user };
}

The rest of this lesson

  • How a CSRF attack worksexplain
  • Layered defencesexplain
  • Cookie flagsmatch
  • Checking a POSTorder
  • Guard the endpointwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 8 lessons of Security