mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-01 02:41:39 -05:00
Remove open redirect by removing double slashes from redirects (#7247)
no issue Double slashes are treated as a HTTP calls as specified in [RFC1801](http://www.ietf.org/rfc/rfc1808.txt). Because of this behaviour the uncapitalise created an open redirect. By removing double slashes in the path we ensure open redirects cannot be created. As an example, please click the following URL: https://dev.ghost.org///Google.com/. This issue has been reported by pentesters of our product [LearningSpaces.io](http://learningspaces.io).
This commit is contained in:
parent
6a1c10516e
commit
f546a5ce1d
4 changed files with 50 additions and 5 deletions
|
@ -13,7 +13,8 @@ uncapitalise = function uncapitalise(req, res, next) {
|
|||
/*jslint unparam:true*/
|
||||
var pathToTest = req.path,
|
||||
isSignupOrReset = req.path.match(/(\/ghost\/(signup|reset)\/)/i),
|
||||
isAPI = req.path.match(/(\/ghost\/api\/v[\d\.]+\/.*?\/)/i);
|
||||
isAPI = req.path.match(/(\/ghost\/api\/v[\d\.]+\/.*?\/)/i),
|
||||
redirectPath;
|
||||
|
||||
if (isSignupOrReset) {
|
||||
pathToTest = isSignupOrReset[1];
|
||||
|
@ -29,9 +30,14 @@ uncapitalise = function uncapitalise(req, res, next) {
|
|||
* That encoding isn't useful here, as it triggers an extra uncapitalise redirect, so we decode the path first
|
||||
*/
|
||||
if (/[A-Z]/.test(decodeURIComponent(pathToTest))) {
|
||||
res.set('Cache-Control', 'public, max-age=' + utils.ONE_YEAR_S);
|
||||
// Adding baseUrl ensures subdirectories are kept
|
||||
res.redirect(301, (req.baseUrl ? req.baseUrl : '') + req.url.replace(pathToTest, pathToTest.toLowerCase()));
|
||||
redirectPath = (
|
||||
(req.baseUrl ? req.baseUrl : '') +
|
||||
utils.removeOpenRedirectFromUrl(req.url.replace(pathToTest, pathToTest.toLowerCase()))
|
||||
);
|
||||
|
||||
res.set('Cache-Control', 'public, max-age=' + utils.ONE_YEAR_S);
|
||||
res.redirect(301, redirectPath);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
var unidecode = require('unidecode'),
|
||||
_ = require('lodash'),
|
||||
readCSV = require('./read-csv'),
|
||||
|
||||
removeOpenRedirectFromUrl = require('./remove-open-redirect-from-url'),
|
||||
utils,
|
||||
getRandomInt;
|
||||
|
||||
|
@ -102,7 +102,8 @@ utils = {
|
|||
res.redirect(301, path);
|
||||
},
|
||||
|
||||
readCSV: readCSV
|
||||
readCSV: readCSV,
|
||||
removeOpenRedirectFromUrl: removeOpenRedirectFromUrl
|
||||
};
|
||||
|
||||
module.exports = utils;
|
||||
|
|
30
core/server/utils/remove-open-redirect-from-url.js
Normal file
30
core/server/utils/remove-open-redirect-from-url.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
var url = require('url');
|
||||
|
||||
function removeDoubleCharacters(character, string) {
|
||||
var stringArray = string.split('');
|
||||
|
||||
return stringArray.reduce(function (newString, currentCharacter, index) {
|
||||
if (
|
||||
currentCharacter === character &&
|
||||
stringArray[index + 1] === character
|
||||
) {
|
||||
return newString;
|
||||
}
|
||||
|
||||
return newString + currentCharacter;
|
||||
}, '');
|
||||
}
|
||||
|
||||
function removeOpenRedirectFromUrl(urlString) {
|
||||
var parsedUrl = url.parse(urlString);
|
||||
|
||||
return (
|
||||
(parsedUrl.protocol ? parsedUrl.protocol + '//' : '') + // http://
|
||||
(parsedUrl.auth || '') +
|
||||
(parsedUrl.host || '') +
|
||||
removeDoubleCharacters('/', parsedUrl.path) +
|
||||
(parsedUrl.hash || '')
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = removeOpenRedirectFromUrl;
|
|
@ -113,6 +113,14 @@ describe('Frontend Routing', function () {
|
|||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should sanitize double slashes when redirecting uppercase', function (done) {
|
||||
request.get('///Google.com/')
|
||||
.expect('Location', '/google.com/')
|
||||
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should respond with html for valid url', function (done) {
|
||||
request.get('/welcome-to-ghost/')
|
||||
.expect('Content-Type', /html/)
|
||||
|
|
Loading…
Add table
Reference in a new issue