Grails 3 CSRF protection - grails

Is it possible to configure CSRF protection in grails3 app using spring-security plugin, I can't find anything except useToken attribute for grails form and then call withForm inside controller. But this is actually not a very flexible solution. I like approach with filter like here

For csrf protection I reused org.springframework.security.web.csrf.CsrfFilter. You need to define new bean in grails resouces.groovy (See snipet below - csrfFilter bean). You can define your own accessDeniedHandler and requireCsrfProtectionMatcher. Here is the snippet from resources.groovy:
csrfFilter(CsrfFilter, new HttpSessionCsrfTokenRepository()) {
accessDeniedHandler = ref('fnAccessDeniedHandler')
requireCsrfProtectionMatcher = ref('fnRequireCsrfProtectionMatcher')
}
Now in Bootstrap.groovy add this filter into filter chain:
SpringSecurityUtils.clientRegisterFilter('csrfFilter', SecurityFilterPosition.LAST.order + 10)
Now in your main layout GSP add following tags to add csrf token on each page:
<meta name="_csrf" content="${_csrf?.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf?.headerName}"/>
So now csrf token presented on each page of your app, you can use it for each ajax request for example (snippet from application.js (I'm using grails 3)):
$(function () {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
});
For each jquery ajax request we are sending csrf token now.

You can implement it with <g:form> tag:
Example:
<g:form useToken="true" uri="/logout">
Documentation: http://grails.github.io/grails-doc/latest/guide/single.html#formtokens
In my case, I'm using Spring code, so, additionally, I should add manually a _csrf hidden field in the form.
<g:form useToken="true" uri="/logout">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="submit">Logout</input>
</g:form>
Result:
<form action="/nacho/logout" method="post" >
<!-- this two lines are added automatically by Grails -->
<input type="hidden" name="SYNCHRONIZER_TOKEN" value="883a1037-a2c9-4997-8254-e59da6303494" id="SYNCHRONIZER_TOKEN" />
<input type="hidden" name="SYNCHRONIZER_URI" value="/nacho/userInfo" id="SYNCHRONIZER_URI" />
<!-- this line was added by myself, but, using the ${_csrf} variable -->
<input type="hidden" name="_csrf" value="0928f13c-02aa-4122-8ebe-a1239855a85b"/>
<input type="submit">Logout</input>
</form>

Related

Issues with using d2l remote plugins (insert stuff cim) example not working

I am new to Brightspace and been fiddling with the remote plugins sample (logo). I can load the sample logo project, but cannot get it to insert into the page. I have uploaded the file but get a 404 error on submit. Can someone `
$( document ).ready(function() {
$('#submitFormButton').click( function() {
$.ajax({
url: "/getisfdetails",
data: {
image: $("input[name='image']:checked").val()
},
success: function(response){
$("input[name='lti_message_type']").val(response.lti_message_type);
$("input[name='lti_version']").val(response.lti_version);
$("input[name='content_items']").val(response.content_items);
$("input[name='oauth_version']").val(response.oauth_version);
$("input[name='oauth_nonce']").val(response.oauth_nonce);
$("input[name='oauth_timestamp']").val(response.oauth_timestamp);
$("input[name='oauth_consumer_key']").val(response.oauth_consumer_key);
$("input[name='oauth_callback']").val(response.oauth_callback);
$("input[name='oauth_signature_method']").val(response.oauth_signature_method);
$("input[name='oauth_signature']").val(response.oauth_signature);
$("#isfForm").prop('action', response.lti_return_url);
$("#isfForm").submit();
}
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<body>
<h3>Select an logo:</h3>
<input type="radio" name="image" value="brightspace-logo.png"> <img src="../content/isf/brightspace-logo.png" alt="Brightspace Logo"><br />
<input type="radio" name="image" value="d2l-logo.png"> <img src="../content/isf/d2l-logo.png" alt="D2L Logo"><br />
<div hidden>
<form id="isfForm" method="POST">
<input type="hidden" name="lti_message_type" />
<input type="hidden" name="lti_version" />
<input type="hidden" name="content_items" />
<input type="hidden" name="oauth_version" />
<input type="hidden" name="oauth_nonce" />
<input type="hidden" name="oauth_timestamp" />
<input type="hidden" name="oauth_consumer_key" />
<input type="hidden" name="oauth_callback" />
<input type="hidden" name="oauth_signature_method" />
<input type="hidden" name="oauth_signature" />
</form>
</div>
<br />
<button id="submitFormButton">Submit</button>
</body>
` how do you set this cookie in the javascript? I believe a cookie needs to be set??? and I do not see how to set it? or maybe I am missing something else that is not noted in the documentation.
I would highly recommend you consider using LTI Advantage/1.3 instead of Remote Plugins. LTI provides a standards-based integration approach & a better developer experience.
https://community.brightspace.com/s/article/LTI-Integration-Guide
If you are working with a partner of D2L please get in touch with the partner team and technical assistance is available. Your information here is appreciated but we are glad to examine the full context and use case as these errors are not hugely uncommon during dev. Otherwise, I echo Paul's suggestion, but I understand if it is not immediately possible.
partners#d2l.com or talk with your team that knows D2L!
Depending on which browser you are in you might be seeing the recent effects of the third-party cookie blocking that the browsers are adopting. Because LTIs (both 1.1 and 1.3/Advantage) typically launch into iframe any access to those cookies are regarded as third party. This effectively means two things
You need to be aware of the cookie access routines where a user action must be taken to request access to the browser storage API using document.requestStorageAccess()
You need to be marking your cookies appropriately with the new SameSite cookie directives
Without these the browser will mark your cookie request as a 'Tracking cookie' and refuse to serve it along with the request or make it accessible via javascript.
An alternative is also to detect that the LTI launch is happening inside the an iframe and to bust that iframe out to a new window, or alternatively configure the launch inside Brightspace to not use a iframe at all.

Expected CSRF token not found. Has your session expired? + Spring security + CSRF

I am trying to implement CSRF via spring security.
But, facing following error in browser, after clicking login button(from home.jsp)
"Expected CSRF token not found. Has your session expired?"
I have following configuration in
spring-security-config.xml:
<http auto-config="false">
<csrf/>
</http>
home.jsp:
<form action="j_spring_security_check" id="LoginForm" method="post">
<input type="text" title="Username" name="j_username" id="j_username"
class="inset-shadow defaultText" placeholder="Username" />
<input type="password" title="Password" name="j_password"
id="j_password" class="inset-shadow defaultText" placeholder="Password" />
<input type="submit" class="submit" title="LOGIN"
onsubmit="javascript:{loginSubmit();}"/>
<input type="hidden" name="_csrf" value="dc7ce2be-f73b-4086-8f90-8ef00b8f81d5"/>
</form>
Error from jboss server.log:
2015-09-14 19:56:10,221 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/].[jsp]] (http-127.0.0.1-8190-2) Servlet.service() for servlet jsp threw exception: java.lang.IllegalStateException: getAttribute: Session already invalidated
at org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:1024) [:6.1.0.Final]
at org.apache.catalina.session.StandardSessionFacade.getAttribute(StandardSessionFacade.java:110) [:6.1.0.Final]
at org.apache.jsp.WEB_002dINF.jsp.home_jsp._jspService(home_jsp.java:99)
Note : Not sure whether the error from server.log relates to CSRF
Any help on this problem is highly appreciated?
Instead of
<input type="hidden" name="_csrf" value="dc7ce2be-f73b-4086-8f90-8ef00b8f81d5"/>
did you try
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
As per the docs, the csrf and token would be computed by Spring and appended as a request parameter, with name as ${_csrf.parameterName} and value as ${_csrf.token}.
I had the same error.
I my case, the html page containing the form have a link tag to a css file into my web application.
This link to css file has been also protected by spring security and due to this, I had your error.
When I unprotect link to css file, no error occur.
This is an example how to unprotect files in Spring Security with Java Config
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**");
}

