使用JWT和基本身份验证保护REST应用程序是否有意义?(Does securing a REST application with a JWT and Basic authentication make sense?)

我有一个Spring REST应用程序,最初使用基本身份验证进行安全保护。

然后,我添加了一个登录控制器,用于创建JWT JSON Web令牌,该令牌在随后的请求中使用。

我可以将以下代码移出登录控制器并进入安全过滤器吗? 然后,我不再需要登录控制器。

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());

或者我可以删除基本身份验证?

将基本身份验证与JWT混合使用是否是一个好设计?

虽然这一切都很好,但我在这个黑暗中有点为了最好的设计这个安全。

I have a Spring REST application which at first was secured with Basic authentication.

Then I added a login controller that creates a JWT JSON Web Token which is used in subsequent requests.

Could I move the following code out of the login controller and into the security filter? Then I would not need the login controller any longer.

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());

Or could I remove the Basic authentication?

Is it a good design to mix Basic authentication with a JWT?

Although it all works fine, I'm a bit in the dark here as to best design this security.

最满意答案

假设所有通信都使用100%TLS - 无论是在登录期间还是在所有时间 - 通过基本身份验证使用用户名/密码进行身份验证并接收JWT作为交换是有效的用例。 这几乎是OAuth 2的流程之一('密码授权')的工作原理。

其思想是最终用户通过一个端点进行身份验证,例如/login/token使用您想要的任何机制,并且响应应该包含将在所有后续请求上发回的JWT。 JWT应该是一个具有适当JWT到期( exp )字段的JWS(即加密签名的JWT):这可以确保客户不能操纵JWT或使其延长寿命。

您不需要X-Auth-Token标头:为此确切的用例创建了HTTP认证Bearer方案:基本上任何跟踪Bearer方案名称的信息都是应该验证的“承载”信息。 您只需设置Authorization标头:

Authorization: Bearer <JWT value here>

但是,这就是说,如果你的REST客户端是'不受信任的'(例如启用JavaScript的浏览器),我甚至不会这么做:HTTP响应中可以通过JavaScript访问的任何值 - 基本上任何标题值或响应主体值 - 可以通过MITM XSS攻击嗅探和拦截。

最好将JWT值存储在仅安全的纯http cookie(cookie config:setSecure(true),setHttpOnly(true))中。 这保证了浏览器将:

只有通过TLS连接传输cookie, 绝对不要将cookie值用于JavaScript代码。

这种方法几乎是您需要为最佳实践安全性所做的一切。 最后一件事是确保您在每个HTTP请求上都拥有CSRF保护,以确保向您的站点发起请求的外部域无法运行。

这样做的最简单方法是设置一个安全的(但不是仅限http)cookie和一个随机值,例如一个UUID。

然后,在对服务器的每个请求中,确保您自己的JavaScript代码读取cookie值并将其设置为自定义标头,例如X-CSRF-Token,并验证服务器中每个请求的值。 除非外部客户端通过HTTP Options请求获得授权,否则外部域客户端无法为您的域的请求设置自定义头,因此任何对CSRF攻击(例如在IFrame中)的尝试都会失败。

这是目前我们知道的网络上不受信任的JavaScript客户端可用的最佳安全性。 如果你很好奇,Stormpath也会写一篇关于这些技术的文章。

最后, Stormpath Java Servlet Plugin 已经为你做了所有这些工作 (还有更多更酷的内容,包括更多的自动化安全检查),所以你永远不必写它 - 或者更糟 - 自己维护它。 查看HTTP请求认证部分和Form / Ajax示例以了解如何使用它。 HTH!

Assuming 100% TLS for all communication - both during and at all times after login - authenticating with username/password via basic authentication and receiving a JWT in exchange is a valid use case. This is almost exactly how one of OAuth 2's flows ('password grant') works.

