6

当问这个问题时,我正在寻找实现我自己的 AuthenticationProvider 的指导。我的意思是:

到目前为止,我已经了解到 Spring Security 会询问 AuthenticationProvider 对象是否用户已通过身份验证。目前我正在使用 DaoAuthenticationProvider 来处理我自己的客户 UserDetailService 返回的用户名和密码。一切都很好!Spring 支持许多不同的 AuthenticationProvider,例如有一个用于 LDAP、Jdbc、DAO(如上所述),我什至能够找到一个用于 Kerberos。但是 SRP 没有身份验证提供程序,因此需要编写一个。

我的问题如下:

当我们使用 DaoAuthenticationProvider 即用户/密码身份验证时,我们有一个 html 表单,其中输入了用户名和密码,然后一个按钮负责提交这两个参数。购买的参数通过某些传输通道传输到服务器,即只需单击一下,我们就可以在同一个 http 请求中发送所有数据,即身份验证所需的所有数据。这可以在 UsernamePasswordAuthenticationFilter 中看到。这里“attemptAuthentication”方法采用“HttpServletRequest request”,其中包括用户名和密码。到现在一切都好。

 public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        ...
        }

好吧,在简单的 SRP 中,我们还有一个包含用户名和密码的表单,除了密码!!!必须!!!不能通过网络传输。为了实现该约束,必须在客户端和服务器之间进行“讨论”,即必须交换以下参数。

1) 用户名​​ (I),

2) 一个名为“A”的值

3) 一个名为“B”的值

4) 一个名为“M1”的值

5) 一个名为“M2”的值

好吧,让我们假设有一个名为“SrpAuthenticationProcessingFilter”的过滤器,如果新的身份验证协议更像是来自 RFC 5054 的对话,那么过滤器应该是什么样子。

   Client                                            Server

   Client Hello (I)        -------->
                                               Server Hello
                                               Certificate*
                                        Server Key Exchange (N, g, s, B)
                           <--------      Server Hello Done
   Client Key Exchange (A) -------->
   [Change cipher spec]
   Finished                -------->
                                       [Change cipher spec]
                           <--------               Finished

   Application Data        <------->       Application Data

在这里,我们有一个客户需要

  • a) 首先发送他的用户名 (I)
  • b) 然后服务器需要以值 B 响应。(在这种情况下,N,g,s 并不是真正需要的)
  • c)客户端发送它的“值A”
  • d) 客户端使用来自服务器的值 B 并基于该值计算密钥。
  • e) 服务器也根据值 A 计算密钥。
  • f) 客户端向服务器发送值 M1。
  • g) 服务器获取 M1 值并基于以 M1 值作为参数的公式,他能够验证密钥是否匹配,如果计算出的购买方的密钥匹配,则用户通过身份验证,并且产品即共享密钥可以进一步用于其他处理。

与用户名和密码验证相比,这些是 7 个步骤而不是一个步骤。其中 3 个需要在 SrpAuthenticationProcessingFilter 之前发生。现在我知道有可能将用户名与“值 A”一起发送,从而缩短步骤数,但我想严格遵守 RFC。永远不要走简单的路,对吧?

问题实际上是我在哪里放置负责客户端和服务器之间的乒乓(对话)的代码,即上面提到的前 3 个步骤 a、b 和 c。它应该将它们放在 SrpEntryPoint 对象中还是其他地方。if else 那么是在 SpringSecurity 的上下文中吗?

我可以解决这个问题的一种方法是使用 websockets,但我也想让该身份验证独立于任何第 5-7 层协议,例如 websockets、http、spdy 等。这意味着第一个实现应该是通过简单的 http 请求/响应,然后使用任何其他协议。

因此,目前实施 SRP 的正确结构是:

  • SRPAuthenticationEntryPoint 实现 org.springframework.security.web.AuthenticationEntryPoint - 这基本上说明了如果对受保护资源的请求进入但用户尚未经过身份验证应该做什么。在这里,我们可以在资源尚未经过身份验证的情况下进行重定向。也许这也是负责步骤 a、b、c 的地方,不确定这是否是正确的地方。请求指导和信息!

  • SrpAuthenticationProcessingFilter 扩展了 GenericFilterBean。SrpAuthenticationProcessingFilter 的存在是为了进行部分验证,例如检查 srp 参数是否接收到正确的并对应于服务器设置的 srp 参数。在这里重要的是要提到 SrpAuthenticationProcessingFilter 没有进行任何用户名验证,即需要在调用 SrpAuthenticationProcessingFilter 之前的一步中进行,可能是 SrpEntryPoint 或我不知道如何调用它的其他步骤。SrpAuthenticationProcessingFilter 有一个方法“doFilter”,其中正在创建第二个结构,即 SrpAuthenticationToken。

  • SrpAuthenticationToken 扩展 org.springframework.security.authentication.AbstractAuthenticationToken。在我的理解中,该令牌与 DAO 对象类似,该令牌映射成功身份验证所需的所有字段。当部分验证的参数被填充到 SrpAuthenticationToken 中时,SrpAuthenticationToken 被传递给 org.springframework.security.authentication.AuthenticationManager 接口的authenticat方法,即类似的东西

    myAuthentication = authenticationManager.authenticate(SrpAuthenticationToken);

