I have to implement a filter to prevent XSS attack in my Liferay Portal. I have read a lot of answers about it, so I used an HttpServletRequestWrapper to add sanitized parameters to my request. My filter works properly: debugging the code I realized that the filter takes the parameter and sanitized it.
My problem is that in the processAction of a portlet I am not able to retrieve the sanitized parameter using request.getParameter() but I always get the old not sanitized parameter.
For example, suppose I have a portlet with a simple form like this:
As you can see in the input field there is a b tag to sanitize. When the form is submitted my filter is invoked and it throws the doFilter() method.
My doFilter method iterates over all parametes doing sanitation. Then I add them in my WrappedRequest:
/*
* Did it make any difference?
*/
if (!Arrays.equals(processedParams, params)) {
logger.info("Parameter: " + params[0] + " sanitized with: " + processedParams[0] );
/*
* If so, wrap up the request with a new version that will return the trimmed version of the param
*/
HashMap<String, String[]> map = new HashMap<>();
map.put(name, processedParams);
final HttpServletRequestWrapper newRequest = new ExtendedRequestWrapper(httpServletRequest,map);
/*
* Return the wrapped request and forward the processing instruction from
* the validation rule
*/
return newRequest;
My class ExtendedRequestWrapper implements getparameter method:
public class ExtendedRequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> modifiableParameters;
private Map<String, String[]> allParameters = null;
public ExtendedRequestWrapper(final HttpServletRequest request,
final Map<String, String[]> additionalParams)
{
super(request);
this.modifiableParameters = new TreeMap<String, String[]>();
this.modifiableParameters.putAll(additionalParams);
}
#Override
public String getParameter(final String name)
{
String[] strings = getParameterMap().get(name);
if (strings != null)
{
return strings[0];
}
return super.getParameter(name);
}
#Override
public Map<String, String[]> getParameterMap()
{
if (this.allParameters == null)
{
this.allParameters = new TreeMap<String, String[]>();
this.allParameters.putAll(super.getParameterMap());
this.allParameters.putAll(modifiableParameters);
}
//Return an unmodifiable collection because we need to uphold the interface contract.
return Collections.unmodifiableMap(allParameters);
}
#Override
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(getParameterMap().keySet());
}
#Override
public String[] getParameterValues(final String name)
{
return getParameterMap().get(name);
}
}
Now, when I try to access to sanitized params in my processAction() I get the old value, that one not sanitized:
#Override
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException {
String azione = request.getParameter("MyXSSaction");
if(azione.equals("XSSAttack")) {
String descr = req.getParameter("mydescr");
}
}
How can I solve?
You should not do this generically in your input handling. First of all, there is no XSS in <b>, as the second S in XSS is for 'scripting' - and <b> doesn't contain any scripts.
Second, a general and thorough application of such a filter will effectively keep you from adding proper web content, blog articles and other content, where formatting is legitimately done.
Third - let's say you have a random book management system: Why shouldn't people be able to enter Let x < 5 as a book title, or even <script>alert('XSS')</script> and what to do against it - wouldn't they be proper book titles? In fact, they'd be proper data, and you want to escape them when you display.
There might be an argument for sanitizing (like Liferay's AntiSamy plugin does) certain elements if they're meant to be displayed as HTML. But anything else just needs to be properly escaped during output.
Another way to put it: Those parameters are only dangerous if you incorrectly don't escape them when they're shown in HTML pages - but if you embed them in a text/plain email body, they're completely harmless.
Related
I need to add support for passing field values to a form via a URL parameter when viewing a form which will be used to populate values into the form when it loads. should support a JSON formatted value of field names and values. Example:
https://web/form/view?id=1&data={'fieldname':'value'}
#RequestMapping(value = "/form/view", method = RequestMethod.GET)
public ModelAndView viewDomainForm(HttpSession session, #ModelAttribute("command") FormBean inFormBean) {
Form form = formService.getForm(inFormBean.getId());
FormInstance formInstance = formInstanceService.createFormInstance(form);
String formInstanceId = (String) session.getAttribute("formInstanceId");
if (formInstanceId != null && formInstanceId.length() > 0) {
formInstanceService.deleteFormInstanceById(formInstanceId);
}
formInstanceId = formInstance.getId();
session.setAttribute("formInstanceId", formInstanceId);
FormBean formBean = prepareFormBean(form);
formBean.setEmbed(inFormBean.isEmbed());
formBean.setFormInstanceId(formInstance.getId());
Map<String, Object> model = new HashMap<String, Object>();
model.put("externalBaseUrl", configurationService.getValue("core.external.url.base"));
model.put("fromTaskList", false);
model.put("form", formBean);
model.put("flow", new FlowBean());
model.put("task", new TaskBean());
return new ModelAndView("form-viewer", model);
}
I have this method for viewing. what would be the best way to Populate fields from URL parameter?
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
// this is the value that will populate into the form when it loads.
First question, why not use POST with the JSON in the request body?
If the JSON will be large, then you will run in a URL limitation problem. And you have to encode your URL with % and different delimiters which will make it even less debuggable.
But it is doable.
Let's say that you correctly encoded your URL and the JSON is as a query param.
What you could do is receive it and either traverse it and create/populate your form or map it to an object and use that:
public ModelAndView viewDomainForm(... #RequestParam("data") String jsonDataInUrl...)
{
// Work with jsonDataInUrl either through parsing it or through transforming it into a java bean.
...
}
Here is a URL decoder/encoder in case you need it.
I want to invoke series of API calls in Java. The requirement is that some API's response will be used in the subsequent API call's request. I can achieve this using certain loops. But I want to use a design pattern in such a way that the implementation is generic. Any help?
Chain of responsibility doesn't serve my need as I won't be knowing what is my request context in the beginning.
String out = null;
Response res = execute(req);
out += res.getOut();
req.setXYZ(res.getXYZ);
Response res = execute(req);
out += res.getOut();
req.setABC(res.getABC);
Response res = execute(req);
out += res.getOut();
System.out.println("Final response::"+out);
The following come to mind:
For function calls that return an object: never return null.
For function calls that do not (otherwise) return anything: return this.
Accept functional interfaces in your API so users can customize behavior
For stateful objects that expose API as described above, provide a Builder pattern so users don't end up choosing between constructors
All methods of the Builder described must be void, and therefore return this
You can create a ResponseStringBuilder class that takes a Function<Response,String> to get the String from the Response.
public ResponseStringBuilder {
private Request request;
public StringBuilder resultBuilder = new StringBuilder();
public ResponseBuilder(Request req) {
this.request = req;
}
public ResponseStringBuilder fromExtractor(Function<Request, Response> getResponse, Function<Response,String> extract) {
Response response = getResponse.apply(request);
resultBuilder.append(extract.apply(response));
return this;
}
public String getResult() {
return resultBuilder.toString();
}
}
That would make your calls
ResponseStringBuilder builder = new ResponseStringBuilder(req);
#SuppressWarnings("unchecked")
Function<Response,String> extractors = new Function[] {
Response::getABC, Response::getXYZ
};
for (Function<Response,String> ext : extractors) {
builder = builder.fromExtractor(this::execute, ext);
}
System.out.println("final response: " + builder.getResult());
Not sure if the array declaration actually compiles, but it should work with minor modification and you get the gist.
You can use a CompletableFuture to implement promises in Java. The problem is, you're trying to pass two different things down the 'pipeline:' the request, which is mutable and (sometimes) changes, and the result, which is accumulated over the course of the calls.
I've gotten around that by creating a class called Pipe which has a request, and the accumulator for the results so far. It has getters for both, and it has a few convenience methods to return a new object with the accumulated results or even mutate the request and accumulate in one call. This makes the code of the API chaining a lot cleaner.
The with* methods after the fields, constructor, and getters are the ones that handle the accumulation and mutation. The chain method puts it all together:
import java.util.concurrent.CompletableFuture;
public class Pipe {
private Request req;
private String out;
public Pipe(Request req, String out) {
this.req = req;
this.out = out;
}
public Request getReq() {
return req;
}
public String getOut() {
return out;
}
public Pipe with(String data) {
return new Pipe(req, out + data);
}
public Pipe withABC(String abc, String data) {
req.setABC(abc);
return new Pipe(req, out + data);
}
public Pipe withXYZ(String xyz, String data) {
req.setXYZ(xyz);
return new Pipe(req, out + data);
}
public static void chain(Request req) throws Exception {
var promise = CompletableFuture.supplyAsync(() -> new Pipe(req, ""))
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.withABC(res.getABC(), res.getOut());
})
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.withXYZ(res.getXYZ(), res.getOut());
})
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.with(res.getOut());
});
var result = promise.get().getOut();
System.out.println(result);
}
public static Response execute(Request req) {
return req.getResponse();
}
}
Because it runs asynchronously, it can throw InterruptedException, and it can also throw ExecutionException if something else breaks. I don't know how you want to handle that, so I just declared chain to throw.
If you wanted to apply n operations in a loop you have to keep reassigning the promise back, as follows:
var promise = CompletableFuture.supplyAsync(() -> new Pipe(req, ""));
for (...) {
promise = promise.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.with(res.getOut());
});
}
var result = promise.get().getOut();
I've used Java 10 type inference with var here, but the types of promise and result would be CompletableFuture<Pipe> and String, respectively.
(Note: it might be better to make Request immutable and pass a new, altered one down the pipeline rather than mutating it. On the other hand, you could also wrap a StringBuilder instead of a String, and have the data you're accumulating be mutable, too. Right now it's an odd mix of mutable and immutable, but that matches what your code was doing.)
Thanks all for the inputs, finally I landed on one solution which meets my need. I used one Singleton for the request execution. For each type of command, there will a set of requests to be executed in one particular order. Each command is having a particular order of requests to be executed which I stored in an array with request's unique ID. Then kept the array in a map against command name.
In a loop, I ran the array and executed, after each iteration I keep setting the response back into the request object and eventually prepared the output response.
private static Map<RequestAction,String[]> actionMap = new HashMap<RequestAction, String[]>();
static{
actionMap.put(RequestAction.COMMAND1,new String[]{WebServiceConstants.ONE,WebServiceConstants.TWO,WebServiceConstants.FOUR,WebServiceConstants.THREE});
actionMap.put(RequestAction.THREE,new String[]{WebServiceConstants.FIVE,WebServiceConstants.ONE,WebServiceConstants.TWO});}
public Map<String,Object> execute(ServiceParam param) {
String[] requestChain = getRequestChain(param);
Map<String,Object> responseMap = new HashMap<String, Object>();
for(String reqId : requestChain) {
prepareForProcessing(param, tempMap,responseMap);
param.getRequest().setReqId(reqId);
//processing the request
tempMap = Service.INSTANCE.process(param);
//prepare responseMap using tempMap
param.setResponse(response);
}
return responseMap;
}
This question is a result of some work I'm doing with the Spring Security Oauth2 library. I've set up an oauth2 authorization server and an oauth2 resource server, the latter of which is meant to authorize based on access tokens.
The problem is that normally access tokens are passed in a header, but the big client we're setting this up for wants to pass the access token in a JSON request body. There's an interface you can use to set up custom access token extraction, but it looks like this:
public interface TokenExtractor {
/**
* Extract a token value from an incoming request without authentication.
*
* #param request the current ServletRequest
* #return an authentication token whose principal is an access token (or null if there is none)
*/
Authentication extract(HttpServletRequest request);
}
So, as best I can tell, all I have access to is the raw HTTPServletRequest, from which I need to deserialize the request and extract the access token.
Further complicating things, though, is the fact that the request body also contains other parameters needed for processing, so I want to deserialize it to a DTO class that I pass into my controller, something like so:
#RequestMapping("/oauth/someresource")
#Transactional
public Map<String, String> resource(#AuthenticationPrincipal UserDetails userDetails,
#RequestBody ClientRequestDto clientRequestDto) {
// Do some processing based on the request dto
}
I tried manually deserializing the request in the token extractor, but then I get an error "java.lang.IllegalStateException: getReader() has already been called for this request".
I was brainstorming a few possible solutions that I could research, and so far I've come up with:
find a way to reset the input stream
deserialize the object in the Token Extractor, attach it to the raw request object, and just access the raw request object in my controller instead of using #RequestBody
like 2, but find a way to add a custom deserializer that fetches the object attached to the raw request instead of processing the request's input stream.
Anyways, those are just some thoughts, if anyone has any ideas in terms of an elegant way of solving this, I'd greatly appreciate it.
EDIT: I did find this question which is similar: Spring reading request body twice, and the last answer did have one possible solution (creating a decorator request class that allows multiple input stream reads and creating a filter early on in the filter chain that wraps the HttpServletRequest). It seems workable, but a little heavy duty, so I'll leave this up to see if anyone has any other ideas as well.
So I ended up finding yet another question that addressed this issue that I didn't see before posting (How can I read request body multiple times in Spring 'HandlerMethodArgumentResolver'?). That one also suggested creating a decorator around the HttpServletRequest, so I adapted the info from http://www.myjavarecipes.com/how-to-read-post-request-data-twice-in-spring/, adding a protection against large requests.
Here's what I came up with, in case anyone has any feedback:
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
// We include a max byte size to protect against malicious requests, since this all has to be read into memory
public static final Integer MAX_BYTE_SIZE = 1_048_576; // 1 MB
private String _body;
public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
_body = "";
InputStream bounded = new BoundedInputStream(request.getInputStream(), MAX_BYTE_SIZE);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(bounded));
String line;
while ((line = bufferedReader.readLine()) != null){
_body += line;
}
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
return new ServletInputStream() {
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 BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
I used the following configuration:
#Bean
FilterRegistrationBean multiReadFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
MultiReadRequestFilter multiReadRequestFilter = new MultiReadRequestFilter();
registrationBean.setFilter(multiReadRequestFilter);
registrationBean.setOrder(SecurityProperties.DEFAULT_FILTER_ORDER - 2);
registrationBean.setUrlPatterns(Sets.newHashSet("/path/here"));
return registrationBean;
}
We are using a very simple setup of #RepositoryRestResource on top of a PagingAndSortingRepository connected to a postgres database. Also we have configured spring.jackson.property-naming-strategy=SNAKE_CASE to return pretty json. It was all fine and dandy until we started sorting. As we have discovered - sorting requires us to provide the actual class field names (which we of course have in camel case):
get("/thing?sort=dateCreated,desc")
And when we try to do javascript friendly
get("/thing?sort=date_created,desc")
it fails miserably because jpa tries to split the parameter by the underscore.
Is there a simple way to have the path params the same format as we have them in the json that we are returning?
There is a bug for this - DATAREST-883. It was fixed and released. But then, due to regressions (DATAREST-909) this has been dropped in the very next release. I asked them on Github if they plan to have this again as this has bitten me in the past as well. We'll see what they have to say about this.
For now you can:
leave it be
go with the camel case property names
work around this (e.g. go with Alan Haye's answer) - this seems fragile IMHO, but probably will do in a short term.
The status of the feature in the spring-boot versions I've tested with:
1.4.0 (spring-data-rest 2.5.2): not yet implemented
1.4.1 (spring-data-rest 2.5.3): works -> code
1.4.2 (spring-data-rest 2.5.5): dropped
It is unclear whether you can do this in some Spring Data Rest specific way however you should be able to handle it by means of a standard Servlet filter which would look something like the below:
public class SortParameterConversionFilter extends GenericFilterBean {
// as we are extending Spring's GenericFilterBean
// you can then *possibly* inject the RepositoryRestConfiguration
// and use RepositoryRestConfiguration#getSortParamName
// to avoid hard coding
private static final String SORT_PARAM_KEY = "sort";
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if (shouldApply(request)) {
chain.doFilter(new CollectionResourceRequestWrapper(request), res);
} else {
chain.doFilter(req, res);
}
}
/**
*
* #param request
* #return True if this filter should be applied for this request, otherwise
* false.
*/
protected boolean shouldApply(HttpServletRequest request) {
return request.getServletPath().matches("some-pattern");
}
/**
* HttpServletRequestWrapper implementation which allows us to wrap and
* modify the incoming request.
*
*/
public class CollectionResourceRequestWrapper extends HttpServletRequestWrapper {
public ResourceRequestWrapper(HttpServletRequest request) {
super(request);
}
#Override
public String getParameter(final String name) {
if (name.equals(SORT_PARAM_KEY)) {
String [] parts = super.getParameter(SORT_PARAM_KEY).split(",");
StringBuilder builder = new StringBuilder();
int index = 0;
for (String part : parts) {
// using some mechanism of you choosing
// convert from underscore to camelCase
// Using the Guava library for example
String convertedPart = CaseFormat.LOWER_UNDERSCORE.to(
CaseFormat.LOWER_CAMEL, part);
++index;
builder.append(convertedPart).append(index < parts.length ? "," : "");
}
return builder.toString();
}
return super.getParameter(name);
}
}
}
I'm trying to catch key value pairs in a Map parameter at spring MVC side. This looks to me to be something simple but I can't wrap my head around it at the moment. Take following url
www.goudengids.be.localhost:8080/ms/view/sendContactForm.ajah?pageId=711408&listingId=685592&siteId=353009&url=http%3A%2F%2Fwww.goudengids.be.localhost%3A8080%2Fms%2Fms%2Fkbc-bank-versicherung-recht-4780%2Fms-353009-preview%2F&moduleId=65920100&mySiteId=353009&pageShortId=1&prefills[Naam]=janneke
You'll notice at the end my latest attempt to get this working prefills[Naam]=janneke. I like to catch this in the following controller.
public String getContactForm(#RequestParam(required = true) Long moduleId, #RequestParam(required = true) String url, #RequestParam(required=false) Map<String,String> prefills, Long mySiteId, Integer pageShortId,
DefaultPageParameters defaultPageParameters, ModelMap model, HttpServletRequest request, HttpServletResponse response, Locale locale) throws Exception {
However I'm recieving all parameters in the request in my prefills variable instead of just Naam,janneke. Is this even possible what I'm attempting or should I go with a large string with a token to tokenize ?
prefills=naam:janneke|title:maan|subject:space
I couldn't find a clean way out, so I went for the pragmatic solution
public String getContactForm(#RequestParam(required = true) Long moduleId, #RequestParam(required = true) String url, #RequestParam(required=false) List<String> prefills, Long mySiteId, Integer pageShortId,
DefaultPageParameters defaultPageParameters, ModelMap model, HttpServletRequest request, HttpServletResponse response, Locale locale) throws Exception {
private void prefillFieldsWithData(List<String> prefills, ModelMap model, BasicContactFormVo contactFormVo) {
if(prefills != null && !prefills.isEmpty()){
Map<String, String> valuesOfCustomFields = new HashMap<String, String>();
List<ContactFormElementVo> customFormElements = contactFormVo.getCustomFormElements();
for (String prefillData : prefills) {
if(prefillData.contains("|")){
String[] prefillFieldData = prefillData.split("|");
for (ContactFormElementVo contactFormElementVo : customFormElements) {
if(contactFormElementVo.getLabel().equals(prefillFieldData[0])){
valuesOfCustomFields.put("cfe"+contactFormElementVo.getId().toString(), prefillFieldData[1]);
break;
}
}
}
}
model.addAttribute("customFieldValues",valuesOfCustomFields);
}
}
It's a bit sad I have to do it this way, but it seems Spring has a generic way of detecting a Map as request parameter and filling it with all parameters in the request. There is no way around that except overloading that class which I rather do not considering it's part of the entire MVC mechanic.
I call the controller now with following URL. It works just ... meh ... not my favorite solution
http://www.goudengids.be.localhost:8080/ms/view/sendContactForm.ajah?pageId=711408&listingId=685592&siteId=353009&url=http%3A%2F%2Fwww.goudengids.be.localhost%3A8080%2Fms%2Fms%2Fkbc-bank-versicherung-recht-4780%2Fms-353009-preview%2F&moduleId=65920100&mySiteId=353009&pageShortId=1&prefills=Naam|janneke%20zag%20eens%20pruimen&prefills=E-mail|maan