The idea is that the end user is authenticated via to one endpoint, e.g. /login/token using whatever mechanism you want, and the response should contain the JWT that is to be sent back on all subsequent requests. The JWT should be a JWS (i.e. a cryptographically signed JWT) with a proper JWT expiration (exp) field: this ensures that the client cannot manipulate the JWT or make it live longer than it should.

You don't need an X-Auth-Token header either: the HTTP Authentication Bearer scheme was created for this exact use case: basically any bit of information that trails the Bearer scheme name is 'bearer' information that should be validated. You just set the Authorization header:

Authorization: Bearer <JWT value here>

But, that being said, if your REST client is 'untrusted' (e.g. JavaScript-enabled browser), I wouldn't even do that: any value in the HTTP response that is accessible via JavaScript - basically any header value or response body value - could be sniffed and intercepted via MITM XSS attacks.

It's better to store the JWT value in a secure-only, http-only cookie (cookie config: setSecure(true), setHttpOnly(true)). This guarantees that the browser will:

only ever transmit the cookie over a TLS connection and, never make the cookie value available to JavaScript code.

This approach is almost everything you need to do for best-practices security. The last thing is to ensure that you have CSRF protection on every HTTP request to ensure that external domains initiating requests to your site cannot function.

The easiest way to do this is to set a secure only (but NOT http only) cookie with a random value, e.g. a UUID.

Then, on every request into your server, ensure that your own JavaScript code reads the cookie value and sets this in a custom header, e.g. X-CSRF-Token and verify that value on every request in the server. External domain clients cannot set custom headers for requests to your domain unless the external client gets authorization via an HTTP Options request, so any attempt at a CSRF attack (e.g. in an IFrame, whatever) will fail for them.

This is the best of breed security available for untrusted JavaScript clients on the web today that we know of. Stormpath wrote an article on these techniques as well if you're curious.

Finally, the Stormpath Java Servlet Plugin already does all of this for you (and a lot more cool stuff, including additional automated security checks), so you don't ever have to write it - or worse - maintain it yourself. Check out the HTTP Request Authentication section and the Form/Ajax example to see how to use it. HTH!

使用JWT和基本身份验证保护REST应用程序是否有意义?(Does securing a REST application with a JWT and Basic authentication make sense?)

我有一个Spring REST应用程序,最初使用基本身份验证进行安全保护。

然后,我添加了一个登录控制器,用于创建JWT JSON Web令牌,该令牌在随后的请求中使用。

我可以将以下代码移出登录控制器并进入安全过滤器吗? 然后,我不再需要登录控制器。

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());

或者我可以删除基本身份验证?

将基本身份验证与JWT混合使用是否是一个好设计?

虽然这一切都很好,但我在这个黑暗中有点为了最好的设计这个安全。

I have a Spring REST application which at first was secured with Basic authentication.

Then I added a login controller that creates a JWT JSON Web Token which is used in subsequent requests.

Could I move the following code out of the login controller and into the security filter? Then I would not need the login controller any longer.

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail());

Or could I remove the Basic authentication?

Is it a good design to mix Basic authentication with a JWT?

Although it all works fine, I'm a bit in the dark here as to best design this security.

最满意答案

假设所有通信都使用100%TLS - 无论是在登录期间还是在所有时间 - 通过基本身份验证使用用户名/密码进行身份验证并接收JWT作为交换是有效的用例。 这几乎是OAuth 2的流程之一('密码授权')的工作原理。

其思想是最终用户通过一个端点进行身份验证,例如/login/token使用您想要的任何机制,并且响应应该包含将在所有后续请求上发回的JWT。 JWT应该是一个具有适当JWT到期( exp )字段的JWS(即加密签名的JWT):这可以确保客户不能操纵JWT或使其延长寿命。

您不需要X-Auth-Token标头:为此确切的用例创建了HTTP认证Bearer方案:基本上任何跟踪Bearer方案名称的信息都是应该验证的“承载”信息。 您只需设置Authorization标头:

Authorization: Bearer <JWT value here>

