java - Order of request parameters for content-type application/x-www-form-urlencoded in Spring MVC -
i working on web service consumes requests of type application/x-www-form-urlencoded
. here example of such request body:
loginid=tester&action=add&requestid=987654321&data=somedata
the request signed (with sha1withrsa
) client , signature sent http header.
the thing parameters in different order, example:
action=add&loginid=tester&requestid=987654321&data=somedata
therefor verifying signature fails.
interesting occurs if content-type
application/x-www-form-urlencoded
, if switch content-type
text/plain
works perfectly.
i've used different types of clients (even monitored traffic using tcp monitor) , sure issue not caused client app.
here part of custom message converter (note directly printing incoming request console):
@override protected object readinternal(class<?> clazz, httpinputmessage inputmessage) throws ioexception, httpmessagenotreadableexception { log.debug("> readinternal - message object"); inputstream inputstream = inputmessage.getbody(); byte[] bytes = ioutils.tobytearray(inputstream); string body = new string(bytes, charset); log.debug("body: {}", body); }
and spring mvc configuration:
<bean class="org.springframework.web.servlet.mvc.annotation.defaultannotationhandlermapping" /> <bean class="org.springframework.web.servlet.mvc.annotation.annotationmethodhandleradapter"> <property name="messageconverters"> <array> <bean class="converter.nvphttpmessageconverter"> <property name="charset" value="utf-8" /> <property name="nvpconverter" ref="nvpconverter" /> </bean> </array> </property> </bean>
i believe spring somehow detects content type application/x-www-form-urlencoded
, uses kind of pre-processing. assumption correct? can turned off?
i'm using tomcat 7.
your message converter not work native request httpinputmessage
parameter. spring class.
the inputmessage.getbody()
problem arises. default, servletserverhttprequest
(another spring class) used has in getbody()
method:
public inputstream getbody() throws ioexception { if (isformsubmittal(this.servletrequest)) { return getformbody(this.servletrequest); } else { return this.servletrequest.getinputstream(); } }
which delegates private implementation this:
private inputstream getformbody(httpservletrequest request) throws ioexception { bytearrayoutputstream bos = new bytearrayoutputstream(); writer writer = new outputstreamwriter(bos, form_charset); map<string, string[]> form = request.getparametermap(); (iterator<string> nameiterator = form.keyset().iterator(); nameiterator.hasnext();) { string name = nameiterator.next(); list<string> values = arrays.aslist(form.get(name)); (iterator<string> valueiterator = values.iterator(); valueiterator.hasnext();) { string value = valueiterator.next(); writer.write(urlencoder.encode(name, form_charset)); if (value != null) { writer.write('='); writer.write(urlencoder.encode(value, form_charset)); if (valueiterator.hasnext()) { writer.write('&'); } } } if (nameiterator.hasnext()) { writer.append('&'); } } writer.flush(); return new bytearrayinputstream(bos.tobytearray()); }
this problem happens:
... map<string, string[]> form = request.getparametermap(); ...
you mentioned use tomcat 7 in case request.getparametermap()
returns org.apache.catalina.util.parametermap
hashmap
makes no specific guarantees content order. iterating through parameters , recomposing request body messes original order of parameters.
spring flexible framework , you might try fixing effects, not cause. , cause signing method fragile.
for example, should these cause different signatures?
aaa=1&bbb=2 bbb=2&aaa=1
or these?
aaa=hello+world aaa=hello%20world
a server not care order of parameters , different ways of encoding values end same decoded value. reason, when signing something, perform normalization first. can borrow ideas url normalization or available apis twitter's.
you notice sorting parameters before signing important step remove current problem.
Comments
Post a Comment