diff --git a/pom.xml b/pom.xml
index b6c908c2a5..19c93c6c4a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -162,6 +162,7 @@
2.3.1
26.0.7
6.3.3
+ 1.3.1
diff --git a/rest/authorization-server/src/main/java/org/eclipse/sw360/rest/authserver/Sw360AuthorizationServer.java b/rest/authorization-server/src/main/java/org/eclipse/sw360/rest/authserver/Sw360AuthorizationServer.java
index d98b186fb6..8ede315a96 100644
--- a/rest/authorization-server/src/main/java/org/eclipse/sw360/rest/authserver/Sw360AuthorizationServer.java
+++ b/rest/authorization-server/src/main/java/org/eclipse/sw360/rest/authserver/Sw360AuthorizationServer.java
@@ -16,13 +16,14 @@
import org.eclipse.sw360.datahandler.thrift.users.UserGroup;
import org.eclipse.sw360.rest.common.PropertyUtils;
import org.eclipse.sw360.rest.common.Sw360CORSFilter;
+import org.eclipse.sw360.rest.common.Sw360XssFilter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Import;
@SpringBootApplication
-@Import(Sw360CORSFilter.class)
+@Import({Sw360CORSFilter.class, Sw360XssFilter.class})
public class Sw360AuthorizationServer extends SpringBootServletInitializer {
private static final String SW360_PROPERTIES_FILE_PATH = "/sw360.properties";
diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/Sw360ResourceServer.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/Sw360ResourceServer.java
index 5dfa583f0e..98013f3eb0 100644
--- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/Sw360ResourceServer.java
+++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/Sw360ResourceServer.java
@@ -27,6 +27,7 @@
import org.eclipse.sw360.datahandler.thrift.users.UserGroup;
import org.eclipse.sw360.rest.common.PropertyUtils;
import org.eclipse.sw360.rest.common.Sw360CORSFilter;
+import org.eclipse.sw360.rest.common.Sw360XssFilter;
import org.eclipse.sw360.rest.resourceserver.core.OpenAPIPaginationHelper;
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
import org.eclipse.sw360.rest.resourceserver.security.apiToken.ApiTokenAuthenticationFilter;
@@ -50,7 +51,7 @@
import java.util.*;
@SpringBootApplication
-@Import(Sw360CORSFilter.class)
+@Import({Sw360CORSFilter.class, Sw360XssFilter.class})
public class Sw360ResourceServer extends SpringBootServletInitializer {
public static final String REST_BASE_PATH = "/api";
diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/security/ResourceServerConfiguration.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/security/ResourceServerConfiguration.java
index b9ac930ad0..cbbb98830f 100644
--- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/security/ResourceServerConfiguration.java
+++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/security/ResourceServerConfiguration.java
@@ -34,6 +34,7 @@
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
@Profile("!SECURITY_MOCK")
@Configuration
@@ -74,6 +75,8 @@ public SecurityFilterChain securityFilterChainRS1(HttpSecurity http) throws Exce
.jwkSetUri(issuerUri)))
.httpBasic(Customizer.withDefaults())
.exceptionHandling(x -> x.authenticationEntryPoint(saep))
+ .headers(headers -> headers.xssProtection(xXssConfig -> xXssConfig.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))
+ .contentSecurityPolicy(cps -> cps.policyDirectives("script-src 'self'")))
.csrf(csrf -> csrf.disable()).build();
}
diff --git a/rest/rest-common/pom.xml b/rest/rest-common/pom.xml
index 31cb98a649..56bffc6941 100644
--- a/rest/rest-common/pom.xml
+++ b/rest/rest-common/pom.xml
@@ -42,6 +42,12 @@
jakarta.servlet-api
provided
+
+ org.owasp.encoder
+ encoder
+ ${org.owasp.encoder.version}
+
+
rest-common
diff --git a/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XSSRequestWrapper.java b/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XSSRequestWrapper.java
new file mode 100644
index 0000000000..60e445a69e
--- /dev/null
+++ b/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XSSRequestWrapper.java
@@ -0,0 +1,113 @@
+/*
+SPDX-FileCopyrightText: © 2024 Siemens AG
+SPDX-License-Identifier: EPL-2.0
+*/
+package org.eclipse.sw360.rest.common;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * This class is used to sanitize the input from the user to prevent XSS attacks.
+ *
+ * @author smruti.sahoo@siemens.com
+ */
+public class Sw360XSSRequestWrapper extends HttpServletRequestWrapper {
+
+ public Sw360XSSRequestWrapper(HttpServletRequest request) {
+ super(request);
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ ServletInputStream originalInputStream = super.getInputStream();
+ String requestBody = new String(originalInputStream.readAllBytes());
+
+ JsonNode requestBodyJSON = sanitizeInput(new ObjectMapper().readTree(requestBody));
+ String sanitizedBody = requestBodyJSON.toString();
+ return new ServletInputStream() {
+ private final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
+ sanitizedBody.getBytes()
+ );
+
+ @Override
+ public int read() throws IOException {
+ return byteArrayInputStream.read();
+ }
+
+ @Override
+ public boolean isFinished() {
+ return byteArrayInputStream.available() == 0;
+ }
+
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ }
+ };
+ }
+
+ @Override
+ public String[] getParameterValues(String parameter) {
+ String[] values = super.getParameterValues(parameter);
+ if (values == null) {
+ return null;
+ }
+ int count = values.length;
+ String[] encodedValues = new String[count];
+ for (int i = 0; i < count; i++) {
+ encodedValues[i] = stripXSS(values[i]);
+ }
+ return encodedValues;
+ }
+
+ @Override
+ public String getParameter(String parameter) {
+ String value = super.getParameter(parameter);
+ return stripXSS(value);
+ }
+
+ @Override
+ public String getHeader(String name) {
+ String value = super.getHeader(name);
+ return stripXSS(value);
+ }
+
+ private String stripXSS(String value) {
+ return org.owasp.encoder.Encode.forHtml(value);
+
+ }
+
+ private JsonNode sanitizeInput(JsonNode input) {
+ if (input.isTextual()) {
+ return JsonNodeFactory.instance.textNode(stripXSS(input.asText()));
+ } else if (input.isArray()) {
+ ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode();
+ for (JsonNode element : input) {
+ arrayNode.add(sanitizeInput(element));
+ }
+ return arrayNode;
+ } else if (input.isObject()) {
+ ObjectNode objectNode = JsonNodeFactory.instance.objectNode();
+ input.fields().forEachRemaining(entry -> objectNode.set(entry.getKey(), sanitizeInput(entry.getValue())));
+ return objectNode;
+ } else {
+ return input;
+ }
+ }
+
+}
diff --git a/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XssFilter.java b/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XssFilter.java
new file mode 100644
index 0000000000..312dd866f3
--- /dev/null
+++ b/rest/rest-common/src/main/java/org/eclipse/sw360/rest/common/Sw360XssFilter.java
@@ -0,0 +1,35 @@
+/*
+SPDX-FileCopyrightText: © 2024 Siemens AG
+SPDX-License-Identifier: EPL-2.0
+*/
+package org.eclipse.sw360.rest.common;
+
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+
+import java.io.IOException;
+
+/**
+ * This filter is used to sanitize the input from the user to prevent XSS attacks.
+ * @author smruti.sahoo@siemens.com
+ */
+@Configuration
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class Sw360XssFilter implements Filter {
+
+ /**
+ * @param servletRequest
+ * @param servletResponse
+ * @param filterChain
+ * @throws IOException
+ * @throws ServletException
+ */
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ filterChain.doFilter(new Sw360XSSRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
+ }
+}