【问题标题】:OAuth2 with Implicit client and csrf protection具有隐式客户端和 csrf 保护的 OAuth2
【发布时间】:2016-09-22 09:50:24
【问题描述】:

我有一个我想用 OAuth2 保护的 API。我已经使用密码 grant_type 进行了虚拟测试,一切正常。我可以请求令牌,使用它访问安全端点等。服务器充当授权和资源服务器。

后来我读到我应该使用隐式授权类型,因为客户端将是一个 javascript 应用程序。

我的客户端是这样配置的:

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {// @formatter:off
clients
    .inMemory().withClient("web")
    .redirectUris("http://localhost:3000")
    .secret("secret")
    .authorizedGrantTypes("implicit", "refresh_token").scopes("read", "write")
    .accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(2592000);
}

如果我尝试像这样访问端点: http://localhost:8080/oauth/authorize?grant_type=implicit&client_id=web&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A3000

我明白了:

{
  "timestamp": 1464136960414,
  "status": 403,
  "error": "Forbidden",
  "message": "Expected CSRF token not found. Has your session expired?",
  "path": "/oauth/authorize"
}

如果我是第一次调用 API,如何获得 CSRF 令牌? 如果(仅用于测试)我禁用 csrf 然后我得到这个:

{
  "timestamp": 1464136840865,
  "status": 403,
  "error": "Forbidden",
  "exception": "org.springframework.security.authentication.InsufficientAuthenticationException",
  "message": "Access Denied",
  "path": "/oauth/authorize"
}

使用密码 grant_type 设置客户端我可以进行此调用并且一切正常: http://localhost:8080/oauth/token?grant_type=password&username=test&password=123 并添加带有客户端 id/secret 的 Authorization Basic 标头。

澄清一下,我们的想法是拥有这个独特的受信任客户。所以用户应该只输入登录名/密码而不要求用户授予应用程序的访问权限。

抱歉,这是一个愚蠢的问题。我一直在阅读我能找到的所有内容,但似乎无法取得进展。

谢谢!

编辑:

我的 Spring 安全配置:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private MongoDBAuthenticationProvider authenticationProvider;

  @Autowired
  public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
  }

  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
}

我的 OAuth 配置:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends     AuthorizationServerConfigurerAdapter {

  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;

  @Override
  public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
  }

  @Override
  public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
    clients
    .inMemory().withClient("web")
    .redirectUris("http://localhost:3000")
    .secret("secret")
    .authorizedGrantTypes("implicit", "refresh_token").scopes("read", "write")
    .accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(2592000);
  }

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints)     throws Exception {
    endpoints.authenticationManager(authenticationManager);
  }  
}

服务器异常:

2016-05-25 19:52:20.744 DEBUG 34968 --- [nio-8080-exec-5] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/authorize
2016-05-25 19:52:20.744 DEBUG 34968 --- [nio-8080-exec-5] .s.o.p.e.FrameworkEndpointHandlerMapping : Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)]
2016-05-25 19:52:20.746 DEBUG 34968 --- [nio-8080-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.
at     org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(AuthorizationEndpoint.java:138) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40]
....

【问题讨论】:

    标签: oauth-2.0 spring-security-oauth2


    【解决方案1】:

    当您为隐式授权类型调用授权服务器时,您必须包含一个不透明的字符串值作为状态参数以避免 csrf 攻击。因此,授权服务器的请求 url 如下所示:

    http://localhost:8080/oauth/authorize?grant_type=implicit&client_id=web&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A3000&state=123abc

    您在 state 参数中提到的值将在响应中回显给您。然后将回显值与初始值进行比较,以确认没有发生 csrf 攻击。

    谢谢你, 索玛。

    【讨论】:

    • 感谢您的回答@Soma。我听说过“状态”参数,但仍然没有处理它与我的案例有关。我修改了它,但我仍然收到错误。我将它作为 POST 发布,我得到 csrf 错误,使用 GET 我得到拒绝访问。我将用更多代码更新我的问题,看看你是否能发现任何错误。非常感谢!
    • 请求应该是 GET。只是为了确认一下,您是否注册了客户?请使用 GET 发布详细的错误消息。谢谢
    • 我编辑了答案。非常感谢您的帮助和时间。
    • 当您访问授权端点时,您是否看到了登录屏幕?如果是这样,您必须提供用户名和密码来验证自己,然后才能使用令牌重定向到提供的重定向 uri。这是怎么回事?如果不是,请解释流程。谢谢。
    猜你喜欢
    • 2016-11-12
    • 2014-07-12
    • 2012-06-19
    • 2016-08-13
    • 1970-01-01
    • 2017-10-18
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多