Reputation: 16271
I am working with Spring Security
The app has enabled the following:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/css/**", "/resources/images/**", "/resources/jquery/**", "/resources/js/**").permitAll()
... more URLs to intercept
.antMatchers("/notification**").hasAuthority("ROLE_ADMIN")
.antMatchers("/ajax/notification**").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.csrf()
...
Observe CSRF
is applied. For a form the following is used:
<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>
It according Form Submissions
The app works fine how is expected, it intercepts any URL prior to load/render a jsp
page and ask for the login control how is expected, if the user has logged the control about authorization is applied how is expected too. Therefore all is working with CSRF
how is suggested.
Until here all is Ok.
I added ajax through jQuery
and because it works with an URL, therefore I need apply the CSRF
control for that URL too.
That's why above appears:
.antMatchers("/ajax/notification**").hasAuthority("ROLE_ADMIN")
Now, I want get the expected HTTP error code and message when CSRF
is applied to the ajax URL "/ajax/notification"
and the CSRF
headers were not send.
The js ajax code is:
$.getJSON(
"/projectname-01/ajax/notification",
function(data, textStatus, req) {
console.log("data: " + data);
console.log("textStatus: " + textStatus);
console.log("req: " + req)
console.log("data: " + data);
console.log(data.content + " " + data.date);
$("#single").empty();
$("#single").append(data.content + " " + data.date);
$("#multiple").append(data.content + " " + data.date)
.append("<br/>");
}
)
Note: The URL needs to be /projectname-01/ajax/notification
, the projectname-01
is mandatory, if I remove that, I get the 404
. It does not work even if ./ajax/notification
is used (observe the dot).
Problem: The code works fine, I mean, the Ajax call happens to the server without any problem, I am expecting some error, it because the code is not using the CRSF
requeriments for ajax.
It according from:
Thus, such as either:
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>
<!-- ... -->
</head>
or
<sec:csrfMetaTags />
and of course the js code working with:
_csrf_parameter
, _csrf_header
etc.
Then the expected HTTP error code and message is need it for testing and production purposes
Thus, what is missing? or what is the problem?
Headers: how was requested below the HTTP headers:
From Opera
General
Request URL:http://localhost:8080/security-01/ajax/notification
Request Method:GET
Status Code:200
Remote Address:[::1]:8080
Referrer Policy:no-referrer-when-downgrade
Response Headers
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 23 Sep 2017 00:14:20 GMT
Request Headers
GET /security-01/ajax/notification HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 OPR/47.0.2631.80
Referer: http://localhost:8080/security-01/tiles/notification/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: JSESSIONID=9F2007DA3C8C683D26B8D17D85563140; jenkins-timestamper-offset=18000000
From Firefox
Request Headers
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/security-01/tiles/notification/
X-Requested-With: XMLHttpRequest
Cookie: JSESSIONID=CF344E56DD03C4019DCA334CD38B73EC
Connection: keep-alive
Response Header
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 23 Sep 2017 00:17:06 GMT
Clarification
According with Spring Security Reference Documentation
we apply CSRF
for a JSP
page (submit form) and for Ajax
, both work around with a URL
. For the former I have already configured and works fine. The latter is the problem.
When I use jQuery
's $.getJSON
call without send the special CSRF data/headers
values (<sec:csrfMetaTags />
, meta[name='_csrf_parameter']
, etc), I mean from: 30.6 The csrfMetaTags Tag appears the following:
// using JQuery to send an x-www-form-urlencoded request
var data = {};
data[csrfParameter] = csrfToken;
data["name"] = "John";
...
$.ajax({
url: "http://www.example.org/do/something",
type: "POST",
data: data,
...
});
// using JQuery to send a non-x-www-form-urlencoded request
var headers = {};
headers[csrfHeader] = csrfToken;
$.ajax({
url: "http://www.example.org/do/something",
type: "POST",
headers: headers,
...
});
From above it sends the CRSF
information either from data
or headers
. But in my code I am not sending that. Therefore I expect some special control and error reported through Spring Security
Thus with my current ajax code, through development in runtime (Tomcat
running with the app), the call to the server happens and data is returned. Thus Spring Security
did not intercept and throw an error due the absence of these CRSF data/headers
.
Therefore thinking now for development and testing, if I create @Test
methods where should fail because the CSRF data/headers
values were not send. The @Test
methods are going to fail because the call to the server happens without any security control.
Upvotes: 0
Views: 863
Reputation: 16969
Your HTTP GET
request produces no error, because the CSRF token is only required for requests that update state, see Spring Security Reference:
18.2 Synchronizer Token Pattern
[...]
We can relax the expectations to only require the token for each HTTP request that updates state. This can be safely done since the same origin policy ensures the evil site cannot read the response. Additionally, we do not want to include the random token in HTTP GET as this can cause the tokens to be leaked.
and CsrfFilter
:
Applies CSRF protection using a synchronizer token pattern. Developers are required to ensure that
CsrfFilter
is invoked for any request that allows state to change. Typically this just means that they should ensure their web application follows proper REST semantics (i.e. do not change state with the HTTP methods GET, HEAD, TRACE, OPTIONS).
To get a CSRF token you have to use HTTP POST
, PUT
or DELETE
request.
Upvotes: 1