Security
XSS (Cross Site Scripting)
Solid automatically escapes 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:
- Set a Content Security Policy (CSP).
- Validate and sanitize user inputs, especially form inputs on the server and client.
- Avoid using
innerHTMLwhen possible. If necessary, make sure to sanitize user-supplied data with libraries such as DOMPurify. - Sanitize attributes containing user-supplied data within
<noscript>elements. This includes both the attributes of the<noscript>element itself and its children. - When URLs are provided or constructed via user input validate its
originandprotocol(to avoid evaluating code viajavascript:URLs) using the URL API.
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.
SolidStart v2 defaults to JSON serialization, which avoids an unsafe-eval requirement. Keep that default for a strict CSP. See solidStart serialization.
With nonce (recommended)
If you want to use a strict CSP with nonces:
- Create middleware that generates a nonce and configures the CSP header before calling
next(). - Create a nonce using a cryptographic random value generator, such as the
randomBytesfunction from thecryptomodule. - Store the nonce in the
localsobject. - Configure SolidStart to use the nonce in your
entry-server.tsxfile.
Without nonce
To configure CSP without a nonce, set the header after the downstream handler returns:
import { createMiddleware } from "@solidjs/start/middleware";
export default createMiddleware([ async (event, next) => { const response = await next(); const csp = ` default-src 'self'; font-src 'self' ; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'; `.replace(/\s+/g, " ");
event.res.headers.set("Content-Security-Policy", csp); return response; },]);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";
const TRUSTED_ORIGINS = ["https://my-app.com", "https://another-app.com"];
export default createMiddleware([ async (event, next) => { const origin = event.req.headers.get("Origin"); const requestUrl = new URL(event.req.url); const isApiRequest = requestUrl && requestUrl.pathname.startsWith("/api");
if (isApiRequest && origin && TRUSTED_ORIGINS.includes(origin)) { if ( event.req.method === "OPTIONS" && event.req.headers.get("Access-Control-Request-Method") ) { return new Response(null, { headers: { "Access-Control-Allow-Origin": origin, "Access-Control-Allow-Methods": "OPTIONS, POST, PUT, PATCH, DELETE", "Access-Control-Allow-Headers": "Authorization, Content-Type", Vary: "Origin, Access-Control-Request-Method", }, }); }
event.res.headers.set("Access-Control-Allow-Origin", origin); }
event.res.headers.append("Vary", "Origin, Access-Control-Request-Method"); return next(); },]);CSRF (Cross-Site Request Forgery)
To prevent basic CSRF attacks, a middleware can be used to block untrusted requests:
import { createMiddleware } from "@solidjs/start/middleware";
const SAFE_METHODS = ["GET", "HEAD", "OPTIONS", "TRACE"];const TRUSTED_ORIGINS = ["https://another-app.com"];
export default createMiddleware([ (event, next) => { const request = event.req;
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 Response.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 Response.json( { error: "referer not supplied" }, { status: 403 } ); }
const parsedReferer = new URL(referer);
if (parsedReferer.protocol !== "https:") { return Response.json({ error: "referer invalid" }, { status: 403 }); }
if ( parsedReferer.host !== requestUrl.host && !TRUSTED_ORIGINS.includes(parsedReferer.host) ) { return Response.json({ error: "referer invalid" }, { status: 403 }); } } }
return next(); },]);This example demonstrates a basic CSRF protection that verifies the Origin and Referer headers, blocking requests from untrusted origins.
Please note both of these headers can be forged.
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.