密码哈希算法用于无状态基本身份验证 API 是什么?

huangapple go评论76阅读模式
英文:

How password hash algorithm for stateless basic authentication api?

问题

我有一个使用spring框架的Web服务API,它会从一个属性文件中对用户进行身份验证。到目前为止,密码是使用bcrypt算法进行存储的。

问题:我的API是无状态的,因此任何basic auth请求都会强制进行bcrypt身份验证的重新计算,从而导致每个请求大约100ms的延迟。

问题:在无状态API的每个请求中都要使用的用户密码加密算法(无论是在属性文件还是数据库中),有哪些建议使用的算法?

重点考虑身份验证性能,但不忽视安全性。

英文:

I have a spring webservice api that authenticates users from a properties file. The passwords are stored in bcrypt algorithm so far.

Problem: my api is stateless, thus any basic auth request will force bcrypt authentication to recalculate, causing delays of approx 100ms on each request.

Question: which algorithm is advised to be used for encrypting user passwords (no matter if in properties file or db), that are to be used on every request on a stateless api?

With focus on authentication performance, but not neglecting security.

答案1

得分: 3

我会跳过加密密码,改用令牌。一个这样的解决方案是JWT(Json Web Tokens),Spring已经默认支持它们。

你可以在这里查看一个示例:这里

你甚至可以更进一步(这是我的做法),将所有这些都委托给一个OAuth提供者。我通常使用Keycloak来实现这一点。

英文:

I'd skip encrypting the password and use tokens instead. One such solution is JWT (Json Web Tokens) and Spring comes with support for them out of the box.

You can take a look at an example here.

You can go even further (this is what I do) and delegate all of this into an OAuth provider. I usually use Keycloak for this.

答案2

得分: -2

最终,我决定创建一个缓存身份验证处理程序。它会缓存基本身份验证的密码,以及相应的哈希 bcrypt 字符串。但仅在认证成功时才会缓存。

这样,我可以加速已知客户端的有效身份验证(因为我不必为它们重新计算 bcrypt 哈希匹配),但仍然保留了 bcrypt 算法的防暴力破解优势。

如下是 Spring 特定的实现:

static class CachingDelegatingPasswordEncoder implements PasswordEncoder {
    private final PasswordEncoder delegate = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    private final Map<String, String> cache = new HashMap<>();

    @Override
    public String encode(CharSequence rawPassword) {
        return delegate.encode(rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        String cachedPassword = cache.get(rawPassword);
        if (cachedPassword != null && StringUtils.equals(cachedPassword, encodedPassword))
            return true;

        boolean match = delegate.matches(rawPassword, encodedPassword);
        if (match) cache.put(rawPassword.toString(), encodedPassword);

        return match;
    }
}

@Configuration
static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        DaoAuthenticationProvider p = new DaoAuthenticationProvider();
        p.setPasswordEncoder(new CachingDelegatingPasswordEncoder());
        p.setUserDetailsService(userDetailsService);
        p.afterPropertiesSet();
        builder.authenticationProvider(p);
    }
}
英文:

In the end I decided to create a caching authentication handler. It cashes the password from basic auth, and the belonging hashed bcrypt string. But only if authentication was successful.

This way I can speed up known clients with valid authentications (as I won't have to recalculate the bcrypt hash match for them), but still keep the brutforce benefits from bcrypt algorithm.

As follows the spring-specific implementation:

static class CachingDelegatingPasswordEncoder implements PasswordEncoder {
		private final PasswordEncoder delegate = PasswordEncoderFactories.createDelegatingPasswordEncoder();
		private final Map&lt;String, String&gt; cache = new HashMap&lt;&gt;();

		@Override
		public String encode(CharSequence rawPassword) {
			return delegate.encode(rawPassword);
		}

		@Override
		public boolean matches(CharSequence rawPassword, String encodedPassword) {
			String cachedPassword = cache.get(rawPassword);
			if (cachedPassword != null &amp;&amp; StringUtils.equals(cachedPassword, encodedPassword))
				return true;

			boolean match = delegate.matches(rawPassword, encodedPassword);
			if (match) cache.put(rawPassword.toString(), encodedPassword);

			return match;
		}
}

@Configuration
static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
	@Autowired
	private UserDetailsService userDetailsService;

	@Override
	public void configure(AuthenticationManagerBuilder builder) throws Exception {
		DaoAuthenticationProvider p = new DaoAuthenticationProvider();
		p.setPasswordEncoder(new CachingDelegatingPasswordEncoder());
		p.setUserDetailsService(userDetailsService);
		p.afterPropertiesSet();
		builder.authenticationProvider(p);
	}
}

huangapple
  • 本文由 发表于 2020年10月14日 20:16:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/64353075.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定