19

I've done a lot of research on "best practices" surrounding this and have read blog post after blog post, SO question after SO question, and OWASP article after OWASP article. I've arrived at a few clear answers but some unknowns.

First, the "Do's":

  1. Use JWT for authorizing users on my REST API [1] [2]
  2. Store the JWT in a HTTPOnly/Secure cookie and build in CSRF protection. Do NOT store in HTML5 local storage [3] [4] [5] (Actually, this point is debatable, is it easier to protect against XSS or CSRF? [6])
  3. Verify the signing method of the JWT [7]

Now I started with the assumption that having a SPA (built with Angular) and using HTML5 sessionStorage would be secure enough for short-lived tokens, but there is a point to be made that XSS attacks can happen from a "bad actor" originating in the one of many libraries loaded in from a CDN.

For my specific use case, I do not plan on having long-lived tokens - expiration after 10 minutes of non-use but I'm still figuring out if I want to track expiration by session or use refresh tokens - StormPath recommends the former (no longer stateless?) but I believe big players using JWTs use refresh tokens (Google uses them but states you need to store them in secure, long-term storage which means HTML5 localStorage is again, out of the question).

I would like to make it so my users don't have to log back in if they refresh the page (hence the need to store the token on the client side). I would also like to use my SPA as a "mobile app" with the help of Cordova. The obvious pitfall here is that if I use cookies, there is no baked-in cookie support/storage with Cordova and I'm urged to switch to HTML5 local storage instead. Since on mobile I don't really need to worry about refreshing pages, I can just let my token live in memory and expire with the strategy I settle on.

If I take this approach, cookie-based JWT on Desktop, "Bearer" headers on mobile, I now need an authentication end-point that will give tokens two different ways, and when I authorize on the REST API side, I need to support both cookie-based JWTs (with CSRF) and header based JWT verification. This complication has me worried as I don't know if I can accurately foresee security implications here.

To summarize the barrage of thoughts above:

  • Create an authentication handler that would hand out tokens via HttpOnly/Secure cookies to desktop, and by payload for mobile.
  • On my REST API, support both methods of verification - header based and cookie-based - including CSRF protection for the cookie-based approach.

Is there any reason why I wouldn't want to take this approach? I assume if I take XSS on my SPA as a serious risk, then I need a classic login-page for authentication to set the proper cookies because if I do authentication via the SPA, then any XSS attack could potentially intercept that as well (both on mobile and Desktop)! However, on mobile, I'd need to inject the JWT into SPA, maybe through some custom DOM element (meta tag?), but at that point I can just let the SPA perform the login and not consider XSS a threat on mobile devices. Cordova packages all assets into the install package so that's somewhat better but then why not take the same approach on the Desktop version?

My application takes very little user input, it is primarily a dashboard/reporting tool. There will be a "message center" but it's content should always be user-created (by only that user) and sanitized. In my use-case then, would it be ok to deviate from "best practices" and rely on localStorage not counting XSS as a serious risk for my SPA? This would simplify this entire thing (use HTML5 sessionStorage as originally planned) and reduce complexity, which would reduce attack surface for potential security blunders. I just want to make sure I understand the risks before moving forward.

Is there no secure way to make this secure other than by building a native app for mobile and not using Cordova to convert my SPA to a mobile app? I'd hate for this to be the case, but it might very well be.

I'd appreciate all thoughts on the matter!

