diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml index 5975aabc5..282093f28 100644 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/pom.xml @@ -33,6 +33,11 @@ org.springframework.cloud spring-cloud-starter-netflix-ribbon + + + org.owasp.esapi + esapi + diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java index 79ba2c0ef..04570498c 100644 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java @@ -17,6 +17,8 @@ package com.tencent.cloud.polaris.circuitbreaker.example; +import org.owasp.esapi.ESAPI; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -62,6 +64,12 @@ public class ServiceAController { ResponseEntity entity = restTemplate.getForEntity( "http://polaris-circuitbreaker-example-b/example/service/b/info", String.class); - return entity.getBody(); + String response = entity.getBody(); + return cleanXSS(response); + } + + private String cleanXSS(String str) { + str = ESAPI.encoder().encodeForHTML(str); + return str; } } diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/xss/XssResponseBodyAdvice.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/xss/XssResponseBodyAdvice.java deleted file mode 100644 index f16c9b71a..000000000 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/xss/XssResponseBodyAdvice.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.circuitbreaker.example.xss; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang.StringEscapeUtils; - -import org.springframework.core.MethodParameter; -import org.springframework.http.MediaType; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; - -/** - * Escape String in ResponseBody before write it into HttpResponse - * - * @author Daifu Wu - */ -@ControllerAdvice -public class XssResponseBodyAdvice implements ResponseBodyAdvice { - - @Override - public boolean supports(MethodParameter methodParameter, Class aClass) { - return methodParameter.hasMethodAnnotation(ResponseBody.class) || methodParameter.getDeclaringClass().getAnnotation(ResponseBody.class) != null || methodParameter.getDeclaringClass().getAnnotation(RestController.class) != null; - } - - @Override - public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { - if (body instanceof String) { - body = StringEscapeUtils.escapeHtml((String) body); - return body; - } - try { - if (!((Class) body.getClass().getField("TYPE").get(null)).isPrimitive()) { - Map map = new HashMap<>(); - Field[] fields = body.getClass().getDeclaredFields(); - for (Field field: fields) { - field.setAccessible(true); - Object value = field.get(body); - if (value instanceof String) { - value = StringEscapeUtils.escapeHtml((String) value); - } - map.put(field.getName(), value); - } - return map; - } - } - catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - return body; - } -} diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/ESAPI.properties b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/ESAPI.properties new file mode 100644 index 000000000..57ff36173 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/ESAPI.properties @@ -0,0 +1,8 @@ +ESAPI.printProperties=true + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +# ESAPI Encoder +Encoder.AllowMultipleEncoding=false +Encoder.AllowMixedEncoding=false +Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/pom.xml index cc37a455b..17c543546 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/pom.xml @@ -28,5 +28,10 @@ org.springframework.boot spring-boot-starter-web + + + org.owasp.esapi + esapi + diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java index 580af7ca9..79050dc4d 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java @@ -21,6 +21,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; +import org.owasp.esapi.ESAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,7 +68,13 @@ public class GatewayCalleeController { @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) throws UnsupportedEncodingException { LOG.info(URLDecoder.decode(metadataStr, UTF_8)); - return URLDecoder.decode(metadataStr, UTF_8); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return cleanXSS(metadataStr); + } + + private String cleanXSS(String str) { + str = ESAPI.encoder().encodeForHTML(str); + return str; } } diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java deleted file mode 100644 index 7c698a2ef..000000000 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.gateway.example.callee.xss; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Component; - -/** - * filter request aim at defending against XSS - * - * @author Daifu Wu - */ -@WebFilter(urlPatterns = "/*", filterName = "xssFilter") -@Component -public class XssFilter implements Filter { - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); - } -} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java deleted file mode 100644 index 33fba2b39..000000000 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.gateway.example.callee.xss; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.StringEscapeUtils; - -import org.springframework.web.servlet.HandlerMapping; - -/** - * Wrap HttpServletRequest to escape String arguments - * - * @author Daifu Wu - */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { - private byte[] requestBody; - - public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException { - super(request); - BufferedReader reader = request.getReader(); - StringBuilder stringBuilder = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - } - if (stringBuilder.length() > 0) { - String json = stringBuilder.toString(); - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.readValue(json, Map.class); - map.forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - map.put(k, v); - } - }); - json = objectMapper.writeValueAsString(map); - requestBody = json.getBytes(); - } - } - - /** - * Handles arguments annotated by @RequestBody - * - * @return - */ - @Override - public ServletInputStream getInputStream() { - final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody); - return new ServletInputStream() { - @Override - public boolean isFinished() { - return false; - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setReadListener(ReadListener readListener) { - - } - - @Override - public int read() throws IOException { - return byteArrayInputStream.read(); - } - }; - } - - /** - * Handles arguments annotated by @RequestParam - * - * @param name string parameter - * @return - */ - @Override - public String[] getParameterValues(String name) { - String[] values = super.getParameterValues(name); - if (values != null && values.length > 0) { - String[] safeValues = new String[values.length]; - for (int i = 0; i < values.length; i++) { - safeValues[i] = cleanXSS(values[i]); - } - return safeValues; - } - return values; - } - - /** - * Handles arguments annotated by @PathVariable - * - * @param name string parameter - * @return - */ - @Override - public Object getAttribute(String name) { - Object value = super.getAttribute(name); - if (name.equalsIgnoreCase(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE) && value != null && value instanceof Map) { - ((Map) value).forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - ((Map) value).put(k, v); - } - }); - } - return value; - } - - /** - * Handles arguments annotated by @RequestHeader - * - * @param name string parameter - * @return - */ - @Override - public Enumeration getHeaders(String name) { - List list = Collections.list(super.getHeaders(name)); - list = list.stream().map((e) -> { - ObjectMapper objectMapper = new ObjectMapper(); - try { - Map map = objectMapper.readValue(e, Map.class); - map.forEach((k, v) -> { - v = cleanXSS(v); - map.put(k, v); - }); - e = objectMapper.writeValueAsString(map); - } - catch (JsonProcessingException e1) { - e1.printStackTrace(); - } - return e; - }).collect(Collectors.toList()); - return Collections.enumeration(list); - } - - @Override - public String getParameter(String name) { - String value = super.getParameter(name); - if (value != null) { - value = cleanXSS(value); - } - return value; - } - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(getInputStream())); - } - - /** - * Escape string to defend against XSS - * - * @param value string request body - */ - private String cleanXSS(String value) { - value = StringEscapeUtils.escapeHtml(value); - return value; - } -} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/ESAPI.properties b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/ESAPI.properties new file mode 100644 index 000000000..57ff36173 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/ESAPI.properties @@ -0,0 +1,8 @@ +ESAPI.printProperties=true + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +# ESAPI Encoder +Encoder.AllowMultipleEncoding=false +Encoder.AllowMixedEncoding=false +Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml index f96b25e15..41cc550a2 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml @@ -27,5 +27,10 @@ org.springframework.boot spring-boot-starter-web + + + org.owasp.esapi + esapi + diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java index 580af7ca9..79050dc4d 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java @@ -21,6 +21,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; +import org.owasp.esapi.ESAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,7 +68,13 @@ public class GatewayCalleeController { @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) throws UnsupportedEncodingException { LOG.info(URLDecoder.decode(metadataStr, UTF_8)); - return URLDecoder.decode(metadataStr, UTF_8); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return cleanXSS(metadataStr); + } + + private String cleanXSS(String str) { + str = ESAPI.encoder().encodeForHTML(str); + return str; } } diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java deleted file mode 100644 index 7c698a2ef..000000000 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.gateway.example.callee.xss; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Component; - -/** - * filter request aim at defending against XSS - * - * @author Daifu Wu - */ -@WebFilter(urlPatterns = "/*", filterName = "xssFilter") -@Component -public class XssFilter implements Filter { - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); - } -} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java deleted file mode 100644 index c5c7e37de..000000000 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/xss/XssHttpServletRequestWrapper.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.gateway.example.callee.xss; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.StringEscapeUtils; - -import org.springframework.web.servlet.HandlerMapping; - -/** - * Wrap HttpServletRequest to escape String arguments - * - * @author Daifu Wu - */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { - private byte[] requestBody; - - public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException { - super(request); - BufferedReader reader = request.getReader(); - StringBuilder stringBuilder = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - } - if (stringBuilder.length() > 0) { - String json = stringBuilder.toString(); - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.readValue(json, Map.class); - map.forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - map.put(k, v); - } - }); - json = objectMapper.writeValueAsString(map); - requestBody = json.getBytes(); - } - } - - /** - * Handles arguments annotated by @RequestBody - * - * @return ServletInputStream - */ - @Override - public ServletInputStream getInputStream() { - final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody); - return new ServletInputStream() { - @Override - public boolean isFinished() { - return false; - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setReadListener(ReadListener readListener) { - - } - - @Override - public int read() throws IOException { - return byteArrayInputStream.read(); - } - }; - } - - /** - * Handles arguments annotated by @RequestParam - * - * @param name string parameter - * @return - */ - @Override - public String[] getParameterValues(String name) { - String[] values = super.getParameterValues(name); - if (values != null && values.length > 0) { - String[] safeValues = new String[values.length]; - for (int i = 0; i < values.length; i++) { - safeValues[i] = cleanXSS(values[i]); - } - return safeValues; - } - return values; - } - - /** - * Handles arguments annotated by @PathVariable - * - * @param name string parameter - * @return - */ - @Override - public Object getAttribute(String name) { - Object value = super.getAttribute(name); - if (name.equalsIgnoreCase(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE) && value != null && value instanceof Map) { - ((Map) value).forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - ((Map) value).put(k, v); - } - }); - } - return value; - } - - /** - * Handles arguments annotated by @RequestHeader - * - * @param name string parameter - * @return - */ - @Override - public Enumeration getHeaders(String name) { - List list = Collections.list(super.getHeaders(name)); - list = list.stream().map((e) -> { - ObjectMapper objectMapper = new ObjectMapper(); - try { - Map map = objectMapper.readValue(e, Map.class); - map.forEach((k, v) -> { - v = cleanXSS(v); - map.put(k, v); - }); - e = objectMapper.writeValueAsString(map); - } - catch (JsonProcessingException e1) { - e1.printStackTrace(); - } - return e; - }).collect(Collectors.toList()); - return Collections.enumeration(list); - } - - @Override - public String getParameter(String name) { - String value = super.getParameter(name); - if (value != null) { - value = cleanXSS(value); - } - return value; - } - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(getInputStream())); - } - - /** - * Escape string to defend against XSS - * - * @param value string request body - */ - private String cleanXSS(String value) { - value = StringEscapeUtils.escapeHtml(value); - return value; - } -} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/ESAPI.properties b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/ESAPI.properties new file mode 100644 index 000000000..57ff36173 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/ESAPI.properties @@ -0,0 +1,8 @@ +ESAPI.printProperties=true + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +# ESAPI Encoder +Encoder.AllowMultipleEncoding=false +Encoder.AllowMixedEncoding=false +Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/pom.xml b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/pom.xml index 253d3739a..bbf3bdb93 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/pom.xml +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/pom.xml @@ -17,6 +17,11 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-discovery + + + org.owasp.esapi + esapi + diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java index 925031a7b..f42cd969d 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.router.example; +import org.owasp.esapi.ESAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +49,15 @@ public class RouterCalleeController { @PostMapping("/info") public String info(String name, @RequestBody User user) { LOG.info("Discovery Service Callee [{}] is called.", port); - return String.format("Discovery Service Callee [%s] is called. user = %s", port, user); + return String.format("Discovery Service Callee [%s] is called. user = %s", port, cleanXSS(user)); + } + + private User cleanXSS(User user) { + User u = new User(); + String name = ESAPI.encoder().encodeForHTML(user.getName()); + u.setName(name); + u.setAge(user.getAge()); + return u; } } diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java deleted file mode 100644 index 5a96dcd41..000000000 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.example.xss; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Component; - -/** - * filter request aim at defending against XSS. - * - * @author Daifu Wu - */ -@WebFilter(urlPatterns = "/*", filterName = "xssFilter") -@Component -public class XssFilter implements Filter { - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); - } -} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java deleted file mode 100644 index 63cd61f8d..000000000 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.example.xss; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Map; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.StringEscapeUtils; - -import org.springframework.web.servlet.HandlerMapping; - -/** - * Wrap HttpServletRequest to escape String arguments. - * - * @author Daifu Wu - */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { - private byte[] requestBody; - - public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException { - super(request); - BufferedReader reader = request.getReader(); - StringBuilder stringBuilder = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - } - String json = stringBuilder.toString(); - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.readValue(json, Map.class); - map.forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - map.put(k, v); - } - }); - json = objectMapper.writeValueAsString(map); - requestBody = json.getBytes(); - } - - /** - * Handles arguments annotated by @RequestBody. - * - * @return - */ - @Override - public ServletInputStream getInputStream() { - final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody); - return new ServletInputStream() { - @Override - public boolean isFinished() { - return false; - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setReadListener(ReadListener readListener) { - - } - - @Override - public int read() throws IOException { - return byteArrayInputStream.read(); - } - }; - } - - /** - * Handles arguments annotated by @RequestParam. - * - * @param name string parameter - * @return - */ - @Override - public String[] getParameterValues(String name) { - String[] values = super.getParameterValues(name); - if (values != null && values.length > 0) { - String[] safeValues = new String[values.length]; - for (int i = 0; i < values.length; i++) { - safeValues[i] = cleanXSS(values[i]); - } - return safeValues; - } - return values; - } - - /** - * Handles arguments annotated by @PathVariable - * - * @param name string parameter - * @return - */ - @Override - public Object getAttribute(String name) { - Object value = super.getAttribute(name); - if (name.equalsIgnoreCase(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE) && value != null && value instanceof Map) { - ((Map) value).forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - ((Map) value).put(k, v); - } - }); - } - return value; - } - - @Override - public String getParameter(String name) { - String value = super.getParameter(name); - if (value != null) { - value = cleanXSS(value); - } - return value; - } - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(getInputStream())); - } - - /** - * Escape string to defend against XSS - * - * @param value string request content - */ - private String cleanXSS(String value) { - value = StringEscapeUtils.escapeHtml(value); - return value; - } -} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/resources/ESAPI.properties b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/resources/ESAPI.properties new file mode 100644 index 000000000..57ff36173 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/resources/ESAPI.properties @@ -0,0 +1,8 @@ +ESAPI.printProperties=true + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +# ESAPI Encoder +Encoder.AllowMultipleEncoding=false +Encoder.AllowMixedEncoding=false +Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/pom.xml b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/pom.xml index 0dd00a788..2397f4481 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/pom.xml +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/pom.xml @@ -17,6 +17,11 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-discovery + + + org.owasp.esapi + esapi + diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java index b3e365ab8..6d6915b7f 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.router.example; +import org.owasp.esapi.ESAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +50,15 @@ public class RouterCalleeController { @PostMapping("/info") public String info(@RequestParam("name") String name, @RequestBody User user) { LOG.info("Discovery Service Callee [{}] is called.", port); - return String.format("Discovery Service Callee [%s] is called. user = %s", port, user); + return String.format("Discovery Service Callee [%s] is called. user = %s", port, cleanXSS(user)); + } + + private User cleanXSS(User user) { + User u = new User(); + String name = ESAPI.encoder().encodeForHTML(user.getName()); + u.setName(name); + u.setAge(user.getAge()); + return u; } } diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java deleted file mode 100644 index 96e58baaf..000000000 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.example.xss; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Component; - -/** - * filter request aim at defending against XSS - * - * @author Daifu Wu - */ -@WebFilter(urlPatterns = "/*", filterName = "xssFilter") -@Component -public class XssFilter implements Filter { - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest), servletResponse); - } -} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java deleted file mode 100644 index b5a34d6e9..000000000 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/xss/XssHttpServletRequestWrapper.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.example.xss; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Map; - -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang.StringEscapeUtils; - -import org.springframework.web.servlet.HandlerMapping; - -/** - * Wrap HttpServletRequest to escape String arguments - * - * @author Daifu Wu - */ -public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { - private byte[] requestBody; - - public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException { - super(request); - BufferedReader reader = request.getReader(); - StringBuilder stringBuilder = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - } - String json = stringBuilder.toString(); - ObjectMapper objectMapper = new ObjectMapper(); - Map map = objectMapper.readValue(json, Map.class); - map.forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - map.put(k, v); - } - }); - json = objectMapper.writeValueAsString(map); - requestBody = json.getBytes(); - } - - /** - * Handles arguments annotated by @RequestBody - * - * @return - */ - @Override - public ServletInputStream getInputStream() { - final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody); - return new ServletInputStream() { - @Override - public boolean isFinished() { - return false; - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setReadListener(ReadListener readListener) { - - } - - @Override - public int read() throws IOException { - return byteArrayInputStream.read(); - } - }; - } - - /** - * Handles arguments annotated by @RequestParam - * - * @param name string parameter - * @return - */ - @Override - public String[] getParameterValues(String name) { - String[] values = super.getParameterValues(name); - if (values != null && values.length > 0) { - String[] safeValues = new String[values.length]; - for (int i = 0; i < values.length; i++) { - safeValues[i] = cleanXSS(values[i]); - } - return safeValues; - } - return values; - } - - /** - * Handles arguments annotated by @PathVariable - * - * @param name string parameter - * @return - */ - @Override - public Object getAttribute(String name) { - Object value = super.getAttribute(name); - if (name.equalsIgnoreCase(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE) && value != null && value instanceof Map) { - ((Map) value).forEach((k, v) -> { - if (v instanceof String) { - v = cleanXSS((String) v); - ((Map) value).put(k, v); - } - }); - } - return value; - } - - @Override - public String getParameter(String name) { - String value = super.getParameter(name); - if (value != null) { - value = cleanXSS(value); - } - return value; - } - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(getInputStream())); - } - - /** - * Escape string to defend against XSS - * - * @param value string request body - */ - private String cleanXSS(String value) { - value = StringEscapeUtils.escapeHtml(value); - return value; - } -} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/resources/ESAPI.properties b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/resources/ESAPI.properties new file mode 100644 index 000000000..57ff36173 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/resources/ESAPI.properties @@ -0,0 +1,8 @@ +ESAPI.printProperties=true + +ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder + +# ESAPI Encoder +Encoder.AllowMultipleEncoding=false +Encoder.AllowMixedEncoding=false +Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec \ No newline at end of file diff --git a/spring-cloud-tencent-examples/pom.xml b/spring-cloud-tencent-examples/pom.xml index 3395e9b04..17752a148 100644 --- a/spring-cloud-tencent-examples/pom.xml +++ b/spring-cloud-tencent-examples/pom.xml @@ -31,4 +31,14 @@ true + + + + org.owasp.esapi + esapi + 2.1.0.1 + + + +