File upload & Spring Security

Based on the Spring Security documentation, I setup a MultipartFileter as the following:
#Order(1)
public class SecurityWebAppInitializer
extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
In a file upload form, I can see a CSRF input with a not-null value in a HTML file (see the code below).
<form method="POST" enctype="multipart/form-data" action="/upload">
File to upload: <input type="file" name="file" /><br />
Name: <input type="text" name="name" /><br /> <br />
<input type="submit" value="Upload" />
Press here to upload the file!
<input type="hidden" name="_csrf" value="df94be7d-675d-428c-89e5-2ebf0b473c42" />
</form>
After submitting the form, I get an error as
HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
type Status report
message Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
description Access to the specified resource has been forbidden.
What is missing here?
This problem is resolved after changing the Java configuration of the application. The followings are those changes.
In AbstractAnnotationConfigDispatcherServletInitializer class, I add the MultipartFilter in the getServletFilters method and set the MultipartConfig with a MultipartConfigElement in customizeRegistration(ServletRegistration.Dynamic registration) method. A MutlipartConfigElement originally defined in WebMvcConfigurerAdapter class is removed. And a MultipartResolver defined in the class is unchanged.
The Java configuration was set up based on the original XML configuration of the application. The approach doesn't always work based on this case.

How to implement my own login page instead of default Spring Security login page in Grails application?

