@cryptotaxi247 / netdata-1 / commits / 98f13d851

send pipes URL encoded (#4358)

* send pipes URL encoded; fixes #3819 * use encodeURIComponent() for user supplied parameters * fix LGTM detected XSS * escape also parenthesis on URLs * escape also parenthesis on URLs no2

Costa Tsaousis committed Oct 5, 2018 at 12:26 UTC 98f13d85150227cfc83648bfab1dd64b9a0217f6
3 files changed +65 -34
web/dashboard.js
+22 -11
@@ -75,6 +75,14 @@
75 var NETDATA = window.NETDATA || {};
76
77 (function(window, document, $, undefined) {
78 +
79 + NETDATA.encodeURIComponent = function(s) {
80 + if(typeof(s) === 'string')
81 + return encodeURIComponent(s);
82 +
83 + return s;
84 + };
85 +
86 // ------------------------------------------------------------------------
87 // compatibility fixes
88
@@ -2927,7 +2935,7 @@ var NETDATA = window.NETDATA || {};
2935 that.force_update_every *= 1000;
2936
2937 // the dimensions requested by the user
2930 - that.dimensions = NETDATA.dataAttribute(that.element, 'dimensions', null);
2938 + that.dimensions = NETDATA.encodeURIComponent(NETDATA.dataAttribute(that.element, 'dimensions', null));
2939
2940 that.title = NETDATA.dataAttribute(that.element, 'title', null); // the title of the chart
2941 that.units = NETDATA.dataAttribute(that.element, 'units', null); // the units of the chart dimensions
@@ -2935,8 +2943,11 @@ var NETDATA = window.NETDATA || {};
2943 that.units_current = that.units;
2944 that.units_common = NETDATA.dataAttribute(that.element, 'common-units', null);
2945
2938 - that.append_options = NETDATA.dataAttribute(that.element, 'append-options', null); // additional options to pass to netdata
2939 - that.override_options = NETDATA.dataAttribute(that.element, 'override-options', null); // override options to pass to netdata
2946 + // additional options to pass to netdata
2947 + that.append_options = NETDATA.encodeURIComponent(NETDATA.dataAttribute(that.element, 'append-options', null));
2948 +
2949 + // override options to pass to netdata
2950 + that.override_options = NETDATA.encodeURIComponent(NETDATA.dataAttribute(that.element, 'override-options', null));
2951
2952 that.debug = NETDATA.dataAttributeBoolean(that.element, 'debug', false);
2953
@@ -4686,12 +4697,12 @@ var NETDATA = window.NETDATA || {};
4697 ret = this.library.options(this);
4698
4699 if(this.append_options !== null)
4689 - ret += '|' + this.append_options.toString();
4700 + ret += '%7C' + this.append_options.toString();
4701
4691 - ret += '|jsonwrap';
4702 + ret += '%7C' + 'jsonwrap';
4703
4704 if(NETDATA.options.current.eliminate_zero_dimensions === true)
4694 - ret += '|nonzero';
4705 + ret += '%7C' + 'nonzero';
4706
4707 return ret;
4708 };
@@ -8468,7 +8479,7 @@ var NETDATA = window.NETDATA || {};
8479 enabled: true,
8480 xssRegexIgnore: new RegExp('^/api/v1/data\.result.data$'),
8481 format: function(state) { void(state); return 'json'; },
8471 - options: function(state) { return 'ms|flip' + (this.isLogScale(state)?'|abs':'').toString(); },
8482 + options: function(state) { return 'ms' + '%7C' + 'flip' + (this.isLogScale(state)?('%7C' + 'abs'):'').toString(); },
8483 legend: function(state) {
8484 return (this.isSparkline(state) === false && NETDATA.dataAttributeBoolean(state.element, 'legend', true) === true) ? 'right-side' : null;
8485 },
@@ -8513,7 +8524,7 @@ var NETDATA = window.NETDATA || {};
8524 enabled: true,
8525 xssRegexIgnore: new RegExp('^/api/v1/data\.result$'),
8526 format: function(state) { void(state); return 'array'; },
8516 - options: function(state) { void(state); return 'flip|abs'; },
8527 + options: function(state) { void(state); return 'flip' + '%7C' + 'abs'; },
8528 legend: function(state) { void(state); return null; },
8529 autoresize: function(state) { void(state); return false; },
8530 max_updates_to_recreate: function(state) { void(state); return 5000; },
@@ -8533,7 +8544,7 @@ var NETDATA = window.NETDATA || {};
8544 enabled: true,
8545 xssRegexIgnore: new RegExp('^/api/v1/data\.result$'),
8546 format: function(state) { void(state); return 'ssvcomma'; },
8536 - options: function(state) { void(state); return 'null2zero|flip|abs'; },
8547 + options: function(state) { void(state); return 'null2zero' + '%7C' + 'flip' + '%7C' + 'abs'; },
8548 legend: function(state) { void(state); return null; },
8549 autoresize: function(state) { void(state); return false; },
8550 max_updates_to_recreate: function(state) { void(state); return 5000; },
@@ -8553,7 +8564,7 @@ var NETDATA = window.NETDATA || {};
8564 enabled: true,
8565 xssRegexIgnore: new RegExp('^/api/v1/data\.result.data$'),
8566 format: function(state) { void(state); return 'json'; },
8556 - options: function(state) { void(state); return 'objectrows|ms'; },
8567 + options: function(state) { void(state); return 'objectrows' + '%7C' + 'ms'; },
8568 legend: function(state) { void(state); return null; },
8569 autoresize: function(state) { void(state); return false; },
8570 max_updates_to_recreate: function(state) { void(state); return 50; },
@@ -8633,7 +8644,7 @@ var NETDATA = window.NETDATA || {};
8644 enabled: true,
8645 xssRegexIgnore: new RegExp('^/api/v1/data\.result.data$'),
8646 format: function(state) { void(state); return 'json'; },
8636 - options: function(state) { void(state); return 'objectrows|ms'; },
8647 + options: function(state) { void(state); return 'objectrows' + '%7C' + 'ms'; },
8648 legend: function(state) { void(state); return null; },
8649 autoresize: function(state) { void(state); return false; },
8650 max_updates_to_recreate: function(state) { void(state); return 5000; },
web/goto-host-from-alarm.html
+24 -10
@@ -34,12 +34,26 @@ function escapeUserInputHTML(s) {
34 .replace(/\)/g,')')
35 .replace(/\//g,'/');
36 }
37 -function escapeUserInputJS(s) {
38 - return s.toString()
39 - .replace(/"/g, '"')
40 - .replace(/'/g, ''')
41 - .replace(/\(/g,'(')
42 - .replace(/\)/g,')');
37 +
38 +// if string.startsWith is not defined, define it
39 +if(typeof String.prototype.startsWith !== 'function') {
40 + String.prototype.startsWith = function(s) {
41 + if(s.length > this.length) return false;
42 + return this.slice(s.length) === s;
43 + };
44 +}
45 +
46 +function verifyURL(s) {
47 + if(typeof(s) === 'string' && (s.startsWith('http://') || s.startsWith('https://')))
48 + return s
49 + .replace(/'/g, '%22')
50 + .replace(/"/g, '%27')
51 + .replace(/\)/g, '%28')
52 + .replace(/\(/g, '%29');
53 +
54 + console.log('invalid URL detected:');
55 + console.log(s);
56 + return 'javascript:alert("invalid url");';
57 }
58
59 var urlOptions = {
@@ -107,7 +121,7 @@ function gotoServerValidateUrl(id, guid, url) {
121 var finalURL = netdataURL(url);
122
123 setTimeout(function() {
110 - document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + escapeUserInputJS(finalURL) + '" target="_blank">' + escapeUserInputHTML(url) + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
124 + document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + verifyURL(finalURL) + '" target="_blank">' + escapeUserInputHTML(url) + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
125
126 NETDATA.registry.hello(url, function(data) {
127 if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid === guid) {
@@ -120,11 +134,11 @@ function gotoServerValidateUrl(id, guid, url) {
134 if(gotoServerMiddleClick) {
135 window.open(finalURL);
136 gotoServerMiddleClick = false;
123 - document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + escapeUserInputJS(finalURL) + '">' + escapeUserInputHTML(url) + '</a></b><br/>(check your pop-up blocker if it fails)';
137 + document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + verifyURL(finalURL) + '">' + escapeUserInputHTML(url) + '</a></b><br/>(check your pop-up blocker if it fails)';
138 }
139 else {
140 document.getElementById('gotoServerResponse').innerHTML += 'found it! It is at:<br/><small>' + escapeUserInputHTML(url) + '</small>';
127 - document.location = escapeUserInputJS(finalURL);
141 + document.location = verifyURL(finalURL);
142 }
143 }
144 }
@@ -140,7 +154,7 @@ function gotoServerValidateUrl(id, guid, url) {
154
155 if(thisIsHttps === true && urlsInHttp > 0) {
156 document.getElementById('gotoServerResponse').innerHTML += '<br/>redirecting myself to HTTP to allow checking';
143 - document.location = escapeUserInputJS(document.location.toString().replace('https://', 'http://'));
157 + document.location = verifyURL(document.location.toString().replace('https://', 'http://'));
158 }
159 }
160 }
web/index.html
+19 -13
@@ -592,12 +592,18 @@
592 .replace(/\)/g,'&#41;')
593 .replace(/\//g,'&#47;');
594 }
595 - function escapeUserInputJS(s) {
596 - return s.toString()
597 - .replace(/"/g, '&quot;')
598 - .replace(/'/g, '&#39;')
599 - .replace(/\(/g,'&#40;')
600 - .replace(/\)/g,'&#41;');
595 +
596 + function verifyURL(s) {
597 + if(typeof(s) === 'string' && (s.startsWith('http://') || s.startsWith('https://')))
598 + return s
599 + .replace(/'/g, '%22')
600 + .replace(/"/g, '%27')
601 + .replace(/\)/g, '%28')
602 + .replace(/\(/g, '%29');
603 +
604 + console.log('invalid URL detected:');
605 + console.log(s);
606 + return 'javascript:alert("invalid url");';
607 }
608
609 // --------------------------------------------------------------------
@@ -1142,7 +1148,7 @@
1148 }
1149
1150 function netdataReload(url) {
1145 - document.location = netdataURL(url, true);
1151 + document.location = verifyURL(netdataURL(url, true));
1152
1153 // since we play with hash
1154 // this is needed to reload the page
@@ -1150,7 +1156,7 @@
1156 }
1157
1158 function gotoHostedModalHandler(url) {
1153 - document.location = url + urlOptions.genHash();
1159 + document.location = verifyURL(url + urlOptions.genHash());
1160 return false;
1161 }
1162
@@ -1172,7 +1178,7 @@
1178 var finalURL = netdataURL(url);
1179
1180 setTimeout(function() {
1175 - document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + escapeUserInputJS(finalURL) + '" target="_blank">' + escapeUserInputHTML(url) + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
1181 + document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + verifyURL(finalURL) + '" target="_blank">' + escapeUserInputHTML(url) + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
1182
1183 NETDATA.registry.hello(url, function(data) {
1184 if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid === guid) {
@@ -1183,13 +1189,13 @@
1189 gotoServerStop = true;
1190
1191 if(gotoServerMiddleClick) {
1186 - window.open(finalURL, '_blank');
1192 + window.open(verifyURL(finalURL), '_blank');
1193 gotoServerMiddleClick = false;
1188 - document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + escapeUserInputJS(finalURL) + '">' + escapeUserInputHTML(url) + '</a></b><br/>(check your pop-up blocker if it fails)';
1194 + document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + verifyURL(finalURL) + '">' + escapeUserInputHTML(url) + '</a></b><br/>(check your pop-up blocker if it fails)';
1195 }
1196 else {
1197 document.getElementById('gotoServerResponse').innerHTML += 'found it! It is at:<br/><small>' + escapeUserInputHTML(url) + '</small>';
1192 - document.location = finalURL;
1198 + document.location = verifyURL(finalURL);
1199 }
1200 }
1201 }
@@ -5780,6 +5786,6 @@
5786 </div>
5787 </div>
5788 <div id="hiddenDownloadLinks" style="display: none;" hidden></div>
5783 - <script type="text/javascript" src="dashboard.js?v20180922-1"></script>
5789 + <script type="text/javascript" src="dashboard.js?v20181005-5"></script>
5790 </body>
5791 </html>