-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added sanitization filter for request sanitization #78
Changes from 8 commits
4094d3e
9c4b7bc
36b5fdb
7ff2e5d
3caac81
fc6a6f8
0f05622
f9b5c06
808643a
30128bb
d93d616
6fe53b7
458e989
179ec79
2d2dec8
e6541a2
2806314
0f1a202
573ace1
bfe04e8
9c9d440
4af29a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package com.salessparrow.api.filter; | ||
|
||
import jakarta.servlet.Filter; | ||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.FilterConfig; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.ServletRequest; | ||
import jakarta.servlet.ServletResponse; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import org.owasp.html.HtmlPolicyBuilder; | ||
import org.owasp.html.PolicyFactory; | ||
|
||
import com.salessparrow.api.lib.wrappers.SanitizedRequestWrapper; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.util.Enumeration; | ||
|
||
/** | ||
* Class to sanitize the request | ||
*/ | ||
public class SanitizationFilter implements Filter { | ||
|
||
private SanitizedRequestWrapper sanitizedRequest; | ||
|
||
private final PolicyFactory policy = new HtmlPolicyBuilder().toFactory(); | ||
|
||
@Override | ||
public void init(FilterConfig filterConfig) { | ||
} | ||
|
||
/** | ||
* Method to sanitize the request | ||
* @param servletRequest - Servlet request object | ||
* @param servletResponse - Servlet response object | ||
* @param chain - Filter chain - Filter chain | ||
* @throws IOException - IOException | ||
* @throws ServletException - ServletException | ||
* @return void | ||
*/ | ||
@Override | ||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) | ||
throws IOException, ServletException { | ||
if (!(servletRequest instanceof HttpServletRequest)) { | ||
throw new ServletException("Can only process HttpServletRequest"); | ||
} | ||
HttpServletRequest request = (HttpServletRequest) servletRequest; | ||
sanitizeRequestBody(request); | ||
sanitizeRequestParams(request); | ||
sanitizeRequestHeaders(request); | ||
|
||
chain.doFilter(sanitizedRequest, servletResponse); | ||
} | ||
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Method to sanitize the request body | ||
* @param request - Servlet request object | ||
* @return void | ||
*/ | ||
private void sanitizeRequestBody(HttpServletRequest request) { | ||
String originalBody = getRequestBody(request); | ||
String sanitizedBody = sanitizeHtml(originalBody); | ||
this.sanitizedRequest = new SanitizedRequestWrapper(request, sanitizedBody); | ||
} | ||
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Method to sanitize the request params | ||
* @return void | ||
*/ | ||
private void sanitizeRequestParams(HttpServletRequest request) { | ||
request.getParameterMap().forEach((key, values) -> { | ||
for (int index = 0; index < values.length; index++) { | ||
String sanitizedValue = sanitizeHtml(values[index]); | ||
this.sanitizedRequest.setParameter(key, sanitizedValue); | ||
} | ||
}); | ||
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/** | ||
* Method to sanitize the request headers | ||
* @return void | ||
*/ | ||
private void sanitizeRequestHeaders(HttpServletRequest request) { | ||
Enumeration<String> headerNames = request.getHeaderNames(); | ||
|
||
while (headerNames != null && headerNames.hasMoreElements()) { | ||
String headerName = headerNames.nextElement(); | ||
Enumeration<String> headerValues = request.getHeaders(headerName); | ||
|
||
while (headerValues != null && headerValues.hasMoreElements()) { | ||
String headerValue = headerValues.nextElement(); | ||
String sanitizedValue = sanitizeHtml(headerValue); | ||
this.sanitizedRequest.setHeader(headerName, sanitizedValue); | ||
} | ||
} | ||
kreloaded marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/** | ||
* Method to get the request body | ||
* @param request - Servlet request object | ||
* @return String - Request body | ||
*/ | ||
private String getRequestBody(HttpServletRequest request) { | ||
try { | ||
BufferedReader reader = request.getReader(); | ||
String line; | ||
// TODO: Consider using a more efficient way to read the request body, such as | ||
// streaming | ||
StringBuilder requestBody = new StringBuilder(); | ||
while ((line = reader.readLine()) != null) { | ||
requestBody.append(line); | ||
} | ||
return requestBody.toString(); | ||
} | ||
catch (IOException e) { | ||
throw new RuntimeException("Error reading request body: ", e.getCause()); | ||
} | ||
Comment on lines
+104
to
+117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The BufferedReader is not closed after use which can lead to resource leaks. Always close resources in a finally block or use try-with-resources statement. - BufferedReader reader = request.getReader();
- String line;
- StringBuilder requestBody = new StringBuilder();
- while ((line = reader.readLine()) != null) {
- requestBody.append(line);
- }
- return requestBody.toString();
+ try (BufferedReader reader = request.getReader()) {
+ String line;
+ StringBuilder requestBody = new StringBuilder();
+ while ((line = reader.readLine()) != null) {
+ requestBody.append(line);
+ }
+ return requestBody.toString();
+ } catch (IOException e) {
+ throw new RuntimeException("Error reading request body: ", e.getCause());
+ } |
||
} | ||
Comment on lines
+104
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method |
||
|
||
/** | ||
* Method to sanitize the html | ||
* @param input - Input string | ||
* @return String - Sanitized string | ||
*/ | ||
private String sanitizeHtml(String input) { | ||
String sanitizedInput = policy.sanitize(input); | ||
return sanitizedInput; | ||
} | ||
|
||
/** | ||
* Method to destroy the filter | ||
*/ | ||
@Override | ||
public void destroy() { | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filter should be able to handle all types of
ServletRequest
. Instead of throwing an exception when the request is not an instance ofHttpServletRequest
, consider skipping the sanitization process and just pass the request to the next filter in the chain.