Skip to content

Commit 3820e68

Browse files
Sora4431claude
andcommitted
fix(web): Copilot レビュー対応 — Referer パース安全化・selfOrigin 取得改善
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 60abead commit 3820e68

2 files changed

Lines changed: 17 additions & 31 deletions

File tree

apps/web/src/lib/server/validate-origin.test.ts

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,48 +22,50 @@ describe('validateOrigin', () => {
2222
});
2323

2424
it('rejects requests with no Origin or Referer', () => {
25-
const req = createRequest({ host: 'example.com' });
25+
const req = createRequest();
2626
expect(() => validateOrigin(req)).toThrow();
2727
});
2828

2929
it('allows requests with matching Origin (self-origin fallback)', () => {
3030
const req = createRequest({
3131
origin: 'https://example.com',
32-
host: 'example.com',
3332
});
3433
expect(() => validateOrigin(req)).not.toThrow();
3534
});
3635

3736
it('rejects requests with mismatched Origin (self-origin fallback)', () => {
3837
const req = createRequest({
3938
origin: 'https://evil.com',
40-
host: 'example.com',
4139
});
4240
expect(() => validateOrigin(req)).toThrow();
4341
});
4442

4543
it('allows requests with matching Referer when no Origin', () => {
4644
const req = createRequest({
4745
referer: 'https://example.com/page',
48-
host: 'example.com',
4946
});
5047
expect(() => validateOrigin(req)).not.toThrow();
5148
});
5249

5350
it('rejects requests with mismatched Referer', () => {
5451
const req = createRequest({
5552
referer: 'https://evil.com/page',
56-
host: 'example.com',
5753
});
5854
expect(() => validateOrigin(req)).toThrow();
5955
});
6056

57+
it('rejects requests with malformed Referer', () => {
58+
for (const referer of ['not-a-url', '/relative/path']) {
59+
const req = createRequest({ referer });
60+
expect(() => validateOrigin(req)).toThrow();
61+
}
62+
});
63+
6164
describe('ALLOWED_ORIGINS', () => {
6265
it('allows origins in the allowlist', () => {
6366
mockEnv.ALLOWED_ORIGINS = 'https://app.example.com, https://staging.example.com';
6467
const req = createRequest({
6568
origin: 'https://app.example.com',
66-
host: 'example.com',
6769
});
6870
expect(() => validateOrigin(req)).not.toThrow();
6971
});
@@ -72,25 +74,8 @@ describe('validateOrigin', () => {
7274
mockEnv.ALLOWED_ORIGINS = 'https://app.example.com';
7375
const req = createRequest({
7476
origin: 'https://evil.com',
75-
host: 'example.com',
7677
});
7778
expect(() => validateOrigin(req)).toThrow();
7879
});
7980
});
80-
81-
it('uses x-forwarded-proto for self-origin comparison', () => {
82-
const req = createRequest({
83-
origin: 'http://example.com',
84-
host: 'example.com',
85-
'x-forwarded-proto': 'http',
86-
});
87-
expect(() => validateOrigin(req)).not.toThrow();
88-
});
89-
90-
it('rejects when host header is missing and no ALLOWED_ORIGINS', () => {
91-
const req = createRequest({
92-
origin: 'https://example.com',
93-
});
94-
expect(() => validateOrigin(req)).toThrow();
95-
});
9681
});

apps/web/src/lib/server/validate-origin.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ export function validateOrigin(request: Request): void {
1313
const origin = request.headers.get('origin');
1414
const referer = request.headers.get('referer');
1515

16-
const requestOrigin = origin ?? (referer ? new URL(referer).origin : null);
16+
let requestOrigin = origin;
17+
if (!requestOrigin && referer) {
18+
try {
19+
requestOrigin = new URL(referer).origin;
20+
} catch {
21+
requestOrigin = null;
22+
}
23+
}
1724

1825
if (!requestOrigin) {
1926
throw error(403, 'Forbidden');
@@ -27,13 +34,7 @@ export function validateOrigin(request: Request): void {
2734
}
2835

2936
// Fallback: 自オリジンとの比較
30-
const host = request.headers.get('host');
31-
if (!host) {
32-
throw error(403, 'Forbidden');
33-
}
34-
35-
const protocol = request.headers.get('x-forwarded-proto') ?? 'https';
36-
const selfOrigin = `${protocol}://${host}`;
37+
const selfOrigin = new URL(request.url).origin;
3738

3839
if (requestOrigin !== selfOrigin) {
3940
throw error(403, 'Forbidden');

0 commit comments

Comments
 (0)