web-dev-qa-db-fra.com

Comment utiliser le nouveau PasswordEncoder de Spring Security

À partir de Spring Security 3.1.4.LELEASE, l’ancien org.springframework.security.authentication.encoding.PasswordEncoderest déconseillé en faveur de org.springframework.security.crypto.password.PasswordEncoder. Comme mon application n'a pas encore été publiée, j'ai décidé de passer à la nouvelle API, non obsolète.

Jusqu'à présent, j'avais un ReflectionSaltSource qui utilisait automatiquement la date d'enregistrement de l'utilisateur sous la forme sel par utilisateur pour mot de passe.

String encodedPassword = passwordEncoder.encodePassword(rawPassword, saltSource.getSalt(user));

Pendant le processus de connexion, Spring a également utilisé mes beans pour vérifier si l'utilisateur peut ou non se connecter. Je ne peux pas l'obtenir dans le nouvel encodeur de mot de passe, car l'implémentation par défaut de SHA-1 - StandardPasswordEncoder a seule possibilité d'ajouter un sel secret global lors de la création de l'encodeur.

Existe-t-il une méthode raisonnable pour le configurer avec l'API non obsolète?

55
fracz

Si vous n'avez enregistré aucun utilisateur avec votre format existant, vous feriez mieux d'utiliser plutôt l'encodeur encodeur de mot de passe BCrypt .

C'est beaucoup moins compliqué, car vous n'avez pas à vous soucier du sel - les détails sont complètement encapsulés dans l'encodeur. L'utilisation de BCrypt est plus puissante que celle d'un algorithme de hachage simple. Il s'agit également d'un standard compatible avec les applications utilisant d'autres langages.

Il n'y a vraiment aucune raison de choisir l'une des autres options pour une nouvelle application.

56
Shaun the Sheep

Voici l'implémentation de BCrypt qui fonctionne pour moi.

au printemps-security.xml

<authentication-manager >
    <authentication-provider ref="authProvider"></authentication-provider>  
    </authentication-manager>
<beans:bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  <beans:property name="userDetailsService" ref="userDetailsServiceImpl" />
  <beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
<!-- For hashing and salting user passwords -->
    <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

Dans Java class

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(yourpassword);

Pour un exemple plus détaillé de la sécurité de printemps Cliquez ici

J'espère que cela aidera.

Merci

17
Ravi Kant

J'ai eu un problème similaire. Je devais conserver les mots de passe cryptés hérités ( Base64/SHA-1/Random Salt Encoded ) car les utilisateurs ne voudraient pas changer leurs mots de passe ou se réinscrire. . Cependant, je voulais aussi utiliser le codeur BCrypt .

Ma solution consistait à écrire un décodeur sur mesure qui vérifiait quelle méthode de cryptage avait été utilisée avant de faire correspondre les méthodes ( BCrypted commençant par $).

Pour contourner le problème du sel, je passe au décodeur une chaîne concaténée de sel + mot de passe crypté via mon objet utilisateur modifié.

Décodeur

@Component
public class LegacyEncoder implements PasswordEncoder {

    private static final String BCRYP_TYPE = "$";
    private static final PasswordEncoder BCRYPT = new BCryptPasswordEncoder();

    @Override
    public String encode(CharSequence rawPassword) {

    return BCRYPT.encode(rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {

    if (encodedPassword.startsWith(BCRYP_TYPE)) {
        return BCRYPT.matches(rawPassword, encodedPassword);
    }

    return sha1SaltMatch(rawPassword, encodedPassword);
    }

    @SneakyThrows
    private boolean sha1SaltMatch(CharSequence rawPassword, String encodedPassword) {

    String[] saltHash = encodedPassword.split(User.SPLIT_CHAR);

    // Legacy code from old system   
    byte[] b64salt = Base64.getDecoder().decode(saltHash[0].getBytes());
    byte[] validHash = Base64.getDecoder().decode(saltHash[1]);
    byte[] checkHash = Utility.getHash(5, rawPassword.toString(), b64salt);

    return Arrays.equals(checkHash, validHash);
    }

}

objet utilisateur

public class User implements UserDetails {

    public static final String SPLIT_CHAR = ":";

    @Id
    @Column(name = "user_id", nullable = false)
    private Integer userId;

    @Column(nullable = false, length = 60)
    private String password;

    @Column(nullable = true, length = 32)
    private String salt;

.
.

    @PostLoad
    private void init() {

    username = emailAddress; //To comply with UserDetails
    password = salt == null ? password : salt + SPLIT_CHAR + password;
    }        

Vous pouvez également ajouter un crochet pour réencoder le mot de passe au nouveau format BCrypt et le remplacer. Ainsi, éliminer progressivement l'ancienne méthode.

5
Simon Jenkins

Après avoir consulté Internet pour en savoir plus à ce sujet et sur les options disponibles au printemps, je répondrai en second lieu à Luke: utilisez BCrypt (il est mentionné dans le code source au printemps).

La meilleure ressource que j'ai trouvée pour expliquer pourquoi hachage/sel et pourquoi utiliser BCrypt est un bon choix est la suivante: Salage du mot de passe haché - faire correctement .

3
user2546977