7

I have a microservice app. hub.example.com handles authentication. When a users logs in, I need to set a cookie on learn.example.com What is a secure way to set this? I'm aware of a few approaches:

  • hub sets the cookie on example.com This works, but the cookie propagates to other subdomains. Also a risky subdomain like lab could set the cookie.
  • learn provides a setCookie controller. Hub returns a redirect (or possibly a different mechanism) to learn/setCookie?session=123 This works, but any domain (even evil.com) can use the controller.
  • The setCookie controller could verify Origin and only allow hub. I'm not quite sure what the usability and security consequences of this are.
  • hub contacts learn direct with server-to-server authentication and get's a one-time token. hub then sends a redirect to the user's browser to learn/setCookie?token=token (thanks to Fire Quacker)

Any suggestions about this would be most appreciated.

9
  • For the second option, would it be possible to do something like a TOTP between the microservices for hub and learn? Apr 20, 2020 at 17:16
  • @FireQuacker - I guess so, there's particular constraints in this environment. Can you explain a bit more what you mean?
    – paj28
    Apr 20, 2020 at 17:28
  • 1
    I'm trying to think of a way to mitigate attacks from evil.com. Using some sort of authentication between hub and learn seems the only way to do it. TOTP popped into my head first (with a shared seed and the token being passed as a URL parameter), but it's probably neither the easiest method nor the most efficient; it just popped into my head first. Apr 20, 2020 at 18:03
  • @FireQuacker - Gotcha. hub could contact learn direct (with server-to-server authentication), get a one-time token, then pass this via the user's browser. That sounds a nice and secure approach. Some overhead, but might be worth it. By the way, there was a terrible typo in my comment, I meant to say "there's NO particular constraints" ! Gonna edit the question to include your idea as an option. Thank-you!
    – paj28
    Apr 20, 2020 at 18:17
  • Can you make learn a subdomain of hub? Apr 20, 2020 at 21:13

4 Answers 4

3

Use an iframe that loads a simple page hosted on learn.example.com that listens for JS message events to pass info between domains. You can trust message.origin, which makes it easy to filter with the JS. It basically subscribes a message event and when one happens, ask if the sender is on the list, and if so, sets the cookie. 3 simple steps.

This actually rides on top of a lot of other battle-tested techs like SOP, CSP (optional), and sandboxing. This leaves a lot less to the imagination and doesn't require extra server handling, provisioning, configuration, patching, testing, etc.

4
  • Ah, that is really neat. I've not used message.origin but that feels more solid than the origin header, which has a few too many caveats. I'm slightly hesitant to introduce a hard dependency on JS. The prototype so far works without JS. But everyone has it and I've made plenty of other sites that have a hard dependency. So nice one!
    – paj28
    Apr 20, 2020 at 19:12
  • 1
    you could use a <noscript><meta redirect> in the head to do it server-side when needed, but this should work pretty widely for the (low) cost...
    – dandavis
    Apr 20, 2020 at 19:15
  • When you say the fancy way, do you mean option 4 in the question with the one-time token?
    – paj28
    Apr 20, 2020 at 19:17
  • I've thought about this a bit. This is actually equivalent to option 3, it's the client-side version of it. I know I said the origin header has caveats, but I've reconsidered. Your answer was really helpful, but it's option 3 that's the best answer. All the same benefits as yours, and doesn't rely on JavaScript. Thanks again for the answer.
    – paj28
    Apr 21, 2020 at 6:31
2

Another answer mentioned JWT. If you had the ability to support JWT, you could redirect with the JWT in the in the url.

  1. hub.example.com handles authentication and creates a JWT
  2. hub.example.com redirects to learn.example.com/?jwt={token}
  3. learn.example.com verifies JWT and serves the user

Replay Attack is prevented by using the jti field within the JWT

Here is an example of this implementation from Zendesk

This does bring the overhead of JWT and all of the security concerns that come with it.

3
  • Thanks for the answer. I think this is more-or-less option 4 in question, with the JTI being the one-time token? Does JWT bring much benefit? I could use JWT, although it's good to keep things as simple as possible.
    – paj28
    Apr 22, 2020 at 0:16
  • JWT has its place, and this is one of them, imho. I would recommend you do some reading up on JWT and see if it is a good fit for your stack this a good starting place jwt.io. Just be careful with the implementation you use, this article explains why auth0.com/blog/…
    – iraleigh
    Apr 22, 2020 at 0:23
  • Oh yeah, I've read about those algorithm tweaking attacks. Very clever technique. I know that most libraries are patched now, but it does make me worried about JWT. I don't really need features like support for multiple signing algorithms. In my case, it's a lot of complexity for little gain. Although I can see its place for more complex scenarios, like tokens travelling between different organisations. I'll bear it in mind anyway.
    – paj28
    Apr 22, 2020 at 0:38
1

The approach with TOTP suggested above is good.

Another solutions is also possible. Instead of TOTP your hub site can sign its message and redirect to learn. The learn site will validate the signature and set the needed cookie. Think of JWT.

2
  • Ok, the one thing that troubled me with that was replay attacks. An attacker could login, capture a session ID and signature. Then if a victim visit the attacker's site, they could redirect the victim and to their session ID and signature - 1/2 way towards a session fixation attack. It may still be a sensible setup, just worried me a bit.
    – paj28
    Apr 20, 2020 at 18:48
  • @paj28: When you sign a message, you add also a timestamp to the message. And the target service rejects it if it is too old. Or you say till what time is the message valid, and the target service reject the message it is expired.
    – mentallurg
    Apr 20, 2020 at 20:30
0

Option 3 is the best choice:

  • The setCookie controller verifies the Origin header and only allows hub

This is because it:

  • Avoids the security risk of an open cookie setter
  • Doesn't have the replay issue of a signature (even with time stamp)
  • Doesn't require maintaining server state for a one-time approach
  • Doesn't depend on JavaScript

Someone commented that the Origin header can be spoofed. However, an open cookie setter is only a concern for cross-domain attacks, which take place in the victim's browser. In this scenario the Origin header cannot be spoofed.

4
  • Warning, don't rely on Origin, it can be easily forged. Just try it yourself from the terminal: curl learn.example.com -H "Origin: hub.example.com" Apr 21, 2020 at 18:17
  • Also, I have a question: do you need users to get authenticated to the hub directly? Apr 21, 2020 at 18:28
  • 1
    @AlexanderFadeev - It can only be forged when making direct requests. In the scenario of a cross-domain attack, where the attack happens in the victim's browser, it can't. The main reason is to keep passwords away from learn. I may in future be putting a lot of functionality there including a third-party learning module so it will have way more attack surface than hub which is core business functionality. It's also for scalability. There's labs and well as learn, maybe more in future. Users only login once.
    – paj28
    Apr 21, 2020 at 20:18
  • Perhaps you should add details to your own answer because it just sounds confusing like "you can trust to the Origin header". Either way thank you for clarification Apr 22, 2020 at 7:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .