Prevents XSS when viewing an uploaded SVG

from the media-info and image-preview components.
This commit is contained in:
Sven Geusens
2024-08-12 15:25:05 +01:00
committed by Nikolaj Geisle
parent 1bc5466a8d
commit 3431f76320
4 changed files with 38 additions and 26 deletions

View File

@@ -136,15 +136,7 @@
editorService.mediaTypeEditor(editor);
};
scope.openSVG = () => {
var popup = window.open('', '_blank');
var html = '<!DOCTYPE html><body><img src="' + scope.nodeUrl + '"/>' +
'<script>history.pushState(null, null,"' + $location.$$absUrl + '");</script></body>';
popup.document.open();
popup.document.write(html);
popup.document.close();
}
scope.openSVG = () => mediaHelper.openSVG(scope.nodeUrl);
// watch for content updates - reload content when node is saved, published etc.
scope.$watch('node.updateDate', function(newValue, oldValue){

View File

@@ -3,7 +3,7 @@
* @name umbraco.services.mediaHelper
* @description A helper object used for dealing with media items
**/
function mediaHelper(umbRequestHelper, $http, $log) {
function mediaHelper(umbRequestHelper, $http, $log, $location) {
//container of fileresolvers
var _mediaFileResolvers = {};
@@ -449,7 +449,29 @@ function mediaHelper(umbRequestHelper, $http, $log) {
cropY2: options.crop ? options.crop.y2 : null
})),
"Failed to retrieve processed image URL for image: " + imagePath);
}
},
/**
* @ngdoc function
* @name umbraco.services.mediaHelper#openSVG
* @methodOf umbraco.services.mediaHelper
* @function
*
* @description
* Opens an SVG file in a new window as an image file, to prevent any potential XSS exploits.
*
* @param {string} imagePath File path, ex /media/1234/my-image.svg
*/
openSVG: function (imagePath) {
var popup = window.open('', '_blank');
var html = '<!DOCTYPE html><body style="background-image: linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(135deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(135deg, transparent 75%, #ccc 75%); background-size:30px 30px; background-position:0 0, 15px 0, 15px -15px, 0px 15px;">'
+ '<img src="' + imagePath + '"/>'
+ '<script>history.pushState(null, null,"' + $location.$$absUrl + '");</script></body>';
popup.document.open();
popup.document.write(html);
popup.document.close();
}
};
} angular.module('umbraco.services').factory('mediaHelper', mediaHelper);

View File

@@ -1,6 +1,6 @@
<div class="umb-image-preview" ng-controller="umbImagePreviewController as controller">
<img class="umb-image-preview--image" ng-if="vm.clientSide" ng-init="previewUrl = controller.getClientSideUrl(vm.clientSideData)" ng-src="{{previewUrl}}" alt="{{vm.name}}" />
<a ng-if="!vm.clientSide" href="#" ng-href="{{vm.source}}" target="_blank" rel="noopener">
<a ng-if="!vm.clientSide" href="" ng-attr-href="{{vm.extension !== 'svg' ? vm.source : undefined}}" ng-click="vm.extension === 'svg' && controller.openSVG(vm.source)" target="_blank" rel="noopener">
<img class="umb-image-preview--image" ng-init="previewUrl = controller.getThumbnail(vm.source)" ng-src="{{previewUrl}}" alt="{{vm.name}}" />
</a>
</div>

View File

@@ -1,18 +1,16 @@
angular.module("umbraco")
.controller("umbImagePreviewController",
function (mediaHelper) {
.controller("umbImagePreviewController",
function (mediaHelper) {
var vm = this;
var vm = this;
vm.getThumbnail = function(source) {
return mediaHelper.getThumbnailFromPath(source) || source;
}
vm.getClientSideUrl = function(sourceData) {
return URL.createObjectURL(sourceData);
}
vm.getThumbnail = function (source) {
return mediaHelper.getThumbnailFromPath(source) || source;
}
});
vm.getClientSideUrl = function (sourceData) {
return URL.createObjectURL(sourceData);
}
vm.openSVG = (source) => mediaHelper.openSVG(source);
});