From d871592e9836fdc9631940b21c9545c647b1981b Mon Sep 17 00:00:00 2001 From: KaKa Date: Wed, 13 Oct 2021 02:40:40 +0800 Subject: [PATCH] fix: url handle (#247) --- index.js | 15 ++++++++++++--- test/static.test.js | 7 ++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index ae4365a0..10b04f04 100644 --- a/index.js +++ b/index.js @@ -155,6 +155,8 @@ async function fastifyStatic (fastify, opts) { try { reply.redirect(301, getRedirectUrl(request.raw.url)) } catch (error) { + // the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack + /* istanbul ignore next */ reply.send(error) } } else { @@ -447,16 +449,23 @@ function getEncodingExtension (encoding) { } function getRedirectUrl (url) { - if (url.startsWith('//') || url.startsWith('/\\')) { - // malicous redirect - return '/' + let i = 0 + // we detech how many slash before a valid path + for (i; i < url.length; i++) { + if (url[i] !== '/' && url[i] !== '\\') break } + // turns all leading / or \ into a single / + url = '/' + url.substr(i) try { const parsed = new URL(url, 'http://localhost.com/') return parsed.pathname + (parsed.pathname[parsed.pathname.length - 1] !== '/' ? '/' : '') + (parsed.search || '') } catch (error) { + // the try-catch here is actually unreachable, but we keep it for safety and prevent DoS attack + /* istanbul ignore next */ const err = new Error(`Invalid redirect URL: ${url}`) + /* istanbul ignore next */ err.statusCode = 400 + /* istanbul ignore next */ throw err } } diff --git a/test/static.test.js b/test/static.test.js index fdd59acc..67335eda 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -3288,12 +3288,13 @@ t.test('should not redirect to protocol-relative locations', (t) => { ['//^/..', '/', 301], ['//^/.', null, 404], // it is NOT recognized as a directory by pillarjs/send ['//:/..', '/', 301], - ['/\\\\a//google.com/%2e%2e%2f%2e%2e', '/', 301], - ['//a//youtube.com/%2e%2e%2f%2e%2e', '/', 301], + ['/\\\\a//google.com/%2e%2e%2f%2e%2e', '/a//google.com/%2e%2e%2f%2e%2e/', 301], + ['//a//youtube.com/%2e%2e%2f%2e%2e', '/a//youtube.com/%2e%2e%2f%2e%2e/', 301], ['/^', null, 404], // it is NOT recognized as a directory by pillarjs/send ['//google.com/%2e%2e', '/', 301], ['//users/%2e%2e', '/', 301], - ['//users', null, 404] + ['//users', null, 404], + ['///deep/path//for//test//index.html', null, 200] ] t.plan(1 + urls.length * 2)