Implementing CSRF protection with OpenIG

Tagged: ,

This topic has 4 replies, 2 voices, and was last updated 6 years, 4 months ago by Miguel F.

  • Author
    Posts
  • #8495
     Miguel F
    Participant

    Hi,

    I need to implement CSRF protection for my applications. As we are using OpenIG as a gateway I thought OpenIG could be in charge to:

    1. Create the CRSF token and set it as a cookie in the response if the CRSF token does not exists – I guess it could be stored in the OpenIG context

    2. Obtain the CRSF token from incoming requests (which name would be different to the cookie set in the response as explained in 1 and compare it to the one stored in the OpenIG context (connected to the user session).

    At the end of the day, several applications will use the OpenIG gateway so I thought is a good place to implement CSRF protection.

    My questions are:

    – Is this a good approach? are there any other better ways to implement CRSF with OpenIG?
    – Is there any out-of-the-box filter / handler / feature helping to implement this?
    – If there is nothing, could this be implemented using the ScriptableFilter?

    Thanks so much, any help will be appreciated!

    • This topic was modified 6 years, 5 months ago by Miguel F.
    #8602

    Well, usual CSRF protection technics involve a transfer of some secret (the token) from the application to the user-agent and then the user-agent is responsible to add back this secret in requests (usually POST requests).
    Traditionally, this is a hidden <input ...> in forms, or sometime, the addition of a <meta ...> tag (to be consumed by javascript). That means that the application is aware of CSRF.

    If we imagine to do the same with a transparent reverse-proxy (means that the app doesn’t know about CSRF), that would mean that the response’s content should be enriched with the token, and this is not a trivial task to do in a generic fashion.

    Your proposition is slightly different: the token would be passed to the UA using a cookie, but then the UA has to send back the token when doing requests. If we assume it will come back with the cookie, then there is not such much protection, because an illegal request would have the cookie, just like other requests.

    So the token has to be explicitly added by the UA for each form submition. And then we come back to the content rewriting/enriching issue: the HTML is build on the protected application, there is still no hidden <input ...> field in forms, no javascript, …

    So, to finish on a more positive note: we can still do something with OpenIG :)

    If we consider the case of a not so transparent reverse-proxy, we could imagine that IG would be responsible of token generation, it could look for marker in the HTML (the hidden <input ...> field) and then substitute the marker with the actual token. When a POST request comes in, it would check the presence of the token in form parameters.
    Note that this solution ties your application(s) to OpenIG: they are still responsible of generating a CSRF-aware HTML:

    <form ...>
      // ...
      <input type="hidden" value="#CSRF_TOKEN#" />
    </form>
    
    #8607
     Miguel F
    Participant

    Hi Guillaume,

    Thanks so much for your answer.

    The client side would be AngularJS single page apps. There is already support from AngularJS to handle XSRF from the client side. The client side app gets a cookie with name “XSRF-TOKEN” (by default) from the server response and needs to add it in every request as a header with name “X-XSRF-TOKEN” (by default – obviously this header has a different name from the cookie so it’s set by the application and not propagated automatically by the browser). AngularJS takes care of this, so the ‘client side’ is already covered.

    OpenIG would be in charge of the ‘server side’ XSRF responsibilities (1. token generation and 2. token validation).
    It would generate the token with name “XSRF-TOKEN” and adding it to the respose in the “login” request (the first request) and it will store it in the context of the logged in user. For the rest of requests it will always check that a header called “X-XSRF-TOKEN” comes in the request and the value matches the value stored in the user context. Otherwise it would return 401 or 403 (Not authorized or Forbidden).

    At the end of the day we want to protect apps that rely on cookies for security so an attacker can’t take advantage of the session of a user that is logged in to trick him / her to make requests to the server side that will be accepted as valid (as the cookies are propagated by the browser automatically, for instance “iPlanetDirectoryPro” and some custom cookies).

    In summary for applications using OpenIG as gateway to the service layer, I guess the own gateway is a good point to implement the CSRF server side protection code.

    In fact, if the name of the XSRF cookie and XSRF header can be configurable, this OpenIG CSRFFilter can be a general purpose one and it could be even contributed to OpenIG.
    Does it make sense?

    Thanks for your help

    ———————————–
    Annex: About AngularJS Support (from ): https://docs.angularjs.org/api/ng/service/$http

    Cross Site Request Forgery (XSRF) Protection
    XSRF is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. The header will not be set for cross-domain requests.

    To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on the first HTTP GET request. On subsequent XHR requests the server can verify that the cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that only JavaScript running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server (to prevent the JavaScript from making up its own tokens). We recommend that the token is a digest of your site’s authentication cookie with a salt for added security.

    The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, or the per-request config object.

    In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, we recommend that each application uses unique cookie name.

    • This reply was modified 6 years, 4 months ago by Miguel F.
    #8629

    Hmmm, interesting

    If you app already have support for CSRF protection, then doing the cookie stuff and verification on IG make sense.
    Do you know if other JS based frameworks are using the same CSRF protection technic ? If there are some, then this filter is not tight to AngularJS.

    That would be a great contribution!

    Please keep us posted of your progress and come back here if you need any help

    #8635
     Miguel F
    Participant

    Thanks Guillaume,

    Yes, it is common to implement CSRF protection using a cookie (set cookie from ‘server side’) and a header (different name from the cookie) from the ‘client side’.
    Spring framework for instance uses this same approach both for the server side support it provides and client side (for the technologies with Spring CSRF support, JSP, Thymeleaf, etc..).

    If fact an improvement is that the server side looks for the CSRF token both in a header or in an attribute so you have two ways of passing the token depending on the client. This would work for client solutions as you describe where they need to add the CSRF token as a field of a form.

    So this is a good candidate to be a new general purpose CSRF OpenIG filter. With a bit of polishing and allowing configuration (name of the header / attribute, cookie, only accept header or attribute / both, etc..) it can provide the server side solution to fit with different clients.

    Ok. Thanks for confirming that this seems a good idea.
    We will try to implement this and I’ll keep you posted. We might share it with you and you might need to polish / refactor a bit as i’m quite new to OpenIG and I’ll be probably a bit ‘awkward’ with OpenIG expressions and programming :-)

    Thanks again

    • This reply was modified 6 years, 4 months ago by Miguel F.
Viewing 5 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic.

©2022 ForgeRock - we provide an identity and access platform to secure every online relationship for the enterprise market, educational sector and even entire countries. Click to view our privacy policy and terms of use.

Log in with your credentials

Forgot your details?