I have gone through some of the blogs in internet, but I am not able to find out how to do my own login page without Spring Security. How can I do it?
To create a custom login page, create a view called auth.gsp in grails-app/views/login/. Make sure it passes the parameters j_username and j_password to the action ${postUrl}. Here is the default auth.gsp view that comes with Spring Security 1.x:
<html>
<head>
<meta name='layout' content='main'/>
<title><g:message code="springSecurity.login.title"/></title>
<link rel="stylesheet" href="${resource(dir: 'css', file: 'auth.css')}" type="text/css">
</head>
<body>
<div id='login'>
<div class='inner'>
<div class='fheader'><g:message code="springSecurity.login.header"/></div>
<g:if test='${flash.message}'>
<div class='login_message'>${flash.message}</div>
</g:if>
<form action='${postUrl}' method='POST' id='loginForm' class='cssform pure-form pure-form-aligned' autocomplete='off'>
<p>
<label for='username'><g:message code="springSecurity.login.username.label"/>:</label>
<input type='text' class='text_' name='j_username' id='username'/>
</p>
<p>
<label for='password'><g:message code="springSecurity.login.password.label"/>:</label>
<input type='password' class='text_' name='j_password' id='password'/>
</p>
<p>
<input type='submit' id="submit" class="btn" value='${message(code: "springSecurity.login.button")}'/>
</p>
</form>
</div>
</div>
<script type='text/javascript'>
<!--
(function() {
document.forms['loginForm'].elements['j_username'].focus();
})();
// -->
</script>
</body>
</html>
I would copy that into your auth.gsp view and change it from there.
This can be annoying sometimes.
So if am getting you right you want to change the look and feel of the login spring security offer right?
Do this after you are done with your UI design( CSS, HTML and others).
Now change the input name and compare it to auth.gsp, thus from Spring security.
You can hold ctrl+shift+N on the keyboard and type auth.gsp for you to check.
Compare it to yours and change where possible.
In your UrlMAppings.groovy do this editing
"/"(view:"/Your login page")
"/login/auth"(view:"/Your login page")
Now restart your service and thats all.
If the issue persist you can post the error here so we can see what to do to help.
Note this is for Grails 3.x
In order to do this you need to do this tasks:
Create a login view inside views directory
create two gsp views names auth.gsp and denied.gsp
in this step you probably need to copy content from plugin auth.gsp view and denied.gsp if you are using grails spring security core plugin version 2.0-RC3 these views are located at target > work > plugins > spring-security-core-2.0-RC2 > grails-app > view > login, copy content and paste it in your app auth.gsp and denied.gsp views
You can check an example of views location and views content in this repo.

POST data over HTTPS is secure enough?

I have a page where i need to send parameter (say param1) via post and site is running
over HTTPS, would it be secure can anyone hack this information, what is the correct
solution to send info over https ?
Below is the JSP page, indeed the info is send via HTTPS but user can see view source to
see value of param1 and param2, would we use some encryption standard or jsp taglib so
that user is not able to view source ass well as not able to read param1 and param2 values.
testPage.jsp
This is a parent page , in this a second jsp is included
<form id="myForm" target="iframe" method="post" action="http://www.abc.com/jsp/dGrid.jsp">
<input type="hidden" name="param1" value="77"/>
<input type="hidden" name="param2" value="SS"/>
</form>
<iframe name="iframe" width="1500px" scrolling="no" height="1170px" frameborder="0" allowtransparency="">
</iframe>
<script type="text/javascript">
document.getElementById('myForm').submit();
</script>

Resources