Skip to content

Commit 7b22b35

Browse files
authored
fix: allow cross-protocol requests from the same domain (#7693)
1 parent feee2f5 commit 7b22b35

File tree

7 files changed

+35
-9
lines changed

7 files changed

+35
-9
lines changed

.changeset/pretty-falcons-grow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@builder.io/qwik-city': patch
3+
---
4+
5+
FIX: allow cross-protocol requests from the same domain

packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@
456456
}
457457
],
458458
"kind": "Interface",
459-
"content": "```typescript\nexport interface ServerRenderOptions extends RenderOptions \n```\n**Extends:** RenderOptions\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[checkOrigin?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean\n\n\n</td><td>\n\n_(Optional)_ Protection against cross-site request forgery (CSRF) attacks.\n\nWhen `true`<!-- -->, for every incoming POST, PUT, PATCH, or DELETE form submissions, the request origin is checked to match the server's origin.\n\nBe careful when disabling this option as it may lead to CSRF attacks.\n\nDefaults to `true`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[qwikCityPlan](#)\n\n\n</td><td>\n\n\n</td><td>\n\nQwikCityPlan\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[render](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRender\n\n\n</td><td>\n\n\n</td></tr>\n</tbody></table>",
459+
"content": "```typescript\nexport interface ServerRenderOptions extends RenderOptions \n```\n**Extends:** RenderOptions\n\n\n<table><thead><tr><th>\n\nProperty\n\n\n</th><th>\n\nModifiers\n\n\n</th><th>\n\nType\n\n\n</th><th>\n\nDescription\n\n\n</th></tr></thead>\n<tbody><tr><td>\n\n[checkOrigin?](#)\n\n\n</td><td>\n\n\n</td><td>\n\nboolean \\| 'lax-proto'\n\n\n</td><td>\n\n_(Optional)_ Protection against cross-site request forgery (CSRF) attacks.\n\nWhen `true`<!-- -->, for every incoming POST, PUT, PATCH, or DELETE form submissions, the request origin is checked to match the server's origin. `lax-proto` is for SSL-terminating proxies\n\nBe careful when disabling this option as it may lead to CSRF attacks.\n\nDefaults to `true`<!-- -->.\n\n\n</td></tr>\n<tr><td>\n\n[qwikCityPlan](#)\n\n\n</td><td>\n\n\n</td><td>\n\nQwikCityPlan\n\n\n</td><td>\n\n\n</td></tr>\n<tr><td>\n\n[render](#)\n\n\n</td><td>\n\n\n</td><td>\n\nRender\n\n\n</td><td>\n\n\n</td></tr>\n</tbody></table>",
460460
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/middleware/request-handler/types.ts",
461461
"mdFile": "qwik-city.serverrenderoptions.md"
462462
},

packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,13 +1694,13 @@ Description
16941694
16951695
</td><td>
16961696
1697-
boolean
1697+
boolean \| 'lax-proto'
16981698
16991699
</td><td>
17001700
17011701
_(Optional)_ Protection against cross-site request forgery (CSRF) attacks.
17021702
1703-
When `true`, for every incoming POST, PUT, PATCH, or DELETE form submissions, the request origin is checked to match the server's origin.
1703+
When `true`, for every incoming POST, PUT, PATCH, or DELETE form submissions, the request origin is checked to match the server's origin. `lax-proto` is for SSL-terminating proxies
17041704
17051705
Be careful when disabling this option as it may lead to CSRF attacks.
17061706

packages/qwik-city/src/middleware/request-handler/middleware.request-handler.api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export class ServerError<T = any> extends Error {
194194

195195
// @public (undocumented)
196196
export interface ServerRenderOptions extends RenderOptions {
197-
checkOrigin?: boolean;
197+
checkOrigin?: boolean | 'lax-proto';
198198
// (undocumented)
199199
qwikCityPlan: QwikCityPlan;
200200
// (undocumented)

packages/qwik-city/src/middleware/request-handler/request-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async function loadRequestHandlers(
6464
qwikCityPlan: QwikCityPlan,
6565
pathname: string,
6666
method: string,
67-
checkOrigin: boolean,
67+
checkOrigin: boolean | 'lax-proto',
6868
renderFn: Render
6969
) {
7070
const { routes, serverPlugins, menus, cacheModules } = qwikCityPlan;

packages/qwik-city/src/middleware/request-handler/resolve-request-handlers.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const resolveRequestHandlers = (
3939
serverPlugins: RouteModule[] | undefined,
4040
route: LoadedRoute | null,
4141
method: string,
42-
checkOrigin: boolean,
42+
checkOrigin: boolean | 'lax-proto',
4343
renderHandler: RequestHandler
4444
) => {
4545
const routeLoaders: LoaderInternal[] = [];
@@ -67,6 +67,10 @@ export const resolveRequestHandlers = (
6767
(method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE')
6868
) {
6969
requestHandlers.unshift(csrfCheckMiddleware);
70+
71+
if (checkOrigin === 'lax-proto') {
72+
requestHandlers.push(csrfLaxProtoCheckMiddleware);
73+
}
7074
}
7175
if (isPageRoute) {
7276
// server$
@@ -424,7 +428,13 @@ export function getPathname(url: URL, trailingSlash: boolean | undefined) {
424428

425429
export const encoder = /*#__PURE__*/ new TextEncoder();
426430

431+
function csrfLaxProtoCheckMiddleware(requestEv: RequestEvent) {
432+
checkCSRF(requestEv, 'lax-proto');
433+
}
427434
function csrfCheckMiddleware(requestEv: RequestEvent) {
435+
checkCSRF(requestEv);
436+
}
437+
function checkCSRF(requestEv: RequestEvent, laxProto?: 'lax-proto') {
428438
const isForm = isContentType(
429439
requestEv.request.headers,
430440
'application/x-www-form-urlencoded',
@@ -434,7 +444,18 @@ function csrfCheckMiddleware(requestEv: RequestEvent) {
434444
if (isForm) {
435445
const inputOrigin = requestEv.request.headers.get('origin');
436446
const origin = requestEv.url.origin;
437-
const forbidden = inputOrigin !== origin;
447+
let forbidden = inputOrigin !== origin;
448+
449+
// fix https://github.com/QwikDev/qwik/issues/7688
450+
if (
451+
forbidden &&
452+
laxProto &&
453+
origin.startsWith('https://') &&
454+
inputOrigin?.slice(4) === origin.slice(5)
455+
) {
456+
forbidden = false;
457+
}
458+
438459
if (forbidden) {
439460
throw requestEv.error(
440461
403,

packages/qwik-city/src/middleware/request-handler/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ export interface ServerRenderOptions extends RenderOptions {
5252
* Protection against cross-site request forgery (CSRF) attacks.
5353
*
5454
* When `true`, for every incoming POST, PUT, PATCH, or DELETE form submissions, the request
55-
* origin is checked to match the server's origin.
55+
* origin is checked to match the server's origin. `lax-proto` is for SSL-terminating proxies
5656
*
5757
* Be careful when disabling this option as it may lead to CSRF attacks.
5858
*
5959
* Defaults to `true`.
6060
*/
61-
checkOrigin?: boolean;
61+
checkOrigin?: boolean | 'lax-proto';
6262
}
6363

6464
/** @public */

0 commit comments

Comments
 (0)