但是,这就是说,如果你的REST客户端是'不受信任的'(例如启用JavaScript的浏览器),我甚至不会这么做:HTTP响应中可以通过JavaScript访问的任何值 - 基本上任何标题值或响应主体值 - 可以通过MITM XSS攻击嗅探和拦截。

最好将JWT值存储在仅安全的纯http cookie(cookie config:setSecure(true),setHttpOnly(true))中。 这保证了浏览器将:

只有通过TLS连接传输cookie, 绝对不要将cookie值用于JavaScript代码。

这种方法几乎是您需要为最佳实践安全性所做的一切。 最后一件事是确保您在每个HTTP请求上都拥有CSRF保护,以确保向您的站点发起请求的外部域无法运行。

这样做的最简单方法是设置一个安全的(但不是仅限http)cookie和一个随机值,例如一个UUID。

然后,在对服务器的每个请求中,确保您自己的JavaScript代码读取cookie值并将其设置为自定义标头,例如X-CSRF-Token,并验证服务器中每个请求的值。 除非外部客户端通过HTTP Options请求获得授权,否则外部域客户端无法为您的域的请求设置自定义头,因此任何对CSRF攻击(例如在IFrame中)的尝试都会失败。

这是目前我们知道的网络上不受信任的JavaScript客户端可用的最佳安全性。 如果你很好奇,Stormpath也会写一篇关于这些技术的文章。

最后, Stormpath Java Servlet Plugin 已经为你做了所有这些工作 (还有更多更酷的内容,包括更多的自动化安全检查),所以你永远不必写它 - 或者更糟 - 自己维护它。 查看HTTP请求认证部分和Form / Ajax示例以了解如何使用它。 HTH!

Assuming 100% TLS for all communication - both during and at all times after login - authenticating with username/password via basic authentication and receiving a JWT in exchange is a valid use case. This is almost exactly how one of OAuth 2's flows ('password grant') works.

The idea is that the end user is authenticated via to one endpoint, e.g. /login/token using whatever mechanism you want, and the response should contain the JWT that is to be sent back on all subsequent requests. The JWT should be a JWS (i.e. a cryptographically signed JWT) with a proper JWT expiration (exp) field: this ensures that the client cannot manipulate the JWT or make it live longer than it should.

You don't need an X-Auth-Token header either: the HTTP Authentication Bearer scheme was created for this exact use case: basically any bit of information that trails the Bearer scheme name is 'bearer' information that should be validated. You just set the Authorization header:

Authorization: Bearer <JWT value here>

But, that being said, if your REST client is 'untrusted' (e.g. JavaScript-enabled browser), I wouldn't even do that: any value in the HTTP response that is accessible via JavaScript - basically any header value or response body value - could be sniffed and intercepted via MITM XSS attacks.

It's better to store the JWT value in a secure-only, http-only cookie (cookie config: setSecure(true), setHttpOnly(true)). This guarantees that the browser will:

only ever transmit the cookie over a TLS connection and, never make the cookie value available to JavaScript code.

This approach is almost everything you need to do for best-practices security. The last thing is to ensure that you have CSRF protection on every HTTP request to ensure that external domains initiating requests to your site cannot function.

The easiest way to do this is to set a secure only (but NOT http only) cookie with a random value, e.g. a UUID.

Then, on every request into your server, ensure that your own JavaScript code reads the cookie value and sets this in a custom header, e.g. X-CSRF-Token and verify that value on every request in the server. External domain clients cannot set custom headers for requests to your domain unless the external client gets authorization via an HTTP Options request, so any attempt at a CSRF attack (e.g. in an IFrame, whatever) will fail for them.

This is the best of breed security available for untrusted JavaScript clients on the web today that we know of. Stormpath wrote an article on these techniques as well if you're curious.

Finally, the Stormpath Java Servlet Plugin already does all of this for you (and a lot more cool stuff, including additional automated security checks), so you don't ever have to write it - or worse - maintain it yourself. Check out the HTTP Request Authentication section and the Form/Ajax example to see how to use it. HTH!