- Security fix/Breaking change (Imagelib): Require allowedImageLibOrigins

config array be set with safe origins or otherwise reject `postMessage`
  messages in case from untrusted sources
- Security fix/Breaking change (xdomain): Namespace xdomain file to avoid
  it being used to modify non-xdomain storage
- Security fix (Imagelib): Expose `dropXMLInternalSubset` to extensions
  for preventing billion laughs attack (and use in Imagelib)
This commit is contained in:
Brett Zamir
2018-09-24 20:59:47 +08:00
parent 25ed8ad465
commit 11baad0402
10 changed files with 55 additions and 25 deletions

View File

@@ -32,7 +32,7 @@ export default {
// Must match the icon ID in helloworld-icon.xml
id: 'hello_world',
// Fallback, e.g., for `file://` access
// Fallback, e.g., for `file:///` access
icon: svgEditor.curConfig.extIconsPath + 'helloworld.png',
// This indicates that the button will be added to the "mode"

View File

@@ -9,12 +9,12 @@
*/
export default {
name: 'imagelib',
async init ({decode64, importLocale}) {
async init ({decode64, importLocale, dropXMLInteralSubset}) {
const imagelibStrings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const {uiStrings, canvas: svgCanvas} = svgEditor;
const {uiStrings, canvas: svgCanvas, curConfig: {allowedImageLibOrigins}} = svgEditor;
function closeBrowser () {
$('#imgbrowse_holder').hide();
@@ -44,10 +44,8 @@ export default {
let transferStopped = false;
let preview, submit;
window.addEventListener('message', function (evt) {
// Receive `postMessage` data
let response = evt.data;
// Receive `postMessage` data
window.addEventListener('message', function ({origin, data: response}) {
if (!response || typeof response !== 'string') {
// Do nothing
return;
@@ -60,6 +58,10 @@ export default {
if (response.namespace !== 'imagelib') {
return;
}
if (!allowedImageLibOrigins.includes('*') && !allowedImageLibOrigins.includes(origin)) {
console.log(`Origin ${origin} not whitelisted for posting to ${window.origin}`);
return;
}
} catch (e) {
return;
}
@@ -90,7 +92,8 @@ export default {
transferStopped = false;
curMeta = response;
pending[curMeta.id] = curMeta;
// Should be safe to add dynamic property as passed metadata
pending[curMeta.id] = curMeta; // lgtm [js/remote-property-injection]
const name = (curMeta.name || 'file');
@@ -170,7 +173,8 @@ export default {
title = curMeta.name;
} else {
// Try to find a title
const xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
// `dropXMLInteralSubset` is to help prevent the billion laughs attack
const xml = new DOMParser().parseFromString(dropXMLInteralSubset(response), 'text/xml').documentElement; // lgtm [js/xml-bomb]
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
}
if (curMeta) {

View File

@@ -19,7 +19,7 @@ export default {
return;
}
// The default is not to allow any origins, including even the same domain or
// if run on a file:// URL See svgedit-config-es.js for an example of how
// if run on a `file:///` URL. See `svgedit-config-es.js` for an example of how
// to configure
const {allowedOrigins} = svgEditor.curConfig;
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {

View File

@@ -31,7 +31,7 @@ $('a').click(function () {
try {
data = canvas.toDataURL();
} catch (err) {
// This fails in Firefox with file:// URLs :(
// This fails in Firefox with `file:///` URLs :(
alert('Data URL conversion failed: ' + err);
data = '';
}