How can i securely implement CSRF tokens in java - java

Problem Behind the question :
I was trying to prevent csrf attack in my java web application,In order to implement it i have tried with implementation of X-CSRF-Token,whenever the request was made the request would be transmitted through like this :
POST /sessions HTTP/1.1
Host: sample.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-CSRF-Token: Ma7g2c5tpeJGcenBa0S4rGtPaHLe2o+kO5AXz+Uk2WnpaTp1J9jdZMPcE1mMSLxZ/7BA1nCBxvLKiZwtepKdoA==
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://sample.com
Content-Length: 67
now as a attacker what i have tried to achieve this was,i intercepted the post request,instead of attacking token ,i tried to attack the parameter for example see the below request :
POST /sessions HTTP/1.1
Host: sample.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
testX-CSRF-Token: Ma7g2c5tpeJGcenBa0S4rGtPaHLe2o+kO5AXz+Uk2WnpaTp1J9jdZMPcE1mMSLxZ/7BA1nCBxvLKiZwtepKdoA==
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://sample.com
Content-Length: 67
while i tried the above request the CSRF token implementation gets failed ,i was able to successfully bypass csrf injection ,
What would be the best method to mitigate this kind of attack?is it valid csrf injection?how can i optimize my java webapplication for preventing this kind of attacks?
How i implemented java code :
In my xml :
<http>
<!-- ... -->
<csrf disabled="true"/>
</http>
And at my code :
#EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}
At form submissions :
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}"
method="post">
<input type="submit"
value="Log out" />
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</form>
also i followed the recommended methods provided over here
,on the above scenario the csrf fails ,what might be the mitigations?

As per spring's documentation, you can inject your custom RequestMatcher to validate HTTP request for CSRF token. Spring provides you the feature to override the defaults.
See section 16.6 http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html
class CSRFRequestMatcher implements RequestMatcher{
public boolean matches (HttpServletRequest req){
//Check if request contains valid header name & header value
}
}

Related

Spring CSRF: Ajax giving 403 error even after setting request headers

