forked from MTSR/mapserver
add some XSS security
This commit is contained in:
parent
8c7ccc0035
commit
e15571f1b9
@ -1,3 +1,8 @@
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
@ -7,6 +12,10 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -1,6 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html style="height: 100%">
|
||||
<html >
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data:; connect-src 'self'; style-src 'self'; script-src 'self';report-uri /csp-reports">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="theme-color" content="#000">
|
||||
@ -17,7 +18,7 @@
|
||||
<body>
|
||||
<div id="app">
|
||||
<br>
|
||||
<h5 style="text-align: center;">Starting mapserver...</h5>
|
||||
<h5 id="title">Starting mapserver...</h5>
|
||||
</div>
|
||||
|
||||
<!-- libraries -->
|
||||
|
111
static/js/lib/HtmlSanitizer.js
Normal file
111
static/js/lib/HtmlSanitizer.js
Normal file
@ -0,0 +1,111 @@
|
||||
//JavaScript HTML Sanitizer, (c) Alexander Yumashev, Jitbit Software.
|
||||
|
||||
//homepage https://github.com/jitbit/HtmlSanitizer
|
||||
|
||||
//License: MIT https://github.com/jitbit/HtmlSanitizer/blob/master/LICENSE
|
||||
|
||||
console.log('Sanitizer loading');
|
||||
|
||||
export var HtmlSanitizer = new (function () {
|
||||
|
||||
var tagWhitelist_ = {
|
||||
'A': true, 'ABBR': true, 'B': true, 'BLOCKQUOTE': true, 'BODY': true, 'BR': true, 'CENTER': true, 'CODE': true, 'DIV': true, 'EM': true, 'FONT': true,
|
||||
'H1': true, 'H2': true, 'H3': true, 'H4': true, 'H5': true, 'H6': true, 'HR': true, 'I': true, 'IMG': true, 'LABEL': true, 'LI': true, 'OL': true, 'P': true, 'PRE': true,
|
||||
'SMALL': true, 'SOURCE': true, 'SPAN': true, 'STRONG': true, 'TABLE': true, 'TBODY': true, 'TR': true, 'TD': true, 'TH': true, 'THEAD': true, 'UL': true, 'U': true, 'VIDEO': true
|
||||
};
|
||||
|
||||
var contentTagWhiteList_ = { 'FORM': true }; //tags that will be converted to DIVs
|
||||
|
||||
var attributeWhitelist_ = { 'align': true, 'color': true, 'controls': true, 'height': true, 'href': true, 'src': true, 'style': true, 'target': true, 'title': true, 'type': true, 'width': true };
|
||||
|
||||
var cssWhitelist_ = { 'color': true, 'background-color': true, 'font-size': true, 'text-align': true, 'text-decoration': true, 'font-weight': true };
|
||||
|
||||
var schemaWhiteList_ = [ 'http:', 'https:', 'data:', 'm-files:', 'file:', 'ftp:' ]; //which "protocols" are allowed in "href", "src" etc
|
||||
|
||||
var uriAttributes_ = { 'href': true, 'action': true };
|
||||
|
||||
this.SanitizeHtml = function(input) {
|
||||
input = input.trim();
|
||||
if (input == "") return ""; //to save performance and not create iframe
|
||||
|
||||
//firefox "bogus node" workaround
|
||||
if (input == "<br>") return "";
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
if (iframe['sandbox'] === undefined) {
|
||||
alert('Your browser does not support sandboxed iframes. Please upgrade to a modern browser.');
|
||||
return '';
|
||||
}
|
||||
iframe['sandbox'] = 'allow-same-origin';
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe); // necessary so the iframe contains a document
|
||||
var iframedoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
if (iframedoc.body == null) iframedoc.write("<body></body>"); // null in IE
|
||||
iframedoc.body.innerHTML = input;
|
||||
|
||||
function makeSanitizedCopy(node) {
|
||||
if (node.nodeType == Node.TEXT_NODE) {
|
||||
var newNode = node.cloneNode(true);
|
||||
} else if (node.nodeType == Node.ELEMENT_NODE && (tagWhitelist_[node.tagName] || contentTagWhiteList_[node.tagName])) {
|
||||
|
||||
//remove useless empty spans (lots of those when pasting from MS Outlook)
|
||||
if ((node.tagName == "SPAN" || node.tagName == "B" || node.tagName == "I" || node.tagName == "U")
|
||||
&& node.innerHTML.trim() == "") {
|
||||
return document.createDocumentFragment();
|
||||
}
|
||||
|
||||
if (contentTagWhiteList_[node.tagName])
|
||||
newNode = iframedoc.createElement('DIV'); //convert to DIV
|
||||
else
|
||||
newNode = iframedoc.createElement(node.tagName);
|
||||
|
||||
for (var i = 0; i < node.attributes.length; i++) {
|
||||
var attr = node.attributes[i];
|
||||
if (attributeWhitelist_[attr.name]) {
|
||||
if (attr.name == "style") {
|
||||
for (s = 0; s < node.style.length; s++) {
|
||||
var styleName = node.style[s];
|
||||
if (cssWhitelist_[styleName])
|
||||
newNode.style.setProperty(styleName, node.style.getPropertyValue(styleName));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (uriAttributes_[attr.name]) { //if this is a "uri" attribute, that can have "javascript:" or something
|
||||
if (attr.value.indexOf(":") > -1 && !startsWithAny(attr.value, schemaWhiteList_))
|
||||
continue;
|
||||
}
|
||||
newNode.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < node.childNodes.length; i++) {
|
||||
var subCopy = makeSanitizedCopy(node.childNodes[i]);
|
||||
newNode.appendChild(subCopy, false);
|
||||
}
|
||||
} else {
|
||||
newNode = document.createDocumentFragment();
|
||||
}
|
||||
return newNode;
|
||||
};
|
||||
|
||||
var resultElement = makeSanitizedCopy(iframedoc.body);
|
||||
document.body.removeChild(iframe);
|
||||
return resultElement.innerHTML
|
||||
.replace(/<br[^>]*>(\S)/g, "<br>\n$1")
|
||||
.replace(/div><div/g, "div>\n<div"); //replace is just for cleaner code
|
||||
}
|
||||
|
||||
function startsWithAny(str, substrings) {
|
||||
for (var i = 0; i < substrings.length; i++) {
|
||||
if (str.indexOf(substrings[i]) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.AllowedTags = tagWhitelist_;
|
||||
this.AllowedAttributes = attributeWhitelist_;
|
||||
this.AllowedCssStyles = cssWhitelist_;
|
||||
this.AllowedSchemas = schemaWhiteList_;
|
||||
});
|
@ -1,4 +1,6 @@
|
||||
import AbstractIconOverlay from './AbstractIconOverlay.js';
|
||||
import {HtmlSanitizer} from '../../lib/HtmlSanitizer.js';
|
||||
|
||||
|
||||
export default AbstractIconOverlay.extend({
|
||||
initialize: function() {
|
||||
@ -18,16 +20,19 @@ export default AbstractIconOverlay.extend({
|
||||
},
|
||||
|
||||
createPopup: function(poi){
|
||||
|
||||
if (poi.attributes.url)
|
||||
{
|
||||
return "<a href=\"" + poi.attributes.url + "\">" +
|
||||
"<h4>" + poi.attributes.name + "</h4></a><hr>" +
|
||||
"<b>Owner: </b> " + poi.attributes.owner + "<br>";
|
||||
return "<a href=\"" + HtmlSanitizer.SanitizeHtml(poi.attributes.url) + "\">" +
|
||||
"<h4>" + HtmlSanitizer.SanitizeHtml(poi.attributes.name) + "</h4></a><hr>" +
|
||||
"<b>Owner: </b> " + HtmlSanitizer.SanitizeHtml(poi.attributes.owner) + "<br>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "<h4>" + poi.attributes.name + "</h4><hr>" +
|
||||
"<b>Owner: </b> " + poi.attributes.owner + "<br>";
|
||||
return "<h4>" + HtmlSanitizer.SanitizeHtml(poi.attributes.name) + "</h4><hr>" +
|
||||
"<b>Owner: </b> " + HtmlSanitizer.SanitizeHtml(poi.attributes.owner) + "<br>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user