1. 2

    few questions:

    • Would having the jwt returned by an IdP(cognito/auth0/okta) as a result of a oauth process improve the situation?
    • any recommended way to work around this and keep stateless backend services ?
    1. 2

      So, to answer your questions:

      • If you’re using an authentication provider then no, it won’t really help, although… In my recommendations I mention using patterns like adaptive multi-factor authentication to re-prompt for a second factor when changes are detected – this is something Okta provides. I’m not too familiar with auth0/cognito, they might also have this functionality. So that can help a bit.

      • There is honestly no way to have a stateless backend service without revocation. The best you can do is maintain a cache where in the cache you store any invalidated JWTs and check each request against the cache. This is a pretty common pattern.

      But, re: stateless backend services, one thing I like to think about it is the security vs speed tradeoff. You basically have two options: either guarantee security so you aren’t servicing revoked tokens or guarantee speed and not bother with it at all. If your architecture has backend-only services that aren’t exposed to users, going for the speed tradeoff might be worth it since you’re in a trusted environment. But, if your API is servicing end-users it’s probably better to go with the approach mentioned above so you don’t run into issues :x

    1. 2

      Could one store the IP address of the initial request that causes you to generate a JWT in the token itself? Then you can validate that the current request comes from the same IP. If they’re different, then force them to log in again from their current IP.

      The user would need to re-login if they turn on a VPN or change locations, but that’s a small price to pay if that reduces the possibility for certain types of attacks. I’m definitely not a security expert, but working on a fairly sensitive app where a breach would be bad for a user. The fact that I haven’t seen this suggested next to more complex safeguards makes me think there’s a fundamental flaw in it that I’m just not thinking of.

      1. 5

        IPs aren’t a great factor to base stuff like this one, although that’s a good idea.

        I think what’s better is something like token binding (https://datatracker.ietf.org/wg/tokbind/documents/) which is a way to pin a certain token to a specific TLS session. This way you have some basic guarantees. But in the real world things are sorta messy =p

        1. 2

          Most home users would have to re log in every day. Services that tie my login to an IP address piss me off so much because they are constantly logging me out.

          1. 2

            The fact that I haven’t seen this suggested next to more complex safeguards makes me think there’s a fundamental flaw in it that I’m just not thinking of.

            It’s not a safe presumption that a users requests will always come from the same IP - even from request to request. Their internet access could be load balanced or otherwise change due to factors like roaming.

            1. 1

              Yeah that is also a common technique for cookies. If the remote IP changes you can invalidate the cookie.

            1. 3

              The only problem here is that if an attacker was able to steal your token in the first place, they’re likely able to do it once you get a new token as well. The most common ways this happens is by man-in-the-middling (MITM) your connection or getting access to the client or server directly.

              For my education; is there another security mechanism that will protect from MITM or server being compromised? Seems like if your JWT token is being stolen then you’ve got bigger problems.

              1. 6

                JWTs are commonly stolen via XSS – which is particularly common today as more and more of the auth logic is being pushed into the browser which is an insecure channel.

                There are some new things browsers are attempting to implement to help mitigate this risk, including token binding, https://datatracker.ietf.org/wg/tokbind/documents/, but to my knowledge there is no active implementation of token binding in a major browser yet.

              1. 8

                It’s worth noting that static sites and CMSs are not mutually incompatible - I work on one, Netlify CMS, which connects to a hosted Git repo and edits the content within it, which triggers a rebuild of the site if you have a CI pipeline set up. There’s other ways to do it as well, such as using a CMS which serves content through an API API (GraphQL is typical for this kind of CMS) which your static site generator pulls from to build the site, and having the CMS ping a service which rebuilds the site when changes are made. The term for these kind of CMSs is “headless CMS” - it’s only involved in editing your content, and the actual building, deployment, and hosting of the site is totally orthogonal. There’s a list of headless CMSs at https://headlesscms.org/ (disclaimer: this site is run by Netlify, though it’s an open-source project with a repo at https://github.com/netlify/headlesscms.org/).

                1. 2

                  Awesome! I didn’t know this existed. I’m a huge fan of Netlify and use it for a lot of projects. Didn’t realize y’all have a CMS that works like that – I will investigate this fully.

                  Your service is fantastic. Super clean + useful.

                  1. 2

                    There are a couple CMS options around. I’ve also been working on one: https://github.com/usetint

                    1. 2

                      Hey that looks sweet, and I was quite happy to see you support indieauth for sign in!

                  2. 1

                    I’ve believe Gatsby also supports this via its WordPress plugin. I don’t know how well it works, but lot of people (especially non-developers) are comfortable with the WordPress UI, so it could be a nice combo.

                  1. 18

                    “Static sites, on the other hand, are impossible to hack: there is no code running, and thus no vulnerabilities to exploit!”

                    That’s overstating it. We were hacking static sites all the time before the invention of web applications. We did it via their web servers or other software running on the machine. Sometimes hit the boxes of people connecting to the machine with user or admin privileges. Vulnerabilities are still found in web servers. People still use buggy software in the trusted network. So, this claim should instead say they’re either more secure or harder to hack since they just depend on a web server without extra, bug-ridden code on top. Then, maybe a recommendation of using some specific ones that have good, track record both in number of vulnerabilities and how quickly they patch them. Maybe there should be a mention of Let’s Encrypt in that section, too. Kind of a combined recommendation.

                    I like your additional sections on ownership and portability. Those were either not covered or barely discussed in some prior write-ups on static sites.

                    1. 4

                      That’s true – thanks for calling it out. What I typically do is deploy my static sites into an S3 bucket (with restricted permissions, obviously), then throw it behind Cloudfront for speed.

                      Netlify is another awesome service that makes this stuff really easy/simple and mitigates a lot of the misconfigs for web servers/etc. that many people run into.

                      1. 4

                        I like your additional sections on ownership and portability.

                        Funny enough, I have a problem with one of those sections.

                        Take a look at any outsourced products, and compare them to in-house products: with very few exceptions, in-house projects are almost always better.

                        I’m currently doing a POC of a competitor of Okta for enterprise authn/authz (ha!). The only metric favoring our in-house solution was cost.

                        I’ve found that outsourced products are often more reliable, secure, and maintainable than in-house solutions. Where in-house solutions typically win are around matching the solution to the very specific business problem they’re designed to solve. When that’s enough, it’s perfect; when it isn’t, though, the rough edges really start to be noticed.

                        1. 4

                          Heh. I think my argument there was that you shouldn’t outsource your core product code. So if you’re a web company and your website is a main driver of your business, being able to customize/control it is pretty important. Really depends on the business goals though =)

                          1. 3

                            I think that’s fair. FWIW: after going through the static site/CMS debate internally, I can also agree 100% with your conclusion.

                            I guess after further consideration what I’m arguing with here is your definition of “outsourcing”. To me, I’d rather toss dollars at SaaS to solve something that isn’t my core competency. If I can’t do that, I’d rather come up with an extremely narrowly tailored solution that addresses my very specific business needs. The least palatable option is a very general-purpose tool (like Drupal or Wordpress) that I still have to operationalize, as it tends to come with nasty headaches elsewhere.

                            It’s an odd one… I’d chose to pay someone for operational certainty around a general purpose tool over operationalizing the general purpose tool myself. I wonder what that says about me.

                            1. 2

                              I agree. For what it’s worth, you should totally check out Netlify. They make managing static sites so easy. I started using it recently and absolutely fell in love with it <3 I’m not at all affiliated with them but it is useful.

                      1. 3

                        I found Duo’s post (which this curiously doesn’t link to) to be much more informative.

                        1. 1

                          Kelby’s article is really great. This was just my recap of the issue he discovered. My company was notified about the issue a few weeks back and so I wrote up my own article about it for the deadline. Didn’t see his until after this was live.

                        1. 1

                          Cookies are insecure because they are sent with every request automatically making them susceptible to CSRF attacks.

                          1. 2

                            CSRF prevention is well-known and widely implemented in pretty much every web framework/language. Submitting a random string in forms is pretty standard now. CSRF used to be a big problem in the late 90s but hasn’t been an issue since then.

                            1. 1
                              1. 1

                                Thats quite interesting. Thanks for the link.

                            1. 18

                              The article seems to put forward two seemingly separate arguments, that localStorage is not a good API and that localStorage is insecure. I see these as separate issues. I don’t have a particularly strong opinion about whether or not the API is good or bad, it is what it is. However I do think that calling localStorage insecure is unfair. It’s no more secure or insecure than anything else in the browser: if you’re giving 3rd parties access to your website you’re inherently trusting them.

                              Things are getting completely out of hand.

                              Almost every day I stumble across a new website storing sensitive user information in local storage and it bothers me to know that so many developers are opening themselves up to catastrophic security issues by doing so.

                              […]

                              And the thing about local storage is that it is not secure! Not at all! Everyone who uses local storage to store sensitive information such as session data, user details, credit card info (even temporarily!) and anything else you wouldn’t want publicly posted to Facebook is doing it wrong.

                              [yadda yadda yadda XSS]

                              So to err on the side of caution and dramatically reduce your risk for a security incident: don’t store anything sensitive in local storage.

                              The argument boils down to “don’t use localStorage because it’s susceptible to XSS attacks” and I disagree wholeheartedly. XSS is basically game-over in the context of a website, so building your application under the assumption you’re vulnerable to XSS is, I think, misguided. I think it’s better to work your darnedest to prevent XSS attacks, and between Content Security Policy (CSP) and Subresource Integrity (SRI) I think developers have the tools they need (in modern browsers, granted*) to do so.

                              * That said, the author talks about using SameSite=strict, which has poorer support than CSP 2, let alone CSP 1.

                              Don’t tell me that JWTs are “stateless” and “fast” and you have to use local storage to store them: you’re wrong!

                              JWTs are stateless and they are “fast”. Neither of those things are negated by the fact that you can use localStorage to store them.

                              NOTE: For those of you who made it this far who are wondering if I didn’t read the article in its entirety because the author has notes at the bottom about CSP and SRI, I think CSP and SRI are solutions to the problems they’re describing and they seem to have tacked on hand-wavy dismissals at the end. The combination of CSP and SRI prevent XSS. The people who can’t use SRI because of 3rd-party ad networks or whatnot are inherently trusting those resources.

                              The article would be better to say “if you’re blindly trusting 3rd-party code, know that they can read your localStorage values and think twice” instead of trying to make sweeping the claim that localStorage is insecure.

                              1. 4

                                The article seems to put forward two seemingly separate arguments, that localStorage is not a good API and that localStorage is insecure. I see these as separate issues. I don’t have a particularly strong opinion about whether or not the API is good or bad, it is what it is. However I do think that calling localStorage insecure is unfair. It’s no more secure or insecure than anything else in the browser: if you’re giving 3rd parties access to your website you’re inherently trusting them.

                                You hit the nail on the head. Sorta.

                                I don’t really think local storage is bad or anything, but it just seems like it has a really limited use case. What really annoys me and what prompted me to write this article is the common pattern now-a-days (adopted by 99% of web developers) where you authenticate a user, store their usre info in a JWT in local storage, and somehow believe that makes the site more secure than a cookie.

                                I just wanted to emphasize how widespread XSS is, how easy it can be for your most sensitive data to be stolen (your session token), and why it’s not a good idea to trust local storage for sensitive information.

                                Finally – towards the bottom of your response you mention the thing about JWTs being stateless and fast as incorrect. JWTs are stateless (and fast, sure, once they’ve been sent to the server), but:

                                • Using a stateless JWT makes you store a lot of user info in a token which ends up making it larger (>4mb for almost all my sample apps). This means I’m now required to store it in local storage as cookies cap out at 4k.
                                • Using JWTs requires you to build centralized revocation list patterns into your server side app (unless you don’t really care), and that requires centralization again – so you lose the stateless benefits of the JWT.
                                • Using JWTs in local storage means you’ve now got to send a much larger amount of data to a web server on every request. This feels like a bad tradeoff to me. Datacenter networks will always be faster than consumer networks, and it doesn’t make sense to me to push the burden of extra data transmission to the client.
                                • Using JWTs for auth means you’re directly reducing security (speed/security tradeoff). The best practice in the security world is to always perform authn/authz in realtime to get guarantees. This is impossible by design in JWTs.

                                I’m just a fan of using normal sessions and keeping things simple. I wanted to present an argument for why I think it’s a better strategy and give people something to think about before blindly choosing to store sensitive info in local storage =)

                                1. 1

                                  You missed “localstorage auth can only work with JavaScript, so your site probably sucks to use”.

                                  Having to load the page, parse the script, then send another request and put the results into the DOM is much slower than just serving the content in the first place.

                                  1. 1

                                    What really annoys me and what prompted me to write this article is the common pattern now-a-days (adopted by 99% of web developers) where you authenticate a user, store their usre info in a JWT in local storage, and somehow believe that makes the site more secure than a cookie.

                                    Maybe my point is this: the “security” of cookies and the “security” of localStorage are incomparable. I don’t think it’s correct to say one is more secure than the other. Everything in software development is about tradeoffs, to your point. They have different attack vectors and require different approaches to securing their usage. Cookies are susceptible to CSRF and localStorage is susceptible to XSS (both probably amongst other things).

                                    How about I propose this hypothetical: if XSS wasn’t a thing, would it then be fine to store “sensitive” information in localStorage? I think yes. If so, I think it’s more useful to work towards preventing XSS than assuming game over.

                                    I just wanted to emphasize how widespread XSS is

                                    That’s a good thing to do, I agree that web developers sometimes don’t realize how susceptible their applications are. That said, I again think the article would be better to say “if you’re blindly trusting 3rd-party code, you’re susceptible to XSS, they can read your localStorage values, and think twice about using localStorage” instead of trying to make sweeping the claim that localStorage is insecure.

                                1. 3

                                  Do you have any examples of sensitive data being leaked because of local storage?

                                  I also have some bad news for you and its name is PWA.

                                  1. 2

                                    PWA’s don’t prevent you from using cookies for sessions.

                                    1. 1

                                      There are a lot of examples: I work in security for a living. I recently discovered a pretty well-known vendor of analytics services who had their CDN’d JS scripts (that tons of customers have embedded in their websites) sitting on a publicly accessible (with write access!) S3 bucket.

                                      For PWAs: I honestly have no idea how to secure those things. It’s hard =/

                                      1. 1

                                        Are there examples I can look at? That I can use to make the case myself. Any documented instances of the threat vectors mentioned in the article.

                                    1. 3

                                      Why focus so much on local storage? You shouldn’t store sensitive information anywhere in your browser.

                                      1. 3

                                        I solely focused on that because this is the trend I see: developers building web apps storing JWTs in localStorage. I could have focused on the larger picture but it was easier to pick on just this one pattern as it is so common.

                                        1. 1

                                          I’ve always stored them in cookies tbh, and from a security perspective - there is nothing wrong w/ storing JWTs in cookies or local storage. That’s literally what they’re for.

                                        2. 3

                                          It’s necessary to store auth tokens so you don’t need to type your password with every request.

                                          1. 1

                                            Yep, but cookies seem to work better for that use case.

                                        1. 7

                                          I‘m not convinced that the current trend to put authentication info in local storage is entirely driven by the thought of being able to bypass the EU cookie banner thing. I think it‘s more related to the fact that a lot of people are jumping on the JWT bandwagon and that you need to send that JWT over an Authorization header rather than the cookie header.

                                          Also, often, the domain serving the API isn‘t the domain the user connects to (nor even a single service in many cases), so you might not even have access to a cookie to send to the API.

                                          However, I totally agree with the article that storing security sensitive things in local storage is a very bad idea and that httponly cookies would be a better idea. But current architecture best-practice (stateless JWT tokens, microservices across domains) make them impractical.

                                          1. 4

                                            Hey! You are correct in that this isn’t the main reason people are doing this – but I’ve spoken to numerous people who are doing this as a workaround because of the legislation which is why I wrote the article =/

                                            I think one way of solving the issue you mention (cross-domain style stuff) is to use redirect based cookie auth. I’ve recently put together a talk which covers this in more details, but have yet to write up a proper article about it. It’s on my todo list: https://speakerdeck.com/rdegges/jwts-suck-and-are-stupid

                                            1. 2

                                              Ha! I absolutely agree with that slide deck of yours. It’s very hard to convince people though.

                                              One more for your list: having JWTs valid for a relatively short amount of time but also provide a way to refresh them (like what you’d do with an oauth refresh token) is tricky to do and practically requires a blacklist on the server, reintroducing state and defeating the one single advantage of JWTs (their statelessnes, though of course you can have that with cookies too)

                                              JWTs to me feel like an overarchitectured solution to an already solved problem.

                                              1. 1

                                                There’s a third use case: services that are behind an authentication gateway (like Kong) and whenever a user is doing an authenticated request then the JWT is injected by the gateway into the request headers and passed forward to the corresponding service.

                                                But yes, a lot of people are using $TECHNOLOGY just because it’s the latest trend and discard “older” approaches just because they are no longer new which is quite interesting because we today see a resurgence of functional languages which are quite old, but I digress.

                                              2. 2

                                                you need to send that JWT over an Authorization header rather than the cookie header.

                                                Well, you don’t need to, but many systems require you to. It’s completely possible — although it breaks certain HTTP expectations — to use cookies for auth² is after all quite an old technique.

                                                1. 1

                                                  This is true – you could definitely store it in a cookie – but there’s basically no incentive to do so. EG: Instead just use a cryptographically signed session ID and get the same benefits with less overhead.

                                                  The other issue w/ storing JWTs in cookies is that cookies are limited to 4kb of data, and JWTs often exceed that by their stateless nature (trying to shove as much data into the token as possible to remove state).

                                                2. 1

                                                  Could you point me to some sort of explanation of why using localStorage is bad for security? Last time I looked at it, it seemed that there was no clear advantage to cookie based storage: http://blog.portswigger.net/2016/05/web-storage-lesser-evil-for-session.html

                                                  1. 2

                                                    Just as the article says: if you mark the session cookie as http only, then an XSS vulnerability will not allow the token to be exfiltrated by injected script code.

                                                    1. 1

                                                      Are we reading the same article? What I see is:

                                                      • “The HttpOnly flag is an almost useless XSS mitigation.”
                                                      • “[Web storage] conveys a huge security benefit, because it means the session tokens don’t act as an ambient authority”
                                                      • “This post is intended to argue that Web Storage is often a viable and secure alternative to cookies”

                                                      Anyway, I was just wondering if you have another source with a different conclusion, but if not, it’s OK.

                                                      1. 3

                                                        I disagree with the author of that article linked above. I’m currently typing out a full article to explain in more depth – far too long for comments.

                                                        The gist of it is: HttpOnly works fine at preventing XSS. The risk of storing session data in a cookie is far less than storing it in local storage. The attack surface is greater there. There are a number of smaller reasons as well.

                                                        1. 1

                                                          Great, I would appreciate a link (or a Lobsters submission) when you’ve written it.

                                                1. 5

                                                  Great guide! One small note; you should use AWS credentials associated with an IAM role that has the least privileges required to get the job done. In this case, using creds from an IAM role that could only write to the particular S3 bucket and invalidate the specific CloudFront domain would be most secure.

                                                  1. 4

                                                    This is correct – although right now there is a bug with IAM cloudfront rules, which means you must have full cloudfront access to do even a simple invalidation :(

                                                  1. 9

                                                    I’m Randall Degges. I’ve been programming since I was ~12 years old, and I just turned 28. I suppose if I add that up, it would mean I’ve been coding (poorly, heh) for ~16 years now.

                                                    I’m the lead Developer Evangelist now over at Stormpath (https://stormpath.com). At Stormpath, I spend most of my time hacking on open source authentication and authorization libraries in Python, Node.js, and Go. I also give tech talks, go to meetups, and do the social outreach stuff you’re all familiar with: blogs, screencasts, etc.

                                                    It’s a fun position!

                                                    Over the last 3 years or so, my hobby has been bodybuilding. I spent all my life being incredibly overweight, and decided that if I could write code and do complex software stuff, then I should at the very least be able to figure out how to diet and look good. After doing a lot of research, slowly learning the ins-n-outs, etc., I think I’ve finally made it =)

                                                    Here’s me when I got married, vs me now:

                                                    Overall, it’s been insanely great. Feels so good being in shape now vs before. It’s been really fun to push myself hard to reach my goals ^^

                                                    1. 2

                                                      Wow, congratulations on all the weight loss and muscle gain! You look great!

                                                      1. 2

                                                        Thanks! <333

                                                    1. 5

                                                      I started lifting weights a few years ago because I was pretty fat from sitting at my desk all day, and decided I wanted to get into shape.

                                                      It’s been a few years now, and I’m sort of addicted to the feeling of becoming bigger and stronger. I started learning about bodybuilding, nutrition, etc., and now do it as a part-time hobby!

                                                      1. 2

                                                        I love this story. I’ve read it many times over the years, but it always continues to inspire me.

                                                        1. 8

                                                          Hey Carlos!

                                                          I’m also quite involved in the telephony world, I’m the creator of OpenCNAM: http://www.opencnam.com/

                                                          I’m quite familiar with playing data before the call is Answered using Asterisk, but my understanding of the US law is that doing that is technically considered ‘toll fraud’ by the big phone companies. You might want to make sure you’re safe from prosecution by the big US telcos (wouldn’t want ya to get into trouble).

                                                          Looks like a very cool service otherwise though! All the best

                                                          1. 5

                                                            Thanks for the advice. This is definitely a gray area; some providers have specific ToS against missed calls, others are happy with them but charge for missed calls, and we’re in a partnership with a local SIP provider who knows about the project and has reached an agreement with us.

                                                            Currently our major problem is the lack of interoperability between networks – especially caller ID, of which I’m sure you know the pain. I’m astonished that calling from one network in one country to another abroad even works. Many of them ignore basic SIP commands or just do the opposite (603 vs 486, you know)

                                                            Anyway, I could ramble about this all day. Telco trouble is one of our major worries, for sure.

                                                            1. 1

                                                              Welp, best of luck to ya! Tis a very cool project, I hope things work out well.

                                                          1. 2

                                                            I loveeee this site – IMO, it’s one of the best python resources for new python developers. Matt is also a personal friend, and really awesome guy. +1

                                                            1. 8

                                                              I actually run this service =) Surprised to see it on here! Am happy to answer any questions (if there are any) =)

                                                              1. 2

                                                                Oh, that is neat! :) I hadn’t heard of it, but yes, it looks as though it fills a real need. I like that the examples are for a broad range of languages.

                                                                1. 3

                                                                  Ya! I started it a while back as a small need – it’s useful for dynamic DNS type stuff, and auto-provisioning tools. I tried to make the libraries really robust and fool-proof. They all use exponential backoff and retry logic, and try to smartly handle all network errors / etc =)

                                                                  1. 2

                                                                    Nice :)

                                                                2. 2

                                                                  This looks neat, I usually hit http://whatismyip.akamai.com when I need it programatically as they just return the plaintext, but I never remember the URL and have to go search my browser history for it every damn time!

                                                                  I do have a small suggestion for the ruby example however, open-uri is easy to use, but devs who use it should be aware what they’re doing with it - if you’re using it to load in external resources you could be opening yourself up to a remote code exploit. http://sakurity.com/blog/2015/02/28/openuri.html has more information.

                                                                  Might I suggest you just drop back to net/http (which is all open-uri is wrapping) instead for the example? It’s still pretty small:

                                                                  require "net/http"
                                                                  
                                                                  ip = Net::HTTP.get(URI("https://api.ipify.org"))
                                                                  puts "My public IP Address is: " + ip
                                                                  
                                                                  1. 2

                                                                    Thanks for the suggestion! I’m not a ruby guy, so the ruby example was cobbled together. I just updated the code snippets! <33

                                                                    1. 2

                                                                      Awesome, thanks! I should’ve noticed it was on github and opened an issue there heh. :-)

                                                                    2. 1

                                                                      I found http://icanhazip.com to be easy to remember. It also return the IP in text/plain.

                                                                  1. 2

                                                                    Very nice documentation site for this, that was a nice touch. Although if you must do content negotiation via query string, I wish it at least supported Accept headers as a fallback. Now I’m tempted to learn enough Go to open a PR.

                                                                    1. 2

                                                                      I’ll add this in =) I’ve been meaning to do it. Initially I wrote this to solve a small need, and got a lot of requests for the whole querystring approach, but I’d like to make it support the pure REST stuff too ^^