I have set up CSRF authentication using Spring Security 4.0. While using AJAX i am getting 403 error each time. I have set up the request headers.
The meta tags:
<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
AJAX looks like this:
var token = $("meta[name='_csrf']").attr("th:content");
var header = $("meta[name='_csrf_header']").attr("th:content");
$.ajax({
type : "POST",
url : "/PRIT/Home/PopulateVisits",
async: false,
beforeSend: function(xhr) {
if (header && token) {
xhr.setRequestHeader(header, token);
}
},
.
.
.
I can see the request headers in the ajax request :
> Accept:*/* Accept-Encoding:gzip, deflate, br
> Accept-Language:en-US,en;q=0.9 Cache-Control:no-cache
> Connection:keep-alive Content-Length:9
> Content-Type:application/x-www-form-urlencoded; charset=UTF-8
> Cookie:JSESSIONID=C3CAAD64269BD0B96FF35B87053B5899 Host:localhost:8082
> Origin:http://localhost:8082 Pragma:no-cache
> Referer:http://localhost:8082/PRIT/Login User-Agent:Mozilla/5.0
> (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
> Chrome/63.0.3239.132 Safari/537.36
> X-CSRF-TOKEN:23c07d26-0494-4588-a158-624791258762
> X-Requested-With:XMLHttpRequest
Request URL:http://localhost:8082/PRIT/Home/PopulateVisits
Request Method:POST
Status Code:403
Remote Address:[::1]:8082
Referrer Policy:no-referrer-when-downgrade
I am not sure what's going wrong. The requested controller is never accessed. The controller is like this:
#RequestMapping(value = "/Home/PopulateVisits", method = RequestMethod.POST)
public #ResponseBody List<DataCollectionForm> PopulateVisits(DataCollectionForm dataCollectionForm, HttpServletRequest request) {
I ran into a similar issue, in my case i was invalidating the spring session during login. Make sure you are not invalidating the Spring session anywhere in your controller prior to the request you are trying to access. Spring associates the token with the session, invalidating it would produce a new token.

Jersey Client to over come ROBOTS response

I'm using below code to get the response from the server. When i used POSTMAN , it gives a different clear response and when i used the java code using jersey client, it is giving robots response assuming my request to be a malicious. I'm using jersey 1.9 version.
Query: How to overcome this robot
ObjectMapper mapper = new ObjectMapper();Client CLIENT = Client.create();
CLIENT.addFilter(new LoggingFilter(System.out));
WebResource webResource = null;
webResource = CLIENT.resource(url);
ClientResponse response = null;
response = webResource
.header("Cache-Control", "no-cache")
.header("Cookies", false)
.accept(MediaType.APPLICATION_JSON)
.get(ClientResponse.class)
;
The below is the header info from POSTMAN. On Session id is set to true in POSTMAN.
Accept-Ranges →bytes
Age →1
Cache-Control →public, max-age=0, must-revalidate, no-transform
Content-Encoding →gzip
Content-Length →5533
Content-Security-Policy →default-src 'self' https://www.xxxx.xxxx https://*.cwp.xxxx.xxxx
Content-Type →application/json
Content-language →en-US
Pragma →no-cache
Server →ngccc
Set-Cookie →SECSESSID=2aprjner5fomn8vrk4sfhbn464; expires=Tue, 23-Jan-2018 18:35:09 GMT; Max-Age=3600; path=/; secure; HttpOnly
Set-Cookie →SECSESSID=2aprjner5fomn8vrk4sfhbn464; expires=Tue, 23-Jan-2018 18:35:09 GMT; Max-Age=3600; path=/; secure; httponly
Set-Cookie →SECSESSID_2=asdasdasdxxsdsdxx; expires=Tue, 23-Jan-2018 17:59:09 GMT; Max-Age=1440; path=/; secure; httponly
Set-Cookie →incap_ses_899_110069=+lYvxV259l1WSI2o+LzxVsA==; path=/; Domain=.www.xxxx.xxxx
Strict-Transport-Security →max-age=31536000
Vary →Accept-Encoding
Via →1.1 varnish-v4, HTTPS/1.1 localhost.localdomain
X-CDN →Incapsula
X-Content-Type-Options →nosniff
X-Frame-Options →SAMEORIGIN
X-UA-Compatible →IE=edge
X-Varnish →436830982
X-XSS-Protection →1; mode=block
Below is the response from code:
<html>
<head>
<META NAME="robots" CONTENT="noindex,nofollow">
<script src="/_Incapsula_Resource?SWJIYLWA=2977">
</script>
<script>
(function() {
var z="";var b="7472797B766172207868723B7661";for (var i=0;i<b.length;i+=2){z=z+parseInt(b.substring(i, i+2), 16)+",";}z = z.substring(0,z.length-1); eval(eval('String.fromCharCode('+z+')'));})();
</script></head>
<body>
<iframe style="display:none;visibility:hidden;"
</body></html>
below is the response from POSTMAN:
{
"query": {
"offset": 0,
"count": 20,
"total": 379
}
}
Got this resolved with by adding a SSL connections related code in it. Due to which it recognized and authenticated this request and responded back with the valid response.

Java MultiPart post

I am trying to create a multipart post to a URL with the following body:
Content-Disposition: form-data; name="json"
Content-Type: "application/json; charset=UTF-8"
{"input1":"data1","input2":"data2","input3":"data3"}
--APIMultipartPost
Content-Disposition: form-data; name="filePath"; filename="myFile.dat"
Content-Length: 381645
Content-Type: text/plain
Content-Transfer-Encoding: binary
<!-- SNIP -->
<!-- The OWL file was included here in plain text (without the SNIPs) -->
<!-- SNIP -->
I tried using MultipartEntityBuilder to create the multipart post, but probably I do something wrong with the parameters.
Can someone help me with the java code for this post?
Here is my code:
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost uploadFile = new HttpPost(URL);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("input1", "data1");
builder.addTextBody("input2", "data2");
builder.addTextBody("input3", "data3");
builder.addBinaryBody("file", new File("C:/myFile.dat"), ContentType.APPLICATION_OCTET_STREAM, "myFile.dat");
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
HttpResponse response = httpClient.execute(uploadFile);
and the error I get:
HttpResponseProxy{HTTP/1.1 422 Unprocessable Entity [Server: nginx/1.6.0, Date: Wed, 28 Jan 2015 19:29:42 GMT, Content-Type: application/json;charset=utf-8, Content-Length: 89, Connection: keep-alive, Status: 422 Unprocessable Entity, X-Rack-Cache: invalidate, pass, X-Content-Type-Options: nosniff] ResponseEntityProxy{[Content-Type: application/json;charset=utf-8,Content-Length: 89,Chunked: false]}}
Thank you!
The response 422 Unprocessable Entity says
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415(Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.
so as you can see the request you send doesn't fit with the specification of the controller/service that you POST to. If you use a tool like TCPMon you can actually intercept the request that you send and check how it looks like. When I do it with your code, it looks like
POST /url HTTP/1.1
Content-Length: 739
Content-Type: multipart/form-data; boundary=L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c
Host: 127.0.0.1:8090
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.3.6 (java 1.5)
Accept-Encoding: gzip,deflate
--L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c
Content-Disposition: form-data; name="input1"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
data1
--L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c
Content-Disposition: form-data; name="input2"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
data2
--L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c
Content-Disposition: form-data; name="input3"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
data3
--L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c
Content-Disposition: form-data; name="file"; filename="myFile.dat"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
--L2EqtNqIEXOWRCYYrYH8FSP1JAD65wz6c--
which is not what you want. You only need a request with two parts, one is the json data and the other is the file.
So if you change your code as the following.
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost uploadFile = new HttpPost("http://localhost:8090/1");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
String jsonStr = "{\"input1\":\"data1\",\"input2\":\"data2\",\"input3\":\"data3\"}";
builder.addTextBody("json", jsonStr, ContentType.APPLICATION_JSON);
builder.addBinaryBody("file", new File("/path/to/file"),
ContentType.TEXT_PLAIN, "myFile.dat");
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
HttpResponse response = httpClient.execute(uploadFile);
You can provide a request like the following.
POST /url HTTP/1.1
Content-Length: 468
Content-Type: multipart/form-data; boundary=mN_bWsS4QQnlPJksvinB_WUpl2Qi6zVVElUEEBKh
Host: 127.0.0.1:8090
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.3.6 (java 1.5)
Accept-Encoding: gzip,deflate
--mN_bWsS4QQnlPJksvinB_WUpl2Qi6zVVElUEEBKh
Content-Disposition: form-data; name="json"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{"input1":"data1","input2":"data2","input3":"data3"}
--mN_bWsS4QQnlPJksvinB_WUpl2Qi6zVVElUEEBKh
Content-Disposition: form-data; name="file"; filename="myFile.dat"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: binary
--mN_bWsS4QQnlPJksvinB_WUpl2Qi6zVVElUEEBKh--
which is what you need.
For multipart request, the content-type has to be multipart/form-data, then you specify content-type for each content. You might want to refer to w3.org - Introduction to forms for the HTTP header examples.

http file upload response structure

i am trying to create an http file upload receiver in java
and i was looking at the post response of file upload in http
POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L
<other headers>
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object
<file data>
------WebKitFormBoundaryePkpFF7tjBAqx29L--
if the boundary string will be a part of the file that is being uploaded (by coincidence) how can i detect it ? is that even possible?
Well, as section 4.1 of RFC 2388 states:
4.1 Boundary
As with other multipart types, a boundary is selected that does not occur in any of the data.
So I guess that your browser will probably be smart enough to choose an appropriate boundary.

JSF action listener not called

I am using JSF 1.2 and RichFaces 3.3.3, and I have a very strange issue, what the code does is take the name of the media item to be searched and put it in the backing bean attribute searcTitle, and when the user clicks the search button the onSearch action listener populates the results list.
And here's the code
<rich:panelBar>
<rich:panelBarItem>
<rich:tabPanel>
<rich:tab label="Media">
<h:panelGrid columns="1">
<h:panelGrid columns="2">
<h:inputText value="#{media.searchTitle}"/>
<a4j:commandButton value="Search" actionListener="#{media.onSearch}"/>
</h:panelGrid>
<a4j:outputPanel id="mediaSearchResults" ajaxRendered="true">
<rich:dataTable value="#{media.results}" var="item">
<h:column>
<h:outputText value="#{item.title}"/>
</h:column>
</rich:dataTable>
</a4j:outputPanel>
</h:panelGrid>
</rich:tab>
</rich:tabPanel>
</rich:panelBarItem>
</rich:panelBar>
And the backing bean code
private String searchTitle="";
private List<MediaItem> results;
public void setSearchTitle(String title){
getLogger().log(Level.INFO,"At the setter of the search title string");
this.searchTitle = title;
}
public String getSearchTitle(){
return searchTitle;
}
//Setter and getter for the results list;
//Action Listener
public void onSearch(ActionEvent evt){
getLogger().log(Level.INFO,"At the actionListener");
//Some function that searches and populates the results list
populateResults();
}
Now the problem is whenever I click on the search button, the action listener is never called, although while inspecting the page with fire bug a request is sent to the server everytime I click on it, but the action listener itself is not triggered.
Does anyone have a clue why I'm having this issue? I'm a beginner at this, so please keep your words simple.
Thanks in advance.
Here are the Reposne/ Request headers from firebug
Response Headers
Ajax-Response true
Cache-Control no-cache, must-revalidate, max_age=0, no-store
Content-Type text/xml;charset=UTF-8
Date Sat, 02 Jun 2012 16:03:13 GMT
Expires 0
Pragma no-cache
Server Sun GlassFish Enterprise Server v2.1.1
Transfer-Encoding chunked
X-Powered-By Servlet/2.5, JSF/1.2
Request Headers
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en,ar;q=0.7,en-us;q=0.3
Connection keep-alive
Content-Length 17986
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Cookie JSESSIONID=de975352b3adc4f59d57006755ea; JSESSIONID=de682f835c0fa928413ba7e5f59d; form:tree-hi=form:tree:applications:enterpriseApplications
Host localhost:8080
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0
And the link to the xml payload of the response http://justpaste.it/10uh
You should try a f:form or a4j:form around your a4j:commandButton.

Categories