Guide: Protect local storage with CSP

Parse is storing user data in local storage, and I learned that local storage can be hacked with XSS attacks. I also learned that implementing CSP can prevent XSS attacks, but how to do it with parse.

Here is my custom header function that is supposed to add CSP along with other headers. But apparently it’s not working, because the content loads even if CSP blocks it.

How to set up CSP with parse?

const setHeaders = (req, res, next) => {
  const origin = "http://localhost:3000"
  res.setHeader("Access-Control-Allow-Origin", origin);
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  res.setHeader("Access-Control-Allow-Headers", "X-Requested-With,content-type");
  res.setHeader(
    "Content-Security-Policy",
    "default-src 'self'; img-src *; media-src *; script-src 'none'; frame-src youtube.com stripe.com"
  );
  res.setHeader("Access-Control-Allow-Credentials", true);
  next();
};

module.exports = setHeaders;

And here is how I mount it along with the cors options

app.options("*", cors(corsOptions), setHeaders);
app.use(mountPath, server.app, cors(corsOptions), setHeaders);
app.use(cors(corsOptions), setHeaders);

It’s not in the response headers

Here is how to set up CSP to prevent XSS attacks from stealing data from local storage.

  1. Create a function that will add the header
async function setHeaders(req, res, next) {
  res.setHeader(
     // define your policy in the line below
    "Content-Security-Policy",
    "default-src 'self'; img-src *; media-src *; script-src 'self'; frame-src youtube.com stripe.com 17track.net"
  );
  next();
};
  1. Mount the function to the app:
  const httpServer = require("http").createServer(app);
  const mountPath = process.env.PARSE_MOUNT || "/parse";
  app.use((req, res, next) => setHeaders(req, res, next));

3 Result:

Note that the goal of CSP is to disable execution of any in-line scripts on the page to prevent hackers from injecting their code that will copy the contents of the local storage.

!!!That’s why the inline code (inside the “script” tags) on your password reset, verify email and other pages will also not work unless you move it from HTML to a separate .js file and import into the HTML.

This way you will transform your inline js code into the hosted js file, which won’t be blocked by CSP because it’s hosted on the same domain.

2 Likes