简体   繁体   中英

Does custom security HTTP headers violate separation of concerns

Does custom application specific, security related HTTP headers violate separation of concerns, is it considered a bad practice? I realize using custom header to control the service would tightly couple the client with the service implementation . Or in this case, to control the security framework behavior. The context where I planned using the custom header is the following:

We are using token based authentication, where token has a fixed lifetime, and new token is issued each time authenticated client calls the web API. SPA client may call the server with AJAX in two contexts

  • User action (navigation and submit)
  • Automatic refresh (current view re-fetches data at fixed intervals)

Now, if user leaves the page open, the session never expires, as new token is generated for each automatic fetch. Somehow, we need to differentiate user action from automatic refresh in the server side, and issue new token only for user actions .

I realize Websocket based refresh would be one solution, but we have decided to stick with timed AJAX call due specific matters. Another solution would be to provide token refresh as a separate endpoint, but this would violate the DRY principle from client's perspective, and would be more cumbersome to setup with Spring Security.

Only remaining option is to embed the user/automated information in the request itself, and using a header seems a viable option here. A presence of certain header would prevent the token refresh. Easy to implement with a few lines of code.

I'm only concerned, if this couples the client too much with the service implementation. Technically, it doesn't couple client with the service, but the preceding security filter, thus leaking security concerns in the user interface. Ideally security stuff should be transparent to user interface, so new client could be coded without knowing anything about security (especially when cookies are used).

In the other hand, this solution isn't destructive or mutative. It's an optional feature. By client utilizing it, security is enhanced, but in either case never reduced (from the perspective of server, as it is). Now the question is, what principles using a optional header to enhance security is violating, and is it a valid solution in this context?

In my option the security should be maximized transparently, but I don't see how to not leak security concerns in the client in this situation.

It sounds like you're using your own home-built custom Token Authentication solution here. This is not a good idea.

I'll take a moment to explain WHY you don't want to do what you're proposing, and then what the better option is.

First off -- the problem that you're trying to solve here is that you don't want a user to remain logged into your site forever if they leave a tab open. The reason you need to fix this is because right now, you're assigning a new Access Token on EVERY REQUEST from the user.

The correct solution to handling the above problem is to have two types of token.

An Access Token that has a very short lifetime (let's say: 1 hour), and a Refresh Token that has a longer lifetime (let's say: 24 hours).

The way this should work is that:

  • When the user first authenticates to your service, the Access and Refresh tokens are generated with their respective timeouts.
  • These tokens are both set in HTTP cookies that the client-side JS cannot access.
  • From this point on, every time your user's browser makes a request to your service, you'll parse out the Access token from the cookie, check to see if it's valid, then allow the request.
  • If the Access token is no longer valid (if it has expired), you'll then parse out the Refresh token from the cookie, and see if that is valid.
  • If the Refresh token is valid, you'll generate a NEW Access token with another 1 hour lifetime, and override the old Access token cookie with the new on.
  • If the Refresh token is invalid, you'll simply return a 301 redirect to the login page of your app, forcing the user to manually re-authenticate again.

This flow has a number of benefits:

  • There is a maximum session length, which is technical (duration of Refresh token + duration of Access token) -- aka: 25 hours in this example.
  • Access tokens are short lived, which means that if a token is somehow compromised, attackers can't use it for very long to impersonate the user.

What's nice about the above flow is that it is a web authorization standard: OAuth2 .

The OAuth2 Password Grant flow does EXACTLY what you're describing. It generates both types of tokens, handles 'refreshing' tokens, handles the entire thing from start to finish in a safe, standards-compliant way.

What I'd highly recommend you do is implement an OAuth2 library on both your server and client, which will take care of these needs for you.

Now -- regarding the tokens, most OAuth2 implementations now-a-days will generate tokens as JSON Web Tokens . These are cryptographically signed tokens that provide a number of security benefits.

Anyhow: I hope this was helpful! I author several popular authentication libraries in Python, Node, and Go -- so this comes from my direct experience working with these protocols over the last several years.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM