From d56d9eb505880bdd66e36c87a7a147abd3b310b6 Mon Sep 17 00:00:00 2001 From: patrykb0802 Date: Wed, 14 Aug 2024 16:29:54 +0200 Subject: [PATCH 01/17] #2983 Prevent XSS for URLs feature/#2983_Prevent_XSS_for_URLs --- WebContent/WEB-INF/jsp/pointHierarchySLTS.jsp | 20 +++++------ WebContent/WEB-INF/spring-security.xml | 19 +++++++++-- src/org/scada_lts/web/security/XSSFilter.java | 34 +++++++++++++++++++ src/org/scada_lts/web/security/XSSUtils.java | 20 +++++++++++ 4 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 src/org/scada_lts/web/security/XSSFilter.java create mode 100644 src/org/scada_lts/web/security/XSSUtils.java diff --git a/WebContent/WEB-INF/jsp/pointHierarchySLTS.jsp b/WebContent/WEB-INF/jsp/pointHierarchySLTS.jsp index 5070db6808..626b293769 100644 --- a/WebContent/WEB-INF/jsp/pointHierarchySLTS.jsp +++ b/WebContent/WEB-INF/jsp/pointHierarchySLTS.jsp @@ -601,7 +601,7 @@ var messages = { $.ajax({ type: "GET", dataType: "json", - url:myLocation+"/pointHierarchy/paths/"+key+"/"+folder, + url:myLocation+"pointHierarchy/paths/"+key+"/"+folder, success: function(msg){ var path="/"; if (msg.length>0) { @@ -753,7 +753,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+'/pointHierarchy/move/'+toMove.key+'/'+toMove.oldParentId+'/'+toMove.newParentId+'/'+nodeDragAndDrop.isFolder(), + url:myLocation+'pointHierarchy/move/'+toMove.key+'/'+toMove.oldParentId+'/'+toMove.newParentId+'/'+nodeDragAndDrop.isFolder(), success: function(msg){ $button.hide(); $button.stopSpin(); @@ -786,7 +786,7 @@ var messages = { glyph: glyph_opts, selectMode: 2, source: { - url: myLocation+"/pointHierarchy/0", + url: myLocation+"pointHierarchy/0", debugDelay: 0, cache: false}, toggleEffect: { effect: "drop", options: {direction: "left"}, duration: 100 }, @@ -802,7 +802,7 @@ var messages = { }, lazyLoad: function(event, data) { data.result = { - url: myLocation+"/pointHierarchy/"+data.node.key, + url: myLocation+"pointHierarchy/"+data.node.key, cache: false, debugDelay: 0 }; @@ -832,7 +832,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+"/pointHierarchy/new/0/"+dialog.getModalBody().find('input').val(), + url:myLocation+"pointHierarchy/new/0/"+dialog.getModalBody().find('input').val(), success: function(msg){ var titleNewNode = dialog.getModalBody().find('input').val(); dialog.getModalBody().html('

'+messages.folder+':

'); @@ -899,7 +899,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+"/pointHierarchy/del/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+nodeActivate.isFolder(), + url:myLocation+"pointHierarchy/del/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+nodeActivate.isFolder(), success: function(msg){ dialog.getModalBody().html('

'+messages.folderRemoved+':

'); $button.hide(); @@ -949,7 +949,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+"/pointHierarchy/del/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+nodeActivate.isFolder(), + url:myLocation+"pointHierarchy/del/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+nodeActivate.isFolder(), success: function(msg){ dialog.getModalBody().html('

'+messages.movedElement+':

'); $button.hide(); @@ -1032,7 +1032,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+"/pointHierarchy/edit/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+newTitle, + url:myLocation+"pointHierarchy/edit/"+getParentId(nodeActivate)+"/"+nodeActivate.key+"/"+newTitle, success: function(msg){ var titleNewNode = dialog.getModalBody().find('input').val(); dialog.getModalBody().html('

'+messages.folderChange+':

