Skip to content
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bba6f2f
Improve security docs
amirhhashemi Mar 1, 2025
cd23779
update
amirhhashemi Mar 1, 2025
bd473d1
Merge branch 'main' into improve-security-docs
amirhhashemi Mar 1, 2025
b329396
update
amirhhashemi Mar 1, 2025
786e7fd
update
amirhhashemi Mar 4, 2025
516bc8b
use bullet lists
amirhhashemi Mar 4, 2025
9a740d5
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 4, 2025
2c03b54
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 4, 2025
216b219
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 6, 2025
4b00e2b
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 7, 2025
8e3c7d6
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 7, 2025
6170e10
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 7, 2025
6849828
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 7, 2025
21b1e15
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 7, 2025
aa2d138
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 8, 2025
7d1bdca
Merge branch 'main' into improve-security-docs
kodiakhq[bot] Mar 8, 2025
9e9dcbf
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
25b8d5a
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
b55ce18
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
9ff7ede
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
fd97efa
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
fb7263d
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
930df93
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
21bde21
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
dc164f9
fix grammar and add link to csp in mdn
amirhhashemi Mar 8, 2025
0660e97
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
e18766c
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
0c9472e
more info about nonce
amirhhashemi Mar 8, 2025
5cbc5aa
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
b2b586c
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
404740b
Update src/routes/solid-start/guides/security.mdx
amirhhashemi Mar 8, 2025
8d5f66f
fix grammar
amirhhashemi Mar 8, 2025
5195d4e
Merge branch 'main' into improve-security-docs
LadyBluenotes Mar 8, 2025
1ff3de3
Update src/routes/solid-start/guides/security.mdx
LadyBluenotes Mar 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 191 additions & 21 deletions src/routes/solid-start/guides/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,205 @@
title: Security
---

As a non-opinionated framework, SolidStart doesn't enforce any security practices, though it enables developers to implement them as needed.
It is important to know what are the requirements for your own app and implement the fitting security measures.
If at any point you are unsure about the security of your app, or how to achieve something within the constraints of SolidStart reach us on [Discord](https://discord.gg/solidjs).
## XSS (Cross Site Scripting)

Below you will find a few notes on how to establish some measures.
Solid automatically escape values passed to JSX expressions to reduce the risk of XSS attacks.
However, this protection does not apply when using [`innerHTML`](/reference/jsx-attributes/innerhtml-or-textcontent#innerhtml-or-textcontent).

## Security Headers
To protect your application from XSS attacks:

Through the use of a [middleware](/solid-start/reference/server/create-middleware#example) it is possible to tab into the `onRequest` event handlers and make sure every request going through your servers have the proper security headers set.
With this, it is possible to setup headers like `Content-Security-Policy`, `X-Frame-Options`, `X-XSS-Protection`, `X-Content-Type-Options`, among others.
- Avoid using `innerHTML` when possible.
If necessary, make sure to sanitize user-supplied data with libraries such as [DOMPurify](https://github.com/cure53/DOMPurify).
- Validate and sanitize user inputs, especially form inputs on the server and client.
- Set a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
- Sanitize attributes containing user-supplied data within `<noscript>` elements.
This includes both the attributes of the `<noscript>` element itself and its children.

### Nonces
It is highly recommended to read the [Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) for further guidance.

When using `Content-Security-Policy` it is possible to use nonces to allow inline scripts and styles to be executed.
SolidStart enables that smoothly in the [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-server).
## Content Security Policy (CSP)

By passing generating the `nonce` within a middleware and storing it in the `request.locals` object, it is possible to use it in the `entry-server.tsx` to generate the `Content-Security-Policy` header.
To configure the `Content-Security-Policy` HTTP header, a [middleware](/solid-start/advanced/middleware) can be used.

## Cross Request Forgery (CSRF)
### With nonce (recommended)

There are multiple ways to add CSRF Protection to your SolidStart app.
The quickest and most common way is to check the `request.referrer` header when the HTTP method is `POST`, `PUT`, `PATCH` or `DELETE`.
This can also be achieved through an `onRequest` [middleware](/solid-start/reference/server/create-middleware#example).
If you want to use a [strict CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#strict_csp) with nonces:

## Cross Site Scripting (XSS)
1. Create a middleware that configures the CSP header.
It must then be registered using the [`onRequest`](/solid-start/advanced/middleware#onrequest) event.
2. Create a nonce using a cryptographic random value generator, such as the [`randomBytes`](https://nodejs.org/api/crypto.html#cryptorandombytessize-callback) function from the `crypto` module.
3. Store the nonce in the [`locals`](/solid-start/advanced/middleware#locals) object.
4. Configure SolidStart to use the nonce in your [`entry-server.tsx`](/solid-start/reference/entrypoints/entry-server) file.

SolidStart automatically escape inserts and attributes in HTML.
The exception is when HTML is inserted via the `innerHTML` property, which bypasses the escaping.
Additionally, it's important to note that `<noscript>` are also outside of the purview of SolidStart, since those tags and its contents are evaluated even without JavaScript.
It is important to sanitize any strings in attributes, especially when inside `<noscript>` tags.
<TabsCodeBlocks>
<div id="Middleware">

As a rule-of-thumb it is recommended to avoid injecting HTML into your page as much as possible, make sure the contents of `<noscript>` are properly sanitized, and add a strict Content Security Policy to your application.
```tsx
import { createMiddleware } from "@solidjs/start/middleware";
import { randomBytes } from "crypto";

export default createMiddleware({
onRequest: (event) => {
const nonce = randomBytes(16).toString("base64");

event.locals.nonce = nonce;

const csp = `
default-src 'self';
script-src 'nonce-${nonce}' 'strict-dynamic' 'unsafe-eval';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
`.replace(/\s+/g, " ");

event.response.headers.set("Content-Security-Policy", csp);
},
});
```

</div>
<div id="entry-server.tsx">

```tsx {6} title="src/entry-server.tsx"
// @refresh reload
import { createHandler, StartServer } from "@solidjs/start/server";

export default createHandler(
() => <StartServer /* ... */ />,
(event) => ({ nonce: event.locals.nonce })
);
```

</div>
</TabsCodeBlocks>

### 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`](/solid-start/advanced/middleware#onbeforeresponse) event:

```tsx
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:

```tsx
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:

```tsx
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](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#alternative-using-a-double-submit-cookie-pattern).

For further guidance, you can look at the [Cross-Site Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
Loading