Skip to content

Commit 7af5268

Browse files
authored
fix: normalize referer before redirect (#1909)
pick from #1908
1 parent 3b16886 commit 7af5268

File tree

2 files changed

+15
-19
lines changed

2 files changed

+15
-19
lines changed

__tests__/response/redirect.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,46 +47,47 @@ describe('ctx.redirect(url)', () => {
4747

4848
describe('with "back"', () => {
4949
it('should redirect to Referrer', () => {
50-
const ctx = context();
50+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
5151
ctx.req.headers.referrer = '/login';
5252
ctx.redirect('back');
5353
assert.strictEqual(ctx.response.header.location, '/login');
5454
});
5555

56-
it('should redirect to Referer', () => {
57-
const ctx = context();
58-
ctx.req.headers.referer = '/login';
59-
ctx.redirect('back');
60-
assert.strictEqual(ctx.response.header.location, '/login');
61-
});
62-
6356
it('should default to alt', () => {
64-
const ctx = context();
57+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
6558
ctx.redirect('back', '/index.html');
6659
assert.strictEqual(ctx.response.header.location, '/index.html');
6760
});
6861

6962
it('should default redirect to /', () => {
70-
const ctx = context();
63+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
7164
ctx.redirect('back');
7265
assert.strictEqual(ctx.response.header.location, '/');
7366
});
7467

7568
it('should redirect to the same origin referrer', () => {
76-
const ctx = context();
77-
ctx.req.headers.host = 'example.com';
69+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
7870
ctx.req.headers.referrer = 'https://example.com/login';
7971
ctx.redirect('back');
8072
assert.strictEqual(ctx.response.header.location, 'https://example.com/login');
8173
});
8274

8375
it('should redirect to root if the same origin referrer is not present', () => {
84-
const ctx = context();
85-
ctx.req.headers.host = 'example.com';
76+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
8677
ctx.req.headers.referrer = 'https://other.com/login';
8778
ctx.redirect('back');
8879
assert.strictEqual(ctx.response.header.location, '/');
8980
});
81+
82+
it('should fix Trailing Double-Slash security issue', () => {
83+
const ctx = context({ url: '/', headers: { host: 'example.com' } });
84+
ctx.req.headers.referrer = '//evil.com/login/';
85+
ctx.redirect('back');
86+
assert.equal(ctx.response.header.location, '/');
87+
88+
ctx.redirect('back', '/home');
89+
assert.equal(ctx.response.header.location, '/home');
90+
});
9091
});
9192

9293
describe('when html is accepted', () => {

lib/response.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,6 @@ module.exports = {
243243
_getBackReferrer() {
244244
const referrer = this.ctx.get('Referrer');
245245
if (referrer) {
246-
// referrer is a relative path
247-
if (referrer.startsWith('/')) {
248-
return referrer;
249-
}
250-
251246
// referrer is an absolute URL, check if it's the same origin
252247
const url = new URL(referrer, this.ctx.href);
253248
if (url.host === this.ctx.host) {

0 commit comments

Comments
 (0)