'); @@ -1140,7 +1140,7 @@ var messages = { $.ajax({ type: "POST", dataType: "json", - url:myLocation+"/viewutil/"+locale, + url:myLocation+"viewutil/"+locale, success: function(msg){ location.reload(); }, @@ -1227,7 +1227,7 @@ var messages = { $.ajax({ type: "GET", dataType: "json", - url:myLocation+"/pointHierarchy/find/"+queryGlobal+"/"+page, + url:myLocation+"pointHierarchy/find/"+queryGlobal+"/"+page, success: function(msg){ if(msg !== undefined ) { diff --git a/WebContent/WEB-INF/spring-security.xml b/WebContent/WEB-INF/spring-security.xml index 557a6c77b0..b0007bab4f 100644 --- a/WebContent/WEB-INF/spring-security.xml +++ b/WebContent/WEB-INF/spring-security.xml @@ -24,6 +24,7 @@ + @@ -46,6 +47,7 @@ + @@ -68,6 +70,7 @@ + @@ -90,6 +93,7 @@ + @@ -112,6 +116,7 @@ + @@ -440,13 +445,13 @@ authentication-failure-url="/login.htm?error" login-page="/login.htm" password-parameter="password" username-parameter="username" login-processing-url="/login.htm"/> - + - + + + + + From e230e8569b28e96986ceabeb6b752a6c14e1c09e Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Thu, 22 Aug 2024 12:26:24 +0200 Subject: [PATCH 04/17] #2983 Prevent XSS for URLs Corrected tests in XssUtilsTest.java and logger Corrected XssUtils.validate(), now it works with all query cases --- WebContent/WEB-INF/jsp/scripting.jsp | 2 +- src/org/scada_lts/web/security/XssUtils.java | 39 ++++++---- .../scada_lts/web/security/XssUtilsTest.java | 78 ++++++++++--------- webapp-resources/log4j2.xml | 6 +- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/WebContent/WEB-INF/jsp/scripting.jsp b/WebContent/WEB-INF/jsp/scripting.jsp index 353587d83d..77d8871672 100644 --- a/WebContent/WEB-INF/jsp/scripting.jsp +++ b/WebContent/WEB-INF/jsp/scripting.jsp @@ -38,7 +38,7 @@ if (!myLocation) { myLocation = location.protocol + "//" + location.host + "/" + appScada + "/"; } - var urlGetDataPoints = "/api/datapoint/getAll"; + var urlGetDataPoints = "api/datapoint/getAll"; function executeScript(){ var xid = jQuery("#xid"); // saveScript() nie zdarzy zapisac !!! diff --git a/src/org/scada_lts/web/security/XssUtils.java b/src/org/scada_lts/web/security/XssUtils.java index 0f50c78444..44af0554f6 100644 --- a/src/org/scada_lts/web/security/XssUtils.java +++ b/src/org/scada_lts/web/security/XssUtils.java @@ -1,36 +1,49 @@ package org.scada_lts.web.security; import java.util.regex.Pattern; -import java.util.regex.Matcher; import java.util.List; import java.util.Arrays; -public class XssUtils { +final public class XssUtils { - private XssUtils() { - throw new UnsupportedOperationException("Utility class"); - } + private static final Pattern KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\-]{1,32}$"); - private static final Pattern SAFE_STRING_PATTERN = Pattern.compile("^[.\\p{Alnum}\\p{Space}]{0,1024}$"); + private static final Pattern VALUE_PATTERN = Pattern.compile("^[\\p{L}\\p{N}.\\-/+=_ !$*?@%]*$"); private static final List FORBIDDEN_XSS_PATTERNS = Arrays.asList( "javascript:", "onerror=", "onload=", "onmouseover=" ); - public static boolean validate(String value) { - if (value == null) { + public static boolean validate(String query) { + if (query == null || query.isEmpty()) { return true; } - Matcher matcher = SAFE_STRING_PATTERN.matcher(value); - if (!matcher.matches()) { - return false; + int questionMarkIndex = query.indexOf("?"); + if (questionMarkIndex >= 0) { + query = query.substring(questionMarkIndex + 1); } - for (String pattern : FORBIDDEN_XSS_PATTERNS) { - if (value.toLowerCase().contains(pattern)) { + String[] parameters = query.split("&"); + for (String parameter : parameters) { + if (parameter.isEmpty()) { + continue; + } + + if (!KEY_PATTERN.matcher(parameter).matches()) { + return false; + } + + if (!VALUE_PATTERN.matcher(parameter).matches()) { return false; } + + String lowerCaseValue = parameter.toLowerCase(); + for (String forbiddenPattern : FORBIDDEN_XSS_PATTERNS) { + if (lowerCaseValue.contains(forbiddenPattern)) { + return false; + } + } } return true; diff --git a/test/org/scada_lts/web/security/XssUtilsTest.java b/test/org/scada_lts/web/security/XssUtilsTest.java index b9f7839f52..028ecacc5e 100644 --- a/test/org/scada_lts/web/security/XssUtilsTest.java +++ b/test/org/scada_lts/web/security/XssUtilsTest.java @@ -1,53 +1,55 @@ package org.scada_lts.web.security; import org.junit.Test; -import static org.junit.Assert.*; - -public class XssUtilsTest { +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; - @Test - public void testValidate_NullValue() { - assertTrue("Null value should be considered valid.", XssUtils.validate(null)); - } +import static org.junit.Assert.*; - @Test - public void testValidate_ValidString() { - assertTrue("A valid string should be considered valid.", XssUtils.validate("ValidString123")); - assertTrue("A valid string with spaces should be considered valid.", XssUtils.validate("Simple sentence with spaces")); - assertTrue("A valid string with alphanumeric characters and allowed symbols should be considered valid.", XssUtils.validate("A1.b2 c3")); - } +import java.util.Arrays; +import java.util.Collection; - @Test - public void testValidate_ExceedsMaxLength() { - String longString = new String(new char[1025]).replace("\0", "a"); - assertFalse("A string longer than 1024 characters should be considered invalid.", XssUtils.validate(longString)); - } +@RunWith(Parameterized.class) +public class XssUtilsTest { - @Test - public void testValidate_ContainsForbiddenPatterns() { - assertFalse("A string containing 'javascript:' should be considered invalid.", XssUtils.validate("This contains javascript: in the middle")); - assertFalse("A string containing 'onerror=' should be considered invalid.", XssUtils.validate("This contains onerror= in the middle")); - assertFalse("A string containing 'onload=' should be considered invalid.", XssUtils.validate("This contains onload= in the middle")); - assertFalse("A string containing 'onmouseover=' should be considered invalid.", XssUtils.validate("This contains onmouseover= in the middle")); - } + private final String input; + private final boolean expectedResult; - @Test - public void testValidate_InvalidCharacters() { - assertFalse("A string containing '<' and '>' should be considered invalid.", XssUtils.validate("")); - assertFalse("A string containing '\"' should be considered invalid.", XssUtils.validate("Invalid\"Character")); - assertFalse("A string containing ''' should be considered invalid.", XssUtils.validate("Invalid'Character")); - assertFalse("A string containing '(' and ')' should be considered invalid.", XssUtils.validate("Invalid(Character)")); + public XssUtilsTest(String input, boolean expectedResult) { + this.input = input; + this.expectedResult = expectedResult; } - @Test - public void testValidate_ValidWithEdgeCases() { - assertTrue("A single dot should be considered valid.", XssUtils.validate(".")); - String edgeCaseString = "A string with exactly 1024 characters" + new String(new char[1024 - 37]).replace("\0", "a"); - assertTrue("A string with exactly 1024 characters should be considered valid.", XssUtils.validate(edgeCaseString)); + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + + // Test for a legitimate Query + {"validUser", true}, + {"123", true}, + + // Tests for queries containing banned patterns. + {"javascript:alert(1)", false}, + {"onerror=alert(1)", false}, + {"", false}, + {"onload=alert(1)", false}, + {"onmouseover=alert(1)", false}, + {"%6A%61%76%61%73%63%72%69%70%74", false}, + + // Borderline cases + {"=&", false}, + {"a”.repeat(33)", false}, + {"invalid!key", false}, + {"validKey", true}, + {"onerror=alert(1)&onload=alert(1)", false}, + {"!key=value", false}, + + }); } @Test - public void testValidate_EmptyString() { - assertTrue("An empty string should be considered valid.", XssUtils.validate("")); + public void testValidate() { + assertEquals("Validation failed for input: " + input, expectedResult, XssUtils.validate(input)); } } diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index 0a486298ed..3f892ba440 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -41,6 +41,10 @@ ERROR + + + WARN + @@ -287,7 +291,7 @@ - + From d8c0cd9278e7780ffbde145dba8e470ebb7870fe Mon Sep 17 00:00:00 2001 From: Kamil Date: Thu, 22 Aug 2024 14:40:21 +0200 Subject: [PATCH 05/17] #2983 Prevent XSS for URLs: - corrected regex pattern (check pattern: param=value, param); - added test cases to XssUtilsTest; - renamed method from validate to validateHttpQuery in XssUtils; - corrected implementation Filter; --- src/org/scada_lts/web/security/XssFilter.java | 25 ++++----- src/org/scada_lts/web/security/XssUtils.java | 41 +++------------ .../scada_lts/web/security/XssUtilsTest.java | 51 ++++++++++++++++++- 3 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/org/scada_lts/web/security/XssFilter.java b/src/org/scada_lts/web/security/XssFilter.java index 11f6122188..9f21e309b8 100644 --- a/src/org/scada_lts/web/security/XssFilter.java +++ b/src/org/scada_lts/web/security/XssFilter.java @@ -16,22 +16,19 @@ public class XssFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - request.getParameterMap().forEach((key, values) -> { - for (String value : values) { - if (!XssUtils.validate(value)) { - LOG.warn("Potential XSS detected in request. Parameter: {}, Value: {}. Request URI: {}", - key, value, request.getRequestURI()); + String query = request.getQueryString(); + if (query != null && !XssUtils.validateHttpQuery(query)) { + LOG.error("Potential XSS detected in request. Request URI: {}, Query: {}", + request.getRequestURI(), request.getQueryString()); - try { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Potential XSS detected in the request parameter: " + key); - } catch (IOException e) { - throw new RuntimeException(e); - } - return; - } + try { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + "Potential XSS detected in the request Query: " + request.getQueryString()); + } catch (IOException e) { + throw new RuntimeException(e); } - }); + return; + } filterChain.doFilter(request, response); } diff --git a/src/org/scada_lts/web/security/XssUtils.java b/src/org/scada_lts/web/security/XssUtils.java index 44af0554f6..fc15c5c017 100644 --- a/src/org/scada_lts/web/security/XssUtils.java +++ b/src/org/scada_lts/web/security/XssUtils.java @@ -6,46 +6,21 @@ final public class XssUtils { - private static final Pattern KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\-]{1,32}$"); + private static final Pattern HTTP_QUERY_STRING = Pattern.compile("^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))*$"); + private static final List FORBIDDEN_XSS_PATTERNS = Arrays.asList("javascript:", "onerror", "onload", "onmouseover", "alert("); - private static final Pattern VALUE_PATTERN = Pattern.compile("^[\\p{L}\\p{N}.\\-/+=_ !$*?@%]*$"); - - private static final List FORBIDDEN_XSS_PATTERNS = Arrays.asList( - "javascript:", "onerror=", "onload=", "onmouseover=" - ); - - public static boolean validate(String query) { + public static boolean validateHttpQuery(String query) { if (query == null || query.isEmpty()) { - return true; - } - - int questionMarkIndex = query.indexOf("?"); - if (questionMarkIndex >= 0) { - query = query.substring(questionMarkIndex + 1); + return false; } - String[] parameters = query.split("&"); - for (String parameter : parameters) { - if (parameter.isEmpty()) { - continue; - } - - if (!KEY_PATTERN.matcher(parameter).matches()) { + for(String pattern: FORBIDDEN_XSS_PATTERNS) { + if(query.contains(pattern)) { return false; } - - if (!VALUE_PATTERN.matcher(parameter).matches()) { - return false; - } - - String lowerCaseValue = parameter.toLowerCase(); - for (String forbiddenPattern : FORBIDDEN_XSS_PATTERNS) { - if (lowerCaseValue.contains(forbiddenPattern)) { - return false; - } - } } - return true; + boolean matches = HTTP_QUERY_STRING.matcher(query).matches(); + return matches; } } diff --git a/test/org/scada_lts/web/security/XssUtilsTest.java b/test/org/scada_lts/web/security/XssUtilsTest.java index 028ecacc5e..ecf32d3284 100644 --- a/test/org/scada_lts/web/security/XssUtilsTest.java +++ b/test/org/scada_lts/web/security/XssUtilsTest.java @@ -21,7 +21,7 @@ public XssUtilsTest(String input, boolean expectedResult) { this.expectedResult = expectedResult; } - @Parameters + @Parameters(name = "{index}: input: {0}, expectedResult: {1}") public static Collection data() { return Arrays.asList(new Object[][]{ @@ -45,11 +45,58 @@ public static Collection data() { {"onerror=alert(1)&onload=alert(1)", false}, {"!key=value", false}, + + {"abc", true}, + {"ABC", true}, + {"abc=abc", true}, + {"ABC=ABC", true}, + {"abc=abc&ABC=ABC", true}, + {"ABC=ABC&abc=abc", true}, + {"abc=1", true}, + {"ABC=1", true}, + {"param123", true}, + {"param1¶m2=23", true}, + {"param1=12¶m2", true}, + {"param1", true}, + + {"", false}, + {null, false}, + {"¶m1", false}, + {"¶m1¶m2", false}, + {"¶m1=123¶m2", false}, + {"¶m1¶m=123", false}, + {"param1¶m2=23&onerror", false}, + {"param1¶m2=23onerror", false}, + {"para!m1", false}, + {"onerror=alert(1)", false}, + {"onload=alert(1)", false}, + {"onerror=abc", false}, + {"onload=abc", false}, + {"onload=", false}, + {"onerror=", false}, + {"onload", false}, + {"onerror", false}, + {"!param1=value", false}, + {"", false}, + {"param1=", false}, + {"param1=¶m2=123", false}, + {"param1=123¶m2=", false}, + {"param1=123¶m2=", false}, + {"param1=alert(document.location)", false}, + {"startTs=123", true}, + {"startTs=1724326168402&endTs=1724329768507", true}, + {"startTs=1724326168402&endTs=1724329768507&ids=101,70,97,84&configFromSystem=false&enabled=false&valuesLimit=10000&limitFactor=1", true}, + {"startTs=123.", true}, }); } @Test public void testValidate() { - assertEquals("Validation failed for input: " + input, expectedResult, XssUtils.validate(input)); + + //when: + boolean result = XssUtils.validateHttpQuery(input); + + //then: + assertEquals("Validation failed for input: " + input, expectedResult, result); } } From 5cc156c1a709a9bf98e7ff182018cfa81faaa49b Mon Sep 17 00:00:00 2001 From: Kamil Date: Fri, 23 Aug 2024 00:41:11 +0200 Subject: [PATCH 06/17] #2983 Prevent XSS for URLs: - added test cases to XssUtilsTest; - added properties: scadalts.security.http.query.access.denied.regex, scadalts.security.http.query.access.granted.regex, scadalts.security.http.query.limit scadalts.security.http.query.xss.enabled to env.properties - corrected /pointHierarchy/move/ --- scadalts-ui/src/store/pointHierarchy/index.js | 2 +- .../scada_lts/utils/SystemSettingsUtils.java | 43 +++++ src/org/scada_lts/web/security/XssUtils.java | 37 +++-- test/WEB-INF/classes/env.properties | 149 ------------------ test/env.properties | 29 +++- .../scada_lts/web/security/XssUtilsTest.java | 16 +- test/utils/mock/MockUtils.java | 2 +- webapp-resources/env.properties | 5 + 8 files changed, 113 insertions(+), 170 deletions(-) delete mode 100644 test/WEB-INF/classes/env.properties diff --git a/scadalts-ui/src/store/pointHierarchy/index.js b/scadalts-ui/src/store/pointHierarchy/index.js index 76abca1047..641c0b9c6a 100644 --- a/scadalts-ui/src/store/pointHierarchy/index.js +++ b/scadalts-ui/src/store/pointHierarchy/index.js @@ -116,7 +116,7 @@ const gv = { return new Promise((resolve, reject) => { axios .post( - `.//pointHierarchy/move/${nodeId}/${parentNodeId}/${newParentNodeId}/${isFolder}`, + `./pointHierarchy/move/${nodeId}/${parentNodeId}/${newParentNodeId}/${isFolder}`, requestConfiguration, ) .then((resp) => { diff --git a/src/org/scada_lts/utils/SystemSettingsUtils.java b/src/org/scada_lts/utils/SystemSettingsUtils.java index 77919caa16..280da883c0 100644 --- a/src/org/scada_lts/utils/SystemSettingsUtils.java +++ b/src/org/scada_lts/utils/SystemSettingsUtils.java @@ -67,6 +67,11 @@ private SystemSettingsUtils() {} public static final String EVENT_ASSIGN_ENABLED_KEY = "event.assign.enabled"; + private static final String SECURITY_HTTP_QUERY_ACCESS_DENIED_REGEX_KEY = "scadalts.security.http.query.access.denied.regex"; + private static final String SECURITY_HTTP_QUERY_ACCESS_GRANTED_REGEX_KEY = "scadalts.security.http.query.access.granted.regex"; + private static final String SECURITY_HTTP_QUERY_LIMIT_KEY = "scadalts.security.http.query.limit"; + private static final String SECURITY_HTTP_QUERY_XSS_ENABLED_KEY = "scadalts.security.http.query.xss.enabled"; + private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(SystemSettingsUtils.class); public static DataPointSyncMode getDataPointSynchronizedMode() { @@ -538,4 +543,42 @@ public static boolean isEventAssignEnabled() { return false; } } + + public static String getSecurityHttpQueryAccessDeniedRegex() { + try { + return ScadaConfig.getInstance().getConf().getProperty(SECURITY_HTTP_QUERY_ACCESS_DENIED_REGEX_KEY, ""); + } catch (Exception e) { + LOG.error(e.getMessage()); + return ""; + } + } + + public static String getSecurityHttpQueryAccessGrantedRegex() { + try { + return ScadaConfig.getInstance().getConf().getProperty(SECURITY_HTTP_QUERY_ACCESS_GRANTED_REGEX_KEY, ""); + } catch (Exception e) { + LOG.error(e.getMessage()); + return ""; + } + } + + public static int getSecurityHttpQueryLimit() { + try { + String securityHttpQueryXssLimit = ScadaConfig.getInstance().getConf().getProperty(SECURITY_HTTP_QUERY_LIMIT_KEY, "4001"); + return Integer.parseInt(securityHttpQueryXssLimit); + } catch (Exception e) { + LOG.error(e.getMessage()); + return 4002; + } + } + + public static boolean isSecurityHttpQueryXssEnabled() { + try { + String securityHttpQueryXssEnabled = ScadaConfig.getInstance().getConf().getProperty(SECURITY_HTTP_QUERY_XSS_ENABLED_KEY, "false"); + return Boolean.parseBoolean(securityHttpQueryXssEnabled); + } catch (Exception e) { + LOG.error(e.getMessage()); + return false; + } + } } diff --git a/src/org/scada_lts/web/security/XssUtils.java b/src/org/scada_lts/web/security/XssUtils.java index fc15c5c017..c0afcf3913 100644 --- a/src/org/scada_lts/web/security/XssUtils.java +++ b/src/org/scada_lts/web/security/XssUtils.java @@ -1,26 +1,43 @@ package org.scada_lts.web.security; +import org.scada_lts.serorepl.utils.StringUtils; +import org.scada_lts.utils.SystemSettingsUtils; + import java.util.regex.Pattern; -import java.util.List; -import java.util.Arrays; final public class XssUtils { - private static final Pattern HTTP_QUERY_STRING = Pattern.compile("^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))*$"); - private static final List FORBIDDEN_XSS_PATTERNS = Arrays.asList("javascript:", "onerror", "onload", "onmouseover", "alert("); + private XssUtils() {} + + private static final Pattern SECURITY_HTTP_ACCESS_DENIED_QUERY_REGEX = init(SystemSettingsUtils.getSecurityHttpQueryAccessDeniedRegex()); + private static final Pattern SECURITY_HTTP_ACCESS_GRANTED_QUERY_REGEX = init(SystemSettingsUtils.getSecurityHttpQueryAccessGrantedRegex()); + public static final int SECURITY_HTTP_ACCESS_GRANTED_QUERY_LIMIT = SystemSettingsUtils.getSecurityHttpQueryLimit(); + public static final boolean SECURITY_HTTP_QUERY_XSS_ENABLED = SystemSettingsUtils.isSecurityHttpQueryXssEnabled(); public static boolean validateHttpQuery(String query) { + + if(!SECURITY_HTTP_QUERY_XSS_ENABLED) + return true; + if (query == null || query.isEmpty()) { return false; } - for(String pattern: FORBIDDEN_XSS_PATTERNS) { - if(query.contains(pattern)) { - return false; - } + if(query.length() > SECURITY_HTTP_ACCESS_GRANTED_QUERY_LIMIT) { + return false; } - boolean matches = HTTP_QUERY_STRING.matcher(query).matches(); - return matches; + if(SECURITY_HTTP_ACCESS_DENIED_QUERY_REGEX != null && SECURITY_HTTP_ACCESS_DENIED_QUERY_REGEX.matcher(query).matches()) { + return false; + } + + return SECURITY_HTTP_ACCESS_GRANTED_QUERY_REGEX == null || SECURITY_HTTP_ACCESS_GRANTED_QUERY_REGEX.matcher(query).matches(); + } + + private static Pattern init(String regex) { + if(StringUtils.isEmpty(regex)) { + return null; + } + return Pattern.compile(regex); } } diff --git a/test/WEB-INF/classes/env.properties b/test/WEB-INF/classes/env.properties deleted file mode 100644 index ad07ffb7cd..0000000000 --- a/test/WEB-INF/classes/env.properties +++ /dev/null @@ -1,149 +0,0 @@ -# -# Mango - Open Source M2M - http://mango.serotoninsoftware.com -# Copyright (C) 2006-2009 Serotonin Software Technologies Inc. -# @author Matthew Lohbihler -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# - -# PARA INTEGRAR O ScadaBR AO POSTGRESQL v9.2 INSTALE O POSTGRESQL v9.2 NA M\u00c1QUINA SERVIDORA -# ALTERE A LINHA db.password=admin (COLOQUE A SENHA DEFINIDA POR VOC\u00ca) -# N\u00c3O REMOVA A LINHA db.url.public=jdbc:postgresql://localhost:5432/postgres - -#testowy!!!! - -#db.type=postgres -#db.url=jdbc:postgresql://localhost:5432/scadabr -#db.url.public=jdbc:postgresql://localhost:5432/postgres -#db.username=postgres -#db.password=admin -#db.pool.maxActive=10 -#db.pool.maxIdle=10 - -db.type=mysql -db.datasource=true -db.datasourceName=java:comp/test_env/jdbc/scadalts -#db.url=jdbc:mysql://localhost:3306/scadalts -#db.username=root -#db.password=root -#db.pool.maxActive=10 -#db.pool.maxIdle=10 -#db.update.log.dir=logs -#db.upgrade.check=false - -#db.type=derby -#db.url=~../../bin/scadabrDB -#db.username= -#db.password= - -js.optimizationlevel=-1 - -api.authentication=disabled -api.username=admin -api.password=admin - -abilit.disableDataSourcesOnServerStart=false - -abilit.api.replace.alert.onview=true - - -abilit.cacheEnable=true -abilit.START_UPDATE_UNSILENCED_ALARM_LEVEL=100000 -abilit.START_UPDATE_EVENT_DETECTORS=100000 -abilit.START_UPDATE_PENDING_EVENTS=100000 -abilit.MILLIS_SECONDS_PERIOD_UPDATE_UNSILENCED_ALARM_LEVEL=1000 -#abilit.MILLIS_SECONDS_PERIOD_UPDATE_EVENT_DETECTORS=1000 -abilit.MILLIS_SECONDS_PERIOD_UPDATE_PENDING_EVENTS=1000 -abilit.CRONE_UPDATE_CACHE_POINT_HIERARCHY=0 0/10 * * * ? - -# every minute -abilit.CRONE_UPDATE_DATA_SOURCES_POINTS=0 0/1 * * * ? -abilit.USE_CACHE_DATA_SOURCES_POINTS_WHEN_THE_SYSTEM_IS_READY=true - -#Permission ACL -abilit.USE_ACL=false -abilit.ACL_SERVER=http://localhost:8090 - -#Events -abilit.DO_NOT_CREATE_EVENTS_FOR_EMAIL_ERROR=true - -#Reactivation HttpRetriver -abilit.HTTP_RETRIVER_SLEEP_CHECK_TO_REACTIVATION_WHEN_START=false -abilit.HTTP_RETRIVER_DO_NOT_ALLOW_ENABLE_REACTIVATION=false - -#security.hashAlgorithm=NONE -#grove.url=http://mango.serotoninsoftware.com/servlet - -api.amcharts.aggregation.enabled=true -api.amcharts.aggregation.valuesLimit=20000 -api.amcharts.aggregation.limitFactor=1.5 - -user.cache.enabled=true -usersprofile.cache.enabled=true -permissions.cache.enabled=true -shareuser.cache.enabled=true -usercomment.cache.enabled=true -view.cache.enabled=true - -alarmlevel.highest.cache.enabled=true -alarmlevel.highest.cache.reset.enabled=true -alarmlevel.highest.cache.reset.cron=0 0 1/3 ? * * * - -svg.validator.enabled=true -svg.validator.only-xml=false -svg.validator.schemas=svg/svg11-flat-20110816/svg11-flat-20110816.xsd;svg/svg10-flat-20010904/svg10-flat-20010904.xsd -# Incompatible with SVG 1.0/1.1/1.1 Second Edition/1.1 Tiny/1.1 Basic - often found in files; -# rdf:RDF - https://www.w3.org/TR/SVGTiny12/metadata.html -svg.validator.tags.ignore=rdf:RDF;sodipodi:namedview;inkscape:perspective -svg.validator.messages.ignore=must appear on element;Attribute 'blend' is not allowed to appear in element 'feBlend'.;sodipodi:;inkscape:;Attribute 'vector-effect' is not allowed to appear in element 'g'. -systemsettings.http.response.headers={} - -datapoint.runtime.value.synchronized=NONE - -comm.serial.timeout.read=500 -comm.serial.timeout.write=500 -comm.serial.timeout.mode=0 -comm.serial.sleep=1000 - -systemsettings.email.timeout=60000 -processing.workitems.limit=51 -processing.workitems.failed.limit=51 -processing.workitems.running.limit=51 -processing.workitems.running.repeat=51 -processing.workitems.history.process.limit=51 -processing.workitems.history.priority.high.limit=51 -processing.workitems.history.priority.medium.limit=51 -processing.workitems.history.priority.low.limit=51 -processing.workitems.history.longer.thanMs=1500 -processing.workitems.history.longer.limit=200 - -scadalts.security.js.access.denied.method.regexes=getDeclaredField;getPassword;getClass;getRuntime;exec -scadalts.security.js.access.denied.class.regexes=java.lang.Runtime;java.lang.Runtime.*;java.lang.reflect.*;java.lang.ref.*;java.lang.System.*;java.lang.System;java.lang.ClassLoader;java.lang.Compiler;java.lang.SecurityManager;java.lang.Thread;java.lang.ThreadGroup;java.lang.ThreadLocal -scadalts.security.js.access.granted.method.regexes=^.* -scadalts.security.js.access.granted.class.regexes=^.* - -view.forceFullScreen=false -view.hideShortcutDisableFullScreen=false -eventdetector.cache.enabled=true -event.pending.limit=101 -event.pending.update.limit=5001 -threads.name.additional.length=5 -workitems.reporting.enabled=false -workitems.reporting.itemspersecond.enabled=false -workitems.reporting.itemspersecond.limit=20000 - -webresource.uploads.path=static/uploads -webresource.graphics.path=static/graphics -svg.validator.disallow-doctype-decl.enabled=false \ No newline at end of file diff --git a/test/env.properties b/test/env.properties index 6239588d4d..a7590a40b9 100644 --- a/test/env.properties +++ b/test/env.properties @@ -107,7 +107,9 @@ svg.validator.schemas=svg/svg11-flat-20110816/svg11-flat-20110816.xsd;svg/svg10- # Incompatible with SVG 1.0/1.1/1.1 Second Edition/1.1 Tiny/1.1 Basic - often found in files; # rdf:RDF - https://www.w3.org/TR/SVGTiny12/metadata.html svg.validator.tags.ignore=rdf:RDF;sodipodi:namedview;inkscape:perspective -svg.validator.messages.ignore=must appear on element;Attribute 'blend' is not allowed to appear in element 'feBlend'.;sodipodi:;inkscape:;Attribute 'vector-effect' is not allowed to appear in element 'g'. +svg.validator.messages.ignore=must appear on element;muss in Element;Attribute 'blend' is not allowed to appear in element 'feBlend'.;sodipodi:;inkscape:;Attribute 'vector-effect' is not allowed to appear in element 'g'.;Attribut 'vector-effect' darf nicht in Element 'g' vorkommen.; +svg.validator.disallow-doctype-decl.enabled=false + systemsettings.http.response.headers={} datapoint.runtime.value.synchronized=NONE @@ -119,9 +121,10 @@ comm.serial.sleep=1000 systemsettings.email.timeout=60000 processing.workitems.limit=51 -processing.workitems.failed.limit=51 processing.workitems.running.limit=51 processing.workitems.running.repeat=51 +processing.workitems.history.limit=51 +processing.workitems.history.failed.limit=51 processing.workitems.history.process.limit=51 processing.workitems.history.priority.high.limit=51 processing.workitems.history.priority.medium.limit=51 @@ -139,14 +142,14 @@ view.hideShortcutDisableFullScreen=false eventdetector.cache.enabled=true event.pending.limit=101 event.pending.update.limit=5001 -threads.name.additional.length=5 +threads.name.additional.length=255 workitems.reporting.enabled=false workitems.reporting.itemspersecond.enabled=false workitems.reporting.itemspersecond.limit=20000 webresource.uploads.path=static/uploads webresource.graphics.path=static/graphics -svg.validator.disallow-doctype-decl.enabled=false +websocket.client.sockjs.url=../../resources/node_modules/sockjs-client/dist/sockjs.min.js thread-pool-executor.low-priority.core-pool-size=1 thread-pool-executor.low-priority.maximum-pool-size=1 @@ -173,4 +176,20 @@ thread-pool-executor.high-priority.keep-alive-time=30 thread-pool-executor.high-priority.blocking-queue-interface-impl=java.util.concurrent.SynchronousQueue thread-pool-executor.high-priority.blocking-queue-interface-impl.args= thread-pool-executor.high-priority.blocking-queue-interface-impl.args-types= -thread-pool-executor.high-priority.time-unit-enum-value=SECONDS \ No newline at end of file +thread-pool-executor.high-priority.time-unit-enum-value=SECONDS + +workitems.config.BatchWriteBehind.maxRows=2000 +workitems.config.BatchWriteBehind.maxInstances=5 +workitems.config.BatchWriteBehind.spawnThreshold=10000 + +http.protocol.reject-relative-redirect=true +http.protocol.method.follow-redirects=false +http.protocol.max-redirects=100 +http.protocol.allow-circular-redirects=false +http.protocol.timeout-ms=15000 +event.assign.enabled=true + +scadalts.security.http.query.xss.enabled=true +scadalts.security.http.query.limit=4000 +scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ +scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]+&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ \ No newline at end of file diff --git a/test/org/scada_lts/web/security/XssUtilsTest.java b/test/org/scada_lts/web/security/XssUtilsTest.java index ecf32d3284..48050b8171 100644 --- a/test/org/scada_lts/web/security/XssUtilsTest.java +++ b/test/org/scada_lts/web/security/XssUtilsTest.java @@ -57,7 +57,17 @@ public static Collection data() { {"param123", true}, {"param1¶m2=23", true}, {"param1=12¶m2", true}, + {"param1=12¶m2¶m3", true}, {"param1", true}, + {"startTs=123", true}, + {"startTs=1724326168402&endTs=1724329768507", true}, + {"startTs=123.", true}, + {"startTs=12345678901234567890123456789012", true}, + {"startTs=123456789012345678901234567890123", true}, + {"12345678901234567890123456789012=abc", true}, + {"123456789012345678901234567890123=abc", true}, + {"startTs=1724326168402&endTs=1724329768507&ids=101,70,97,84&configFromSystem=false&enabled=false&valuesLimit=10000&limitFactor=1", true}, + {"", false}, {null, false}, @@ -83,10 +93,8 @@ public static Collection data() { {"param1=123¶m2=", false}, {"param1=123¶m2=", false}, {"param1=alert(document.location)", false}, - {"startTs=123", true}, - {"startTs=1724326168402&endTs=1724329768507", true}, - {"startTs=1724326168402&endTs=1724329768507&ids=101,70,97,84&configFromSystem=false&enabled=false&valuesLimit=10000&limitFactor=1", true}, - {"startTs=123.", true}, + {"abc=", false}, + {"=abc", false}, }); } diff --git a/test/utils/mock/MockUtils.java b/test/utils/mock/MockUtils.java index 30b5dd8bb5..57e02d50ba 100644 --- a/test/utils/mock/MockUtils.java +++ b/test/utils/mock/MockUtils.java @@ -53,7 +53,7 @@ public static void configMock(RuntimeManager runtimeManager, User user) throws E when(Common.getUser()).thenReturn(user); when(Common.getUser(any(HttpServletRequest.class))).thenReturn(user); - PropertiesUtils propertiesUtils = new PropertiesUtils("WEB-INF/classes/env"); + PropertiesUtils propertiesUtils = new PropertiesUtils("env"); when(Common.getEnvironmentProfile()).thenReturn(propertiesUtils); } diff --git a/webapp-resources/env.properties b/webapp-resources/env.properties index 9261124db5..15c6cb1c3e 100644 --- a/webapp-resources/env.properties +++ b/webapp-resources/env.properties @@ -186,3 +186,8 @@ http.protocol.max-redirects=100 http.protocol.allow-circular-redirects=false http.protocol.timeout-ms=15000 event.assign.enabled=true + +scadalts.security.http.query.xss.enabled=true +scadalts.security.http.query.limit=4000 +scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ +scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]+&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ From 383ebd8bf64831623d4e0a85c82ddfc089435194 Mon Sep 17 00:00:00 2001 From: Kamil Date: Sat, 24 Aug 2024 21:09:39 +0200 Subject: [PATCH 07/17] #2983 Prevent XSS for URLs: - included variant abc= in the regex; --- test/env.properties | 2 +- test/org/scada_lts/web/security/XssUtilsTest.java | 6 +++--- webapp-resources/env.properties | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/env.properties b/test/env.properties index a7590a40b9..746251e926 100644 --- a/test/env.properties +++ b/test/env.properties @@ -192,4 +192,4 @@ event.assign.enabled=true scadalts.security.http.query.xss.enabled=true scadalts.security.http.query.limit=4000 scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ -scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]+&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ \ No newline at end of file +scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[a-zA-Z0-9_\\-.,/+=\s!$*?@%]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ \ No newline at end of file diff --git a/test/org/scada_lts/web/security/XssUtilsTest.java b/test/org/scada_lts/web/security/XssUtilsTest.java index 48050b8171..951cbc6c1c 100644 --- a/test/org/scada_lts/web/security/XssUtilsTest.java +++ b/test/org/scada_lts/web/security/XssUtilsTest.java @@ -67,7 +67,8 @@ public static Collection data() { {"12345678901234567890123456789012=abc", true}, {"123456789012345678901234567890123=abc", true}, {"startTs=1724326168402&endTs=1724329768507&ids=101,70,97,84&configFromSystem=false&enabled=false&valuesLimit=10000&limitFactor=1", true}, - + {"projectName=sagadf&includePointValues=true&includeUploadsFolder=true&includeGraphicsFolder=true&projectDescription=&pointValuesMaxZip=100", true}, + {"abc=", true}, {"", false}, {null, false}, @@ -93,8 +94,7 @@ public static Collection data() { {"param1=123¶m2=", false}, {"param1=123¶m2=", false}, {"param1=alert(document.location)", false}, - {"abc=", false}, - {"=abc", false}, + {"=abc", false} }); } diff --git a/webapp-resources/env.properties b/webapp-resources/env.properties index 15c6cb1c3e..4a2e228086 100644 --- a/webapp-resources/env.properties +++ b/webapp-resources/env.properties @@ -190,4 +190,4 @@ event.assign.enabled=true scadalts.security.http.query.xss.enabled=true scadalts.security.http.query.limit=4000 scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ -scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%,]+&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ +scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[a-zA-Z0-9_\\-.,/+=\s!$*?@%]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ From d63c8fdcea20040924ddce096299f85a7e1db5d0 Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Mon, 26 Aug 2024 12:47:39 +0200 Subject: [PATCH 08/17] #2983 Prevent XSS for URLs - Minor changes in log4j2.xml --- webapp-resources/log4j2.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index 3f892ba440..cbde8c2767 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -42,8 +42,8 @@ ERROR - - WARN + + WARN @@ -290,8 +290,8 @@ - - + + From 78c9279bf65cc3fba6fd7b52dc024d62661ad9b2 Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Mon, 26 Aug 2024 13:18:58 +0200 Subject: [PATCH 09/17] #2983 Prevent XSS for URLs - Minor changes in log4j2.xml --- webapp-resources/log4j2.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index cbde8c2767..a697ebbe90 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -43,7 +43,7 @@ ERROR - WARN + WARN @@ -291,7 +291,7 @@ - + From 7c70a42bcc961cd7b6c01acfe922b33589cb38d5 Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Mon, 26 Aug 2024 13:55:05 +0200 Subject: [PATCH 10/17] #1580 Improvement describe information about scada on top - Changed way of top description being dynamically refreshed --- webapp-resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index a697ebbe90..1e9d3188eb 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -43,7 +43,7 @@ ERROR - WARN + INFO From 4f4c8b85ad014c30d322d1d729e0996ed9dea64b Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Mon, 26 Aug 2024 13:55:16 +0200 Subject: [PATCH 11/17] Revert "#1580 Improvement describe information about scada on top" This reverts commit 7c70a42bcc961cd7b6c01acfe922b33589cb38d5. --- webapp-resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index 1e9d3188eb..a697ebbe90 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -43,7 +43,7 @@ ERROR - INFO + WARN From 9ec2f4a641c4186469fd00ef1e31543fcbdfbf43 Mon Sep 17 00:00:00 2001 From: Patrykb0802 Date: Mon, 26 Aug 2024 13:55:44 +0200 Subject: [PATCH 12/17] #2983 Prevent XSS for URLs --- webapp-resources/log4j2.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index a697ebbe90..1e9d3188eb 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -43,7 +43,7 @@ ERROR - WARN + INFO From a8ee3066a1e9af616a5be76d937c6e75149cc16f Mon Sep 17 00:00:00 2001 From: Kamil Jarmusik Date: Mon, 26 Aug 2024 15:35:44 +0200 Subject: [PATCH 13/17] #2983 Prevent XSS for URLs: - fixed websocket url; --- scadalts-ui/src/store/index.js | 7 +++++-- scadalts-ui/src/store/websocketStore.js | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scadalts-ui/src/store/index.js b/scadalts-ui/src/store/index.js index 0774a26d13..dffc1dd264 100644 --- a/scadalts-ui/src/store/index.js +++ b/scadalts-ui/src/store/index.js @@ -75,7 +75,7 @@ export default new Vuex.Store({ // useCredentials: true, // credentials: 'same-origin', }, - webSocketUrl: 'ws-scada/alarmLevel', + webSocketUrl: 'ws-scada', timePeriods: [ { id: 1, label: i18n.t('common.timeperiod.seconds') }, @@ -98,7 +98,10 @@ export default new Vuex.Store({ }, mutations: { updateWebSocketUrl(state) { - state.webSocketUrl = getAppLocation() + state.webSocketUrl; + let base = getAppLocation(); + if(!state.webSocketUrl.includes(base)) { + state.webSocketUrl = base + state.webSocketUrl; + } }, updateRequestTimeout(state, timeout) { diff --git a/scadalts-ui/src/store/websocketStore.js b/scadalts-ui/src/store/websocketStore.js index 3d0b8f053d..e8a4164b76 100644 --- a/scadalts-ui/src/store/websocketStore.js +++ b/scadalts-ui/src/store/websocketStore.js @@ -18,7 +18,11 @@ const webSocketModule = { mutations: { INIT_WEBSOCKET(state) { - let socket = new SockJS(getAppLocation() + state.webSocketUrl); + let base = getAppLocation(); + if(!state.webSocketUrl.includes(base)) { + state.webSocketUrl = base + state.webSocketUrl; + } + let socket = new SockJS(state.webSocketUrl); let client = Stomp.over(socket); if(!state.debugMode) { client.debug = () => {}; From 01982725ffc45a69e6606811ba04ca64f28da430 Mon Sep 17 00:00:00 2001 From: Kamil Jarmusik Date: Mon, 26 Aug 2024 17:15:21 +0200 Subject: [PATCH 14/17] #2983 Prevent XSS for URLs: - added Logger org.springframework.security; - set ERROR logging level for securityLoggingLevel; - set default query limit to 3900, default URL length limit for Apache Server a is approximately 4000 characters; --- src/org/scada_lts/web/security/XssFilter.java | 10 +++++----- src/org/scada_lts/web/security/XssUtils.java | 2 +- test/env.properties | 4 ++-- webapp-resources/env.properties | 2 +- webapp-resources/log4j2.xml | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/org/scada_lts/web/security/XssFilter.java b/src/org/scada_lts/web/security/XssFilter.java index 9f21e309b8..b150236f2f 100644 --- a/src/org/scada_lts/web/security/XssFilter.java +++ b/src/org/scada_lts/web/security/XssFilter.java @@ -16,14 +16,14 @@ public class XssFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String query = request.getQueryString(); - if (query != null && !XssUtils.validateHttpQuery(query)) { - LOG.error("Potential XSS detected in request. Request URI: {}, Query: {}", - request.getRequestURI(), request.getQueryString()); + String queryString = request.getQueryString(); + if (queryString != null && !XssUtils.validateHttpQuery(queryString)) { + LOG.warn("Potential XSS detected in request. Request URI: {}, Query: {}", + request.getRequestURI(), queryString); try { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Potential XSS detected in the request Query: " + request.getQueryString()); + "Potential XSS detected in the request Query: " + queryString); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/org/scada_lts/web/security/XssUtils.java b/src/org/scada_lts/web/security/XssUtils.java index c0afcf3913..71529d99bc 100644 --- a/src/org/scada_lts/web/security/XssUtils.java +++ b/src/org/scada_lts/web/security/XssUtils.java @@ -5,7 +5,7 @@ import java.util.regex.Pattern; -final public class XssUtils { +public final class XssUtils { private XssUtils() {} diff --git a/test/env.properties b/test/env.properties index 746251e926..169e61b244 100644 --- a/test/env.properties +++ b/test/env.properties @@ -189,7 +189,7 @@ http.protocol.allow-circular-redirects=false http.protocol.timeout-ms=15000 event.assign.enabled=true -scadalts.security.http.query.xss.enabled=true -scadalts.security.http.query.limit=4000 +scadalts.security.http.query.xss.enabled=false +scadalts.security.http.query.limit=3900 scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[a-zA-Z0-9_\\-.,/+=\s!$*?@%]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ \ No newline at end of file diff --git a/webapp-resources/env.properties b/webapp-resources/env.properties index 4a2e228086..37cc88fce8 100644 --- a/webapp-resources/env.properties +++ b/webapp-resources/env.properties @@ -188,6 +188,6 @@ http.protocol.timeout-ms=15000 event.assign.enabled=true scadalts.security.http.query.xss.enabled=true -scadalts.security.http.query.limit=4000 +scadalts.security.http.query.limit=3900 scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[a-zA-Z0-9_\\-.,/+=\s!$*?@%]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ diff --git a/webapp-resources/log4j2.xml b/webapp-resources/log4j2.xml index 1e9d3188eb..9e7f68988b 100644 --- a/webapp-resources/log4j2.xml +++ b/webapp-resources/log4j2.xml @@ -43,7 +43,7 @@ ERROR - INFO + ERROR @@ -173,6 +173,7 @@ + @@ -291,9 +292,8 @@ - - - + + From a004f661437982ed8c49909c8bf4f66ae4e9767d Mon Sep 17 00:00:00 2001 From: Kamil Jarmusik Date: Mon, 26 Aug 2024 17:19:24 +0200 Subject: [PATCH 15/17] #2983 Prevent XSS for URLs: - corrected junit test config --- test/env.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/env.properties b/test/env.properties index 169e61b244..f229c52cef 100644 --- a/test/env.properties +++ b/test/env.properties @@ -189,7 +189,7 @@ http.protocol.allow-circular-redirects=false http.protocol.timeout-ms=15000 event.assign.enabled=true -scadalts.security.http.query.xss.enabled=false +scadalts.security.http.query.xss.enabled=true scadalts.security.http.query.limit=3900 scadalts.security.http.query.access.denied.regex=^(.*?(javascript:|onerror|onload|onmouseover|alert\\(){1}.*?)$ scadalts.security.http.query.access.granted.regex=^(([a-zA-Z0-9_\\-]{1,32}=[a-zA-Z0-9_\\-.,/+=\s!$*?@%]*&?)|([a-zA-Z0-9_\\-]{1,32}&?))+$ \ No newline at end of file From 16123a61ad89804041814f351315d06b79931d1b Mon Sep 17 00:00:00 2001 From: Kamil Jarmusik Date: Mon, 26 Aug 2024 17:34:01 +0200 Subject: [PATCH 16/17] #2983 Prevent XSS for URLs: - commented old configuration for http-firewall --- WebContent/WEB-INF/spring-security.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/WebContent/WEB-INF/spring-security.xml b/WebContent/WEB-INF/spring-security.xml index 84e4f0f832..732fc40e23 100644 --- a/WebContent/WEB-INF/spring-security.xml +++ b/WebContent/WEB-INF/spring-security.xml @@ -452,6 +452,7 @@ success-handler-ref="headerWriterLogoutHandler"/> +