根据 Spring Security 配置中配置的身份验证提供程序,在我们的案例中调用 SrpAuthentication 提供程序,即:

@Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
          .authenticationProvider(sRPAuthenticationProvider);
}
  • SRPAuthenticationProvider - 实现 org.springframework.security.authentication.AuthenticationProvider。在这里,步骤 d、e、f 和 g 正在被验证和比较。如果发生错误,则抛出新的 BadCredentialsException("Invalid username/password/Verifiere") 异常。

  • SrpSessionValidator - 这个只负责验证 Srp 会话的特定参数,并且会从 SrpAuthenticationProcessingFilter 以及在 SrpAuthenticationProcessingFilter 之前的一步中调用,以验证用户名是否存在于数据库中。

我只知道如何实现 Srp 身份验证,因此如果这完全有意义并且 SRPAuthenticationEntryPoint 是步骤 a、b 和 c 的正确位置,我想要一些评论。我觉得这不是正确的地方。

非常感谢任何反馈。

问候,

铁托

Addition1(2014 年 11 月 21 日)-> 作为对“在哪里放置负责客户端和服务器之间的 ping pong(对话)的代码,即前 3 个步骤 a、b 和 c”的问题的回答这很可能是一个标准(我称之为协商)过滤器,它将承担这项工作。

现在我想重新表述这个问题,即在身份验证完成之前以及在接收到 M1 和 M2 消息之前,即步骤 1、2 和 3。我应该把那个对象放在哪里?即它应该是一个对象应该存在的地方,例如 60 秒,然后在没有收到 M1 和 M2 消息的情况下自动删除。我的意思是“SecurityContextHolder”对象之前的某个对象。我只是不知道与弹簧安全相关的对象/上下文的名称是什么,我也不知道这种结构是否存在?

4

2 回答 2

2

我的方法是使用 AJAX 运行协议的第一部分,直到创建AM1在客户端,然后将它们作为登录凭据发布到服务器,并使用 Spring Security 进行检查。

要了解这是如何工作的,有一个junit-js测试,它使用ThinbusTestSRP6JavascriptClientSessionSHA256.js上运行 javascript 客户端对象和 java 服务器对象之间的相互身份验证(注意 maven 构建使用 JDK javascript 运行时运行此单元测试):

    // note the following exchange is written in javascript calling client js and invoking server java which is run by JUnit-JS using the JDK javascript runtime so it shows both sides of the full authentication in one unit test method

    // normal login flow step1a client: browser starts with username and password given by user at the browser
    client.step1(username,password);

    // normal login flow step1b server: server starts with username from browser plus salt and verifier saved to database on user registration. 
    var B = server.step1(username, salt, v);

    // normal login flow step2a client: server sends users salt from user registration and the server ephemeral number
    var credentials = client.step2(salt, B);

    // normal login flow step2b server: client sends its client ephemeral number and proof of a shared session key derived from both ephermal numbers and the password
    var M2 = server.step2(credentials.A, credentials.M1);

    // normal login flow step3 client: client verifies that the server shows proof of the shared session key which demonstrates that it knows actual verifier
    client.step3(M2);

username显然,javascript 客户端仅以and开头password。服务器使用username来解析salt并生成随机B. 客户端从服务器获得saltB生成其随机数AM1即密码证明。作为参数的服务器step2M1检查用户密码证明的服务器,如果证明不正确,它将抛出异常。然后服务器发送M2这是它具有用户验证器的服务器证明,v这是为了防止假服务器欺骗真实服务器。

Thinbus-srp-js-demo上,有一个浏览器使用Thinbus通过 AJAX 对 Java 服务器执行 SRP 的演示。您可以使用 AJAX 方法(例如 Spring MVC AJAX)重新使用 JAX RS 来执行在客户端创建+的第一步,然后使用登录表单发布这些到 Spring Security 并让 Spring Security通过运行验证+在 junit-js 测试中显示的服务器对象上。然后,您可以从由用户名键入的并发映射中解析由 AJAX 创建的服务器对象。AM1AM1step2AuthenticationManager

M2一个小提示是,如果您使用 HTTPS 访问服务器,我会考虑将服务器证明作为可选选项进行检查。如果您不使用 HTTPS,那么服务器欺骗意味着他们可以为用户提供一个发送密码并忽略错误 M2 的页面;因此 M2 证明不提供网页上下文中的安全性。使用电话间隙之类的东西将 html/js 打包到本机应用程序中的移动应用程序将受益于 M2 检查;可以在用户登录后添加到页面中,由可信代码检查。

于 2014-12-20T21:29:17.993 回答
2

在https://bitbucket.org/simon_massey/thinbus-srp-spring-demo有一个弹簧安全 SRP 实施

自述文件页面说:

集成的一个显着特点是除了配置自定义的SrpAuthenticationProvider.

它还说:

Spring Security 不会将用户 HTTPSession 暴露给 AuthenticationProvider。所以演示代码使用一个带有超时的 Guava 缓存来在登录交换的短暂时间内保存 SRP6JavascriptServerSession。从 Thinbus 1.2.1 开始,会话是可序列化的,因此大型无状态网站的替代方法是将 SRP6JavascriptServerSession 对象保存在数据库中而不是内存缓存中。

于 2015-10-05T21:42:49.617 回答