简体   繁体   English

自定义安全HTTP标头是否违反关注点分离

[英]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? 自定义应用程序特定的,与安全性相关的HTTP标头是否违反关注点分离,是否被认为是不好的做法? 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. 我们使用的是基于令牌的身份验证,其中令牌具有固定的生存期,并且每次经过身份验证的客户端调用Web API都会发出新的令牌。 SPA client may call the server with AJAX in two contexts SPA客户端可以在两种情况下使用AJAX调用服务器

  • 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. 我意识到基于Websocket的刷新将是一种解决方案,但是由于特定的原因,我们决定坚持使用定时AJAX调用。 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. 另一个解决方案是提供令牌刷新作为单独的端点,但是从客户端的角度来看这将违反DRY原则,并且使用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). 理想情况下,安全性对用户界面应该是透明的,因此可以在不了解任何安全性的情况下对新客户端进行编码(尤其是在使用cookie时)。

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). 具有很短寿命(例如:1小时)的访问令牌和具有更长寿命(例如:24小时)的刷新令牌。

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. 当用户首次对您的服务进行身份验证时,将生成Access和Refresh令牌及其相应的超时。
  • These tokens are both set in HTTP cookies that the client-side JS cannot access. 这些令牌都设置在客户端JS无法访问的HTTP cookie中。
  • 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. 从现在开始,每次用户的浏览器向您的服务发出请求时,您都会从Cookie中解析出访问令牌,检查其是否有效,然后允许该请求。
  • 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. 如果访问令牌不再有效(如果它已过期),则将从cookie中解析出刷新令牌,并查看其是否有效。
  • 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. 如果刷新令牌有效,则将生成一个具有1小时寿命的NEW Access令牌,并使用新的on覆盖旧的Access令牌cookie。
  • 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. 如果刷新令牌无效,则只需将301重定向返回到应用程序的登录页面,从而迫使用户再次手动进行重新认证。

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. 最大会话长度是技术性的(刷新令牌的持续时间+访问令牌的持续时间)-aka:在此示例中为25小时。
  • 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 . 上面的流程的好处是,它是一个Web授权标准: OAuth2

The OAuth2 Password Grant flow does EXACTLY what you're describing. OAuth2密码授予流程完全符合您的描述。 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. 我强烈建议您做的是在服务器和客户端上都实现OAuth2库,它将为您解决这些需求。

Now -- regarding the tokens, most OAuth2 implementations now-a-days will generate tokens as JSON Web Tokens . 现在-关于令牌,当今大多数OAuth2实现都会将令牌生成为JSON Web令牌 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. 我用Python,Node和Go编写了几种流行的身份验证库-因此,这来自于我在过去几年中使用这些协议的直接经验。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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