8

I have a spring boot application with a GET service.

@RequestMapping(value = "/abc/track/{type}", method = RequestMethod.GET)

    public void DummFunc(                            
          @RequestParam(value="subs", required = false) String sub,
,  HttpServletResponse response) {}

value for subs is an encoded value.

If I pass following as value to parameter subs

{%22endpoint%22:%22https://def.abc.com/tyu/send/eD3vpGNQW28:APA91bHOo8rYrV0xccdQz3okjZJG-QGrJX8LG6ahJnEUpMNfGedqi3hJxQsJx_8BMbH6oDjaSPPEXqzNWchWrGSkhuTkSdemikkys1U22Ipd7MsRw0owWbw89V2fslIVAJ6G5lkyvYuQ%22,%22expirationTime%22:null,%22keys%22:{%22p256dh%22:%22BK0pktn50CMsTQtqwdPlKlJtdFs0LFeXX14T1zgoz6QWnvSTp5dxtChnUP5P1JX0TsjcopbdPKyN31HfABMUyic%22,%22auth%22:%22qbO_z0vGao9wD-E5g8VU-A%22}}

It fails to capture the request and control does not come inside of the function.

If we instead pass as value to parameter subs:

%7B%22endpoint%22:%22https://def.abc.com/tyu/send/dX5q5eV7hFQ:APA91bHib-0QXrMzjatcvTR_uaIeeJK8lf6GmXUC9Jxv0Oxth-BzD4GmWnd4-YpDZv8qSFZ0eSg9mB2YkRvkc5ezdXW5KeaHjuQZfdyDxyBXjJgE-25Xbtlk37pdm8vfLk20k0k_VxW9%22,%22expirationTime%22:null,%22keys%22:%7B%22p256dh%22:%22BCCvcBLpRqp4u0auP688_MUJLsAiwWlQSn5kpyl8YVsEo_J-KpSdnhCmVIE_BhDXBcFYflPK52hqhYf3EaOCyuY%22,%22auth%22:%22iKuW_ESkCZnubWcQu_JK8w%22%7D%7D

It works fine.

  1. Why is this happening? What's wrong with first encoding?

  2. Since server is not able to handle the request, it returns 400. I need to capture such requests and then handle them by encoding them properly. What can be way forward?

I am new to Spring boot/Spring and Java itself. Would be great if I can get some insight.

Also, I can decode both of them online here without any issues- https://www.urldecoder.org/

Edit: Basically, the request that has issue getting through has { and } instead of %7Band %7D.

My question is instead of application failing with 400 bad request,how do I capture such requests in my app, encode them properly and then process them.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
systemdebt
  • 4,589
  • 10
  • 55
  • 116

4 Answers4

3

This is not related to Java nor the Spring itself but the HTML URL Encoding Reference. URLs can only be sent over the Internet using the ASCII character set.

The unsafe characters are defined in the beginning of RFC-1738 and here is the list:

" < > # % { } | \ ^ ~ [ ] ` including the blank/empty space.

Aside from those, there are also reserved characters where belong the following ones and are used to distinguish the parameters, the key-value representation, the port etc.

; / ? : @ = &

The unsafe characters you have used are { and } which are equal to %7B and %7D.


Essentially, you should not be concerned about the data the client sends you in the way you describe. The server must demand the correct form and URL passed. Although, the browsers and REST clients encode those characters automatically, sending them programmatically might cause errors. The only two available solutions in Spring I am aware of is through registering the CharacterEncodingFilter bean (already answered) or the Spring-Boot configuration:

spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

You need to enable the encoding first and force on HTTP requests and responses.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • 1
    Here;s what I did: spring.http.encoding.charset=UTF-8 spring.http.encoding.enabled=true spring.http.encoding.force=true . -- added this in application.properties. Also, tried adding CharacterEncodingFilter in main file but that did not change anything either – systemdebt Jan 03 '19 at 12:47
2

spring-boot is very much concerned about security. Adding double quote / single quotes or either escaping won't work I guess.

Please go through : https://www.rfc-editor.org/rfc/rfc1738

I think you should try the manual encoding { to %7B and } to %7D

Unsafe:

Characters can be unsafe for a number of reasons. The space
character is unsafe because significant spaces may disappear and
insignificant spaces may be introduced when URLs are transcribed or
typeset or subjected to the treatment of word-processing programs.
The characters "<" and ">" are unsafe because they are used as the
delimiters around URLs in free text; the quote mark (""") is used to
delimit URLs in some systems. The character "#" is unsafe and should always be encoded because it is used in World Wide Web and in other
systems to delimit a URL from a fragment/anchor identifier that might follow it. The character "%" is unsafe because it is used for
encodings of other characters. Other characters are unsafe because
gateways and other transport agents are known to sometimes modify
such characters. These characters are "{", "}", "|", "", "^", "~",
"[", "]", and "`".

All unsafe characters must always be encoded within a URL. For
example, the character "#" must be encoded within URLs even in
systems that do not normally deal with fragment or anchor
identifiers, so that if the URL is copied into another system that
does use them, it will not be necessary to change the URL encoding.

Community
  • 1
  • 1
smilyface
  • 5,021
  • 8
  • 41
  • 57
  • Ahh, I understand that. But if manual encoding is not upto us and if we can intercept requests, look for those characters and encode them in the code, that would be elegant I guess. If we do not want to go manual encoding way, what can be done? – systemdebt Jan 02 '19 at 12:35
  • By the word `manual` I mean to do it by some code. Get your URL and find-and-replace curly braces with the unicode with the help of a method/function. I didn't mean to do it by hand :) Well I dont know if there is any other way or not. As of my knowledge, you do not have any other way around !! – smilyface Jan 02 '19 at 12:37
  • Ahh. In that case, where do I intercept the request and change it in the application code? I am very new to spring boot, would be great if you can elaborate a bit – systemdebt Jan 02 '19 at 12:40
  • You know it already. You have mentioned `If we instead pass as value to parameter subs`. You should do the same to encode it with a method where you did it manually in hand (the place from where you send to the API). Hope that is clear. – smilyface Jan 02 '19 at 12:42
  • right. but i would ideally like to handle it in my spring boot application instead of the place it is getting called from. :) Do we have a way? – systemdebt Jan 02 '19 at 12:48
  • Oh yea, you are right. That might be possible. Need to check. – smilyface Jan 02 '19 at 12:49
  • Would be great if I can get a direction along the same lines. being new to spring boot, I lack direction at the moment :). Thanks – systemdebt Jan 02 '19 at 12:59
  • After thinking for some time, security should be enabled before sending it , right ? Anyway can you try @Encoded in the param ? – smilyface Jan 02 '19 at 13:01
  • See the output first and try it https://www.concretepage.com/webservices/resteasy-3/rest-web-service-jax-rs-encoded-annotation-example-with-resteasy-3 – smilyface Jan 02 '19 at 13:02
  • Are you registered in https://chat.stackoverflow.com ? Please register and come in chat. – smilyface Jan 02 '19 at 13:53
  • Hmm.. I am also getting some exception there – smilyface Jan 03 '19 at 12:46
  • Please go through : https://stackoverflow.com/questions/43252750/how-to-send-json-as-a-parameter-in-url-using-spring-resttemplate Using UriComponentsBuilder you can encode the url , try it. – smilyface Jan 03 '19 at 12:59
1

Generally this issue comes when the APP server like Undertow, tomcat, Jboss which is hosting your Springboot application does not allow some special characters, which can very from Server to server. This is done to secure URLs and no one can send some special characters to the server to compromise with its functionality.

If still want to allow special characters so that those can reach to controller in Springboot application, you need to allow this configuration in APP server. e.g. this is the configuration required in Undertow server to allow special characters in URL:

@Configuration
public class HttpConfig {
    @Bean
    public UndertowServletWebServerFactory servletWebServerFactory() {
        UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
        factory.addBuilderCustomizers((UndertowBuilderCustomizer) builder ->
                builder.setServerOption(UndertowOptions.ALLOW_UNESCAPED_CHARACTERS_IN_URL, Boolean.TRUE));
        return factory;
    }
}

In order to make springboot work well with UTF-8 encoding/decoding of rest URLs, add this configuration in application.properties file, for springboot version 2.6:

server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.force-request=true
server.servlet.encoding.force-response=true

Best approach is to encode special characters in the client application which is calling this rest URL to comply with security principles

0

Due to Tomcat upgraded their security in URL param. Please find possible solution https://github.com/bohnman/squiggly/issues/42#issuecomment-386658525

Meet Patel
  • 482
  • 4
  • 12