Spring Security 5 使用 SHA-1 编码生成与 Spring Security 4 不同的编码字符串

问题描述 投票:0回答:1

我们的开发团队已获悉,由于早期版本的 Spring Security 中存在授权绕过漏洞,在我们从 Spring Security 4.x 升级到 Spring Security 5 之前,我们的应用程序将不再部署。我正在努力处理我们的身份验证代码,它使用 Spring Security 4 SHAPasswordEncoder,它已从 Spring Security 5 中删除。我有一个简单的应用程序,它将文本字符串编码为 SHA-1 编码字符串,并且我“成功”将该应用程序的代码迁移到 Spring Security 5,但在编码时我得到了一个非常不同的字符串。

旧应用程序:

import org.springframework.security.authentication.encoding.ShaPasswordEncoder;

/**
 * Small java utility to take a single string and generate an SHA encoded string from
 * the original string, for use as an EIS local password
 * 
 * Usage:
 *      PwGen <string_to_encode>
 *
 */
public class PwGen {
    
    public static void main(String[] args) {
        PwGen pwGen = new PwGen();
        pwGen.generatePassword(args);
    }
    
    private void generatePassword(final String[] args) {

        if (args.length != 1) {
            usage();
            return;
        }

        System.out.println("Generating password");
        
        ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder();
        
        String encodedPassword = passwordEncoder.encodePassword((String)args[0], "");
        System.out.println(encodedPassword);
    }
    
    private void usage() {
        System.out.println("Usage: pwGen <string_to_encode>");
        System.out.println("Application will return an encoded string for use as a password");
    }
}

新应用:

import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Small java utility to take a single string and generate an SHA encoded string from
 * the original string, for use as an EIS local password
 * 
 * Usage:
 *      PwGen <string_to_encode>
 *
 */
public class PwGen {
    
    public static void main(String[] args) {
        PwGen pwGen = new PwGen();
        pwGen.generatePassword(args);
    }
    
    private void generatePassword(final String[] args) {

        if (args.length != 1) {
            usage();
            return;
        }

        System.out.println("Generating password");
        
        PasswordEncoder passwordEncoder = new MessageDigestPasswordEncoder("SHA-1");
        String encodedPassword = passwordEncoder.encode(args[0]);
        
        System.out.println(encodedPassword);
    }
    
    private void usage() {
        System.out.println("Usage: pwGen <string_to_encode>");
        System.out.println("Application will return an encoded string for use as a password");
    }
}

使用旧应用程序,对字符串“password”进行编码生成以下编码字符串:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

这是一个很容易预测的解决方案,因为我们的数据库包含完全相同的字符串。

每次运行新应用程序都会生成不同的字符串,因此我无法再为用户生成特定的密码。我非常清楚这整个过程并不安全,但应用程序已经过时并且在不久的将来会完全重写,因此管理层对资助中间重写并不感到兴奋。我如何保证 MessageDigestPasswordEncoder 带回与实际编码密码相同的字符串?

java spring-security sha1
1个回答
0
投票

免责声明,下面写的代码是:

超级不安全代码

不应在任何应用程序中使用。

使用

SHA-1
存储密码不安全。 2005 年发现了已知的攻击,2011 年 NIST 正式弃用了 SHA-1,谷歌在 2017 年提出了第一次碰撞。请不要使用 SHA-1!shattered.ioGoogle 发现了有史以来第一次 SHA-1 碰撞

现在宣布免责声明时。

如果您查看实现,您会发现代码将生成一个随机盐,并将其添加到字符串中。这很可能是您每次都获得随机字符串的原因。

@Override
public String encode(CharSequence rawPassword) {
    String salt = PREFIX + this.saltGenerator.generateKey() + SUFFIX;
    return digest(salt, rawPassword);
}

有两种方法可以解决它。

您可以像文档建议的那样提供一个空字符串作为盐

If the salt is an empty String, then only use "{}" like this:

 "{}" + digest(password + "{}")

这将确定您正在传递一个空字符串作为盐。所以你的代码会是。

PasswordEncoder passwordEncoder = new MessageDigestPasswordEncoder("SHA-1");
String encodedPassword = passwordEncoder.encode(args[0] + "{}");
        
System.out.println(encodedPassword);

或者我们可以覆盖

MessageDigestPasswordEncoder#encode
函数并绕过盐生成。

public class SuperInsecureMessageDigestPasswordEncoder extends MessageDigestPasswordEncoder {

    @Override
    public String encode(CharSequence rawPassword) {
        return digest("", rawPassword);
    }
}

这将消除盐的产生。

© www.soinside.com 2019 - 2024. All rights reserved.