someone1
  • 3,570
  • 2
  • 22
  • 35
  • I had very similar questions. What did you end up doing? – Adversus Mar 04 '16 at 15:13
  • 2
    Don't use Cordova (go native or go home!) - used JWT in Secure/HTTPOnly cookies along with in the headers of all requests (to prevent CSRF) checking the JWT at both locations. – someone1 Mar 08 '16 at 22:51
  • @someone1 Did you had a chance to look at this link - http://security.stackexchange.com/questions/100129/what-to-do-when-you-can-t-protect-mobile-app-secret-keys – Gandhi Jul 26 '16 at 11:14
  • 1
    @Gandhi - thanks for the link, it was an interesting discussion but I don't believe it is applicable to my question. Specifically, I was less worried about the security of using TLS to secure my API endpoints and ways to prevent brute force password cracking, and more interested in how to securely store a JWT in a Cordova converted application. As aforementioned, I don't think there is a way to do this without bringing in native components to the mobile application. – someone1 Jul 26 '16 at 14:48
  • @someone1 Thanks for the explanation. – Gandhi Jul 27 '16 at 05:55
  • 3
    @someone1 lol @ go native or go home, typical purist but completely inaccurate for anyone reading this. If you have a rounded understanding of HTTP and the web technologies that you are trying to use as well as your storage options on a native app, you will realise that you can implement the same on a cordova application without considerable additional risk, after all http doesn't change simply because you are calling from a native app and if you don't like localStorage, write a plugin to store how you want – Obi Aug 23 '16 at 22:35
  • @ObiOnuorah I think I've stated my case pretty clearly as to why you should not use localStorage, most notably it is explicitly discouraged by OWASP. Since (as of writing) Cordova does not support httponly cookies, you'd have to extend or write your own plugin to support this in Cordova. This does not seem like a trivial task, if even possible, and if security is paramount, then writing a plugin on your own leaves you open to implementation flaws. I'd love to hear ideas to minimize the risk of porting an app using Cordova while following best practices and argue my comments are not inaccurate. – someone1 Aug 24 '16 at 17:00
  • Here's the thing, a cordova app is very different to an app running on a web server so half the security issues on the web (i.e. browser based applications) would not be as applicable. Considering things like httponly cookies for a mobile app are just the indication that you may designing your app like a "website". On writing a plugin, if you are going to write the code in a native app, it's the exact same code that you wrap a plugin around. I daresay the 'difficulty' in writing native plugins where you have concerns is no where near the difficulty in writing a new app for each platform. – Obi Aug 24 '16 at 20:25
  • @ObiOnuorah Well I am writing an application to be run both as a SPA (running on a webserver) and making it a native app via Cordorva - so yes, I'm writing my app like a "website" following best practices which include httponly cookies as recommended by OWASP. Are you specifically talking about having a modified version of the SPA to be used with Cordova in which I do allow the usage of localStorage due to a decrease in attack surface when compared to a traditional browser/webserver based SPA?Please construct an answer so I may give it consideration and award it if I agree! – someone1 Aug 26 '16 at 14:39
  • @ObiOnuorah I'm having the EXACT same problems with my SPA and Cordova and JWT... I would also like to know: Are you specifically talking about having a modified version of the SPA to be used with Cordova in which I do allow the usage of localStorage due to a decrease in attack surface when compared to a traditional browser/webserver based SPA? – mesqueeb Aug 04 '17 at 07:20
  • @mesqueeb: the answer to your questions is yes pretty much. What and how much you modify would depend on the needs of your SPA – Obi Aug 04 '17 at 14:28

1 Answers1

2

When thinking of designing javascript based cross-platform applications to run a mobile device, many of the caveats with designing regular web browser based applications do not necessarily apply.

As far as security is concerned, whether you decide to use JWT or simple OAuth tokens, ensure that all your communications are via https.

Please use localStorage as much as you want. If you consider the anatomy of a http request, all it really is sending some text based message divided into multiple sections to a server. The header of the request is no more secure than any other part of it including the cookies. So the points of interest from a security perspective are generation/validation/invalidation of the token, storage of the token on the device and the transport mechanism of the requests.

  1. Generation/Validation/Invalidation: Generate the tokens on your server. Use some technology/strategy to ensure that there is no possibility for collisions or bleeding. Also, ensure that your strategy will allow you invalidate a token on the server which then subsequently denies access to data requested from the server on further usage of the token. It is then up to you in your app to handle the users UI journey when the server denies access to resources.
  2. How you store the token on the device is constrained to what the device OS make makes available to you. Regarding whether using a native app is better than cross-platform, I think creating a native-cordova plugin to store your token using any specific native strategy if one is unsatisfied with the "out of the box" ones (such as local storage) is possible, although in my experience this is usually overkill. Happy to be corrected on this one if anyone has a different experience.

  3. Please use HTTPS ALWAYS without exception for ALL Webservice end point communications. Is HTTPS foolproof, NO, but you wouldn't build a house without a front door simply because dedicated burglars could learn to pick locks. This secures the transport mechanism considerably.

Usually, this is all native apps have to work with too anyway.

Obi
  • 3,091
  • 4
  • 34
  • 56
  • Dear @obi-onuorah After research I understand that for a browser-SPA the best way to save a token is a [cookie](https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage). But since cookies don't work out of the box with cordova, and security is different for mobile, feel free to use *local storage* to save the token locally. However, [here](https://stackoverflow.com/questions/36389354/securely-store-access-token-in-cordova) I've read: The approach should be using a native solution for both Android (Shared Preferences) and iOS (Keychain). Do you know how to do this? – mesqueeb Aug 07 '17 at 03:42