Customize: Harden url matching to account for varying ports and ensuring matching base pathname for allowed urls

Fixes #38409.


git-svn-id: https://develop.svn.wordpress.org/trunk@38890 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Weston Ruter 2016-10-24 20:06:06 +00:00
parent b5bc4fde53
commit a89aef0f6e
3 changed files with 34 additions and 35 deletions

View File

@ -4040,7 +4040,7 @@
// ssl certs.
previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) {
var result, urlParser, newPreviewUrl, schemeMatchingPreviewUrl, queryParams;
var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = [];
urlParser = document.createElement( 'a' );
urlParser.href = to;
@ -4062,31 +4062,30 @@
}
}
newPreviewUrl = urlParser.href;
urlParser.protocol = previewer.scheme.get() + ':';
schemeMatchingPreviewUrl = urlParser.href;
parsedCandidateUrls.push( urlParser );
// Prepend list with URL that matches the scheme/protocol of the iframe.
if ( previewer.scheme.get() + ':' !== urlParser.protocol ) {
urlParser = document.createElement( 'a' );
urlParser.href = parsedCandidateUrls[0].href;
urlParser.protocol = previewer.scheme.get() + ':';
parsedCandidateUrls.unshift( urlParser );
}
// Attempt to match the URL to the control frame's scheme
// and check if it's allowed. If not, try the original URL.
$.each( [ schemeMatchingPreviewUrl, newPreviewUrl ], function( i, url ) {
$.each( previewer.allowedUrls, function( i, allowed ) {
var path;
allowed = allowed.replace( /\/+$/, '' );
path = url.replace( allowed, '' );
if ( 0 === url.indexOf( allowed ) && /^([/#?]|$)/.test( path ) ) {
result = url;
return false;
parsedAllowedUrl = document.createElement( 'a' );
_.find( parsedCandidateUrls, function( parsedCandidateUrl ) {
return ! _.isUndefined( _.find( previewer.allowedUrls, function( allowedUrl ) {
parsedAllowedUrl.href = allowedUrl;
if ( urlParser.protocol === parsedAllowedUrl.protocol && urlParser.host === parsedAllowedUrl.host && 0 === parsedAllowedUrl.pathname.indexOf( urlParser.pathname ) ) {
result = parsedCandidateUrl.href;
return true;
}
});
if ( result ) {
return false;
}
});
} ) );
} );
// If we found a matching result, return it. If not, bail.
return result ? result : null;
return result;
});
previewer.bind( 'ready', previewer.ready );

View File

@ -654,7 +654,8 @@ window.wp = window.wp || {};
this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
var urlParser = document.createElement( 'a' );
urlParser.href = to;
return urlParser.protocol + '//' + urlParser.hostname;
// Port stripping needed by IE since it adds to host but not to event.origin.
return urlParser.protocol + '//' + urlParser.host.replace( /:80$/, '' );
});
// first add with no value

View File

@ -275,13 +275,13 @@
* @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
* @param {string} element.search Query string.
* @param {string} element.pathname Path.
* @param {string} element.hostname Hostname.
* @param {string} element.host Host.
* @param {object} [options]
* @param {object} [options.allowAdminAjax=false] Allow admin-ajax.php requests.
* @returns {boolean} Is appropriate for changeset link.
*/
api.isLinkPreviewable = function isLinkPreviewable( element, options ) {
var hasMatchingHost, urlParser, args;
var matchesAllowedUrl, parsedAllowedUrl, args;
args = _.extend( {}, { allowAdminAjax: false }, options || {} );
@ -294,15 +294,12 @@
return false;
}
urlParser = document.createElement( 'a' );
hasMatchingHost = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) {
urlParser.href = allowedUrl;
if ( urlParser.hostname === element.hostname && urlParser.protocol === element.protocol ) {
return true;
}
return false;
parsedAllowedUrl = document.createElement( 'a' );
matchesAllowedUrl = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) {
parsedAllowedUrl.href = allowedUrl;
return parsedAllowedUrl.protocol === element.protocol && parsedAllowedUrl.host === element.host && 0 === element.pathname.indexOf( parsedAllowedUrl.pathname );
} ) );
if ( ! hasMatchingHost ) {
if ( ! matchesAllowedUrl ) {
return false;
}
@ -331,7 +328,9 @@
* @access protected
*
* @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
* @param {object} element.search Query string.
* @param {string} element.search Query string.
* @param {string} element.host Host.
* @param {string} element.protocol Protocol.
* @returns {void}
*/
api.prepareLinkPreview = function prepareLinkPreview( element ) {
@ -348,7 +347,7 @@
}
// Make sure links in preview use HTTPS if parent frame uses HTTPS.
if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.hostname ) ) {
if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.host ) ) {
element.protocol = 'https:';
}
@ -496,7 +495,7 @@
urlParser.href = form.action;
// Make sure forms in preview use HTTPS if parent frame uses HTTPS.
if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.hostname ) ) {
if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.host ) ) {
urlParser.protocol = 'https:';
form.action = urlParser.href;
}