Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reporting API #5634

Open
Rich-Harris opened this issue Jul 20, 2022 · 5 comments
Open

Reporting API #5634

Rich-Harris opened this issue Jul 20, 2022 · 5 comments
Labels
feature / enhancement New feature or request
Milestone

Comments

@Rich-Harris
Copy link
Member

Describe the problem

#5496 added CSP report-only mode. To use the report-to directive, it's necessary to add Report-To and Reporting-Endpoints headers inside handle (the latter is the newer API, but isn't universally supported yet, so both are necessary), which somewhat defeats the object of letting the framework handle CSP. In fact it's worse, since report-to isn't universally supported; you need to use the report-uri directive as well.

The whole thing is a shocking mess.

Describe the proposed solution

Copied from this comment:

Just spitballing:

export default {
  kit: {
    csp: {...},
    reporting: {
      'main-endpoint': {
        uri: '/reporting/main',
        maxage: 86400
      },
      default: {
        uri: '/reporting/default',
        maxage: 86400
      }
    }
  }
};

SvelteKit could then easily create the headers and report-to/report-uri directives and verify that the directives match the headers (i.e. the endpoints have been defined in reporting, and have a POST handler if they're implemented as SvelteKit endpoints).

Alternatives considered

Leave it as an exercise to readers. I think that would be a shame, since it's so finicky to set up, and we already have nice CSP handling.

Importance

nice to have

Additional Information

No response

@Rich-Harris Rich-Harris added the feature / enhancement New feature or request label Jul 20, 2022
@Rich-Harris Rich-Harris added this to the post-1.0 milestone Jul 20, 2022
@elliott-with-the-longest-name-on-github
Copy link
Contributor

@Rich-Harris

I'll put together a test implementation this weekend.

@elliott-with-the-longest-name-on-github
Copy link
Contributor

Rich, where are you getting this maxage parameter? How does it affect anything? I don't see any option to add a maxage to Reporting-Endpoints (is it a Report-To option I don't know about?).

@elliott-with-the-longest-name-on-github
Copy link
Contributor

Scratch that, I just hadn't found the right documentation yet. Found it.

@jasongitmail
Copy link

jasongitmail commented Oct 24, 2023

The problem with using handle, is that report-to and report-uri headers won't be applied to pre-rendered routes, at least not in production certainly.

A solution I'd suggest

Make this build-adapter specific and write the CSPs to each platform's headers file, instead of using meta tags.

Examples

  • For (Cloudflare and Netlify), detect if _headers exists within the build and append the CSP headers to it, or create _headers if the file doesn't exist yet. This file will exist if the dev is using it to specify custom headers, so don't overwrite it!
  • For Vercel, update vercel.json's headers property to append CSP headers to any existing headers.
  • For static adapter, use meta tags.
  • And so on.

Then headers will be set in production even if routes prerendered.

@jasongitmail
Copy link

jasongitmail commented Oct 24, 2023

To go further, this workflow creates the opportunity for SvelteKit to allow devs to specify project-wide headers, like security headers, within svelte.config.js too, using a pattern like:

headers: {
  "/*": {
    "X-Frame-Options": "DENY"
    "X-Content-Type-Options": "nosniff"
  },
  "/foo": {
      "Another-header": "some-value"
   }  
 }

(It seems okay to not worry about type safety of property options.)

I use the following when creating my _headers:

type HeadersObj = {
  [key: string]: {
    [innerKey: string]: string;
  };
};

export function toStr(obj: HeadersObj): string {
  let output = '';

  for (const [key, value] of Object.entries(obj)) {
    output += `${key}\n`;

    for (const [innerKey, innerValue] of Object.entries(value)) {
      output += `  ${innerKey}: ${innerValue}\n`;
    }

    output += '\n';
  }

  return output.replace(/\n\n$/, '\n');
}

This also lets me use an object of standard headers for all projects with strict security, that can be customized within each project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature / enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants