Guides

Security

Edit this page

XSS (Cross Site Scripting)

Solid automatically escape values passed to JSX expressions to reduce the risk of XSS attacks. However, this protection does not apply when using innerHTML.

To protect your application from XSS attacks:

  • Avoid using innerHTML when possible. If necessary, make sure to sanitize user-supplied data with libraries such as DOMPurify.
  • Validate and sanitize user inputs, especially form inputs on the server and client.
  • Set a Content Security Policy (CSP).
  • Sanitize attributes containing user-supplied data within <noscript> elements. This includes both the attributes of the <noscript> element itself and its children.

It is highly recommended to read the Cross Site Scripting Prevention Cheat Sheet for further guidance.


Content Security Policy (CSP)

To configure the Content-Security-Policy HTTP header, a middleware can be used.

If you want to use a strict CSP with nonces:

  1. Create a middleware that configures the CSP header. It must then be registered using the onRequest event.
  2. Create a nonce using a cryptographic random value generator, such as the randomBytes function from the crypto module.
  3. Store the nonce in the locals object.
  4. Configure SolidStart to use the nonce in your entry-server.tsx file.

Without nonce

To configure CSP without a nonce, a middleware that sets the CSP header is required, and it should be registered to run during the onBeforeResponse event:

import { createMiddleware } from "@solidjs/start/middleware";
export default createMiddleware({
onBeforeResponse: (event) => {
const csp = `
default-src 'self';
font-src 'self' ;
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
`.replace(/\s+/g, " ");
event.response.headers.set("Content-Security-Policy", csp);
},
});

CORS (Cross-Origin Resource Sharing)

When other applications need access to API endpoints, a middleware that configures the CORS headers is needed:

import { createMiddleware } from "@solidjs/start/middleware";
import { json } from "@solidjs/router";
const TRUSTED_ORIGINS = ["https://my-app.com", "https://another-app.com"];
export default createMiddleware({
onBeforeResponse: (event) => {
const { request, response } = event;
response.headers.append("Vary", "Origin, Access-Control-Request-Method");
const origin = request.headers.get("Origin");
const requestUrl = new URL(request.url);
const isApiRequest = requestUrl && requestUrl.pathname.startsWith("/api");
if (isApiRequest && origin && TRUSTED_ORIGINS.includes(origin)) {
// Handle preflight requests.
if (
request.method === "OPTIONS" &&
request.headers.get("Access-Control-Request-Method")
) {
// Preflight requests are standalone, so we immediately send a response.
return json(null, {
headers: {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Methods": "OPTIONS, POST, PUT, PATCH, DELETE",
"Access-Control-Allow-Headers": "Authorization, Content-Type",
},
});
}
// Handle normal requests.
response.headers.set("Access-Control-Allow-Origin", origin);
}
},
});

CSRF (Cross-Site Request Forgery)

To prevent CSRF attacks, a middleware can be used to block untrusted requests:

import { createMiddleware } from "@solidjs/start/middleware";
import { json } from "@solidjs/router";
const SAFE_METHODS = ["GET", "HEAD", "OPTIONS", "TRACE"];
const TRUSTED_ORIGINS = ["https://another-app.com"];
export default createMiddleware({
onRequest: (event) => {
const { request } = event;
if (!SAFE_METHODS.includes(request.method)) {
const requestUrl = new URL(request.url);
const origin = request.headers.get("Origin");
// If we have an Origin header, check it against our allowlist.
if (origin) {
const parsedOrigin = new URL(origin);
if (
parsedOrigin.origin !== requestUrl.origin &&
!TRUSTED_ORIGINS.includes(parsedOrigin.host)
) {
return json({ error: "origin invalid" }, { status: 403 });
}
}
// If we are serving via TLS and have no Origin header, prevent against
// CSRF via HTTP man-in-the-middle attacks by enforcing strict Referer
// origin checks.
if (!origin && requestUrl.protocol === "https:") {
const referer = request.headers.get("Referer");
if (!referer) {
return json({ error: "referer not supplied" }, { status: 403 });
}
const parsedReferer = new URL(referer);
if (parsedReferer.protocol !== "https:") {
return json({ error: "referer invalid" }, { status: 403 });
}
if (
parsedReferer.host !== requestUrl.host &&
!TRUSTED_ORIGINS.includes(parsedReferer.host)
) {
return json({ error: "referer invalid" }, { status: 403 });
}
}
}
},
});

This example demonstrates a basic CSRF protection that verifies the Origin and Referer headers, blocking requests from untrusted origins. Additionally, consider implementing a more robust CSRF protection mechanism, such as the Double-Submit Cookie Pattern.

For further guidance, you can look at the Cross-Site Request Forgery Prevention Cheat Sheet.

Report an issue with this page