Mejore la seguridad de las contraseñas :3

This commit is contained in:
Daniel Cortés
2019-06-12 12:33:38 -04:00
parent 50ee562fa4
commit 6a4ed86ad3
7 changed files with 73 additions and 60 deletions

View File

@@ -360,7 +360,8 @@ create table usuario
(
id int unsigned primary key auto_increment,
nombre varchar(255) not null,
password varchar(255) not null,
password binary(32) not null,
salt binary(16) not null,
trabajador_id int unsigned not null,
foreign key (trabajador_id) references trabajador (id) on delete cascade on update cascade,
inserted_at timestamp default current_timestamp
@@ -444,6 +445,3 @@ values (1, 2),
INSERT INTO trabajador
VALUES (1, '197638990', 'Daniel', 'Cortes', 'Pincheira', '2019-06-04', '2019-06-04 18:12:55');
INSERT INTO usuario
VALUES (1, 'admin', 'IF7nbMo9zxGOH++0op8eE+obeILVzsZCguAqPVydL/0=', 1, '2019-06-05 00:08:50');

View File

@@ -1,12 +1,11 @@
package xyz.danielcortes.controllers.mantenedores.trabajador.usuario;
import java.nio.charset.StandardCharsets;
import xyz.danielcortes.controllers.LaunchController;
import xyz.danielcortes.controllers.mantenedores.trabajador.TrabajadorViewController;
import xyz.danielcortes.framework.BaseController;
import xyz.danielcortes.framework.BasePanel;
import xyz.danielcortes.framework.Hash;
import xyz.danielcortes.framework.PanelName;
import xyz.danielcortes.framework.Passwords;
import xyz.danielcortes.framework.ValidationResult;
import xyz.danielcortes.models.Trabajador;
import xyz.danielcortes.models.Usuario;
@@ -68,7 +67,8 @@ public class UsuarioCreateController extends BaseController {
Usuario usuario = new Usuario();
usuario.setNombre(user);
usuario.setPassword(Hash.sha256(new String(pass).getBytes(StandardCharsets.UTF_8)));
usuario.setSalt(Passwords.getNextSalt());
usuario.setPassword(Passwords.hash(pass, usuario.getSalt()));
usuario.setTrabajador(trabajador);
this.repository.save(usuario);

View File

@@ -1,12 +1,11 @@
package xyz.danielcortes.controllers.mantenedores.trabajador.usuario;
import java.nio.charset.StandardCharsets;
import xyz.danielcortes.controllers.LaunchController;
import xyz.danielcortes.controllers.mantenedores.trabajador.TrabajadorViewController;
import xyz.danielcortes.framework.BaseController;
import xyz.danielcortes.framework.BasePanel;
import xyz.danielcortes.framework.Hash;
import xyz.danielcortes.framework.PanelName;
import xyz.danielcortes.framework.Passwords;
import xyz.danielcortes.framework.ValidationResult;
import xyz.danielcortes.models.Trabajador;
import xyz.danielcortes.repository.UsuarioRepository;
@@ -77,7 +76,8 @@ public class UsuarioUpdateController extends BaseController {
}
trabajador.getUsuario().setNombre(user);
trabajador.getUsuario().setPassword(Hash.sha256(new String(pass).getBytes(StandardCharsets.UTF_8)));
trabajador.getUsuario().setSalt(Passwords.getNextSalt());
trabajador.getUsuario().setPassword(Passwords.hash(pass, trabajador.getUsuario().getSalt()));
this.repository.update(trabajador.getUsuario());
this.volver();

View File

@@ -1,22 +0,0 @@
package xyz.danielcortes.framework;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Hash {
private static MessageDigest sha;
static {
try {
sha = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String sha256(byte[] toHash) {
return Base64.getEncoder().encodeToString(sha.digest(toHash));
}
}

View File

@@ -0,0 +1,46 @@
package xyz.danielcortes.framework;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class Passwords {
private static final Random RANDOM = new SecureRandom();
private static final int ITERATIONS = 10000;
private static final int KEY_LENGHT = 256;
private Passwords(){}
public static byte[] getNextSalt() {
byte[] salt = new byte[16];
RANDOM.nextBytes(salt);
return salt;
}
public static byte[] hash(char[] password, byte[] salt){
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGHT);
Arrays.fill(password, Character.MIN_VALUE);
try{
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return skf.generateSecret(spec).getEncoded();
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
} finally {
spec.clearPassword();
}
}
public static boolean isExpectedPassword(char[] password, byte[] salt, byte[] expectedHash){
byte[] pwdHash = hash(password, salt);
Arrays.fill(password, Character.MIN_VALUE);
if(pwdHash.length != expectedHash.length) return false;
for(int i = 0; i < pwdHash.length; i++){
if(pwdHash[i] != expectedHash[i]) return false;
}
return true;
}
}

View File

@@ -1,14 +1,13 @@
package xyz.danielcortes.login;
import java.awt.Dimension;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import xyz.danielcortes.framework.Hash;
import xyz.danielcortes.framework.LoggedEvent;
import xyz.danielcortes.framework.LoggedListener;
import xyz.danielcortes.framework.Passwords;
import xyz.danielcortes.models.Usuario;
import xyz.danielcortes.repository.UsuarioRepository;
@@ -46,8 +45,8 @@ public class LoginController {
}
Usuario user = optionalUser.get();
String pass = Hash.sha256(new String(this.view.getPassField().getPassword()).getBytes(StandardCharsets.UTF_8));
if (pass.equals(user.getPassword())) {
char[] pass = this.view.getPassField().getPassword();
if (Passwords.isExpectedPassword(pass, user.getSalt(), user.getPassword())) {
this.frame.dispose();
loggedListener.loginTry(new LoggedEvent(this, user));
} else {

View File

@@ -1,6 +1,5 @@
package xyz.danielcortes.models;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
@@ -21,8 +20,11 @@ public class Usuario {
@Column(name = "nombre")
private String nombre;
@Column(name = "password")
private String password;
@Column(name = "password", columnDefinition = "BINARY(32) NOT NULL")
private byte[] password;
@Column(name = "salt", columnDefinition = "BINARY(16) NOT NULL")
private byte[] salt;
@OneToOne
@JoinColumn(name = "trabajador_id", referencedColumnName = "id")
@@ -44,14 +46,22 @@ public class Usuario {
this.nombre = nombre;
}
public String getPassword() {
public byte[] getPassword() {
return password;
}
public void setPassword(String password) {
public void setPassword(byte[] password) {
this.password = password;
}
public byte[] getSalt() {
return salt;
}
public void setSalt(byte[] salt) {
this.salt = salt;
}
public Trabajador getTrabajador() {
return trabajador;
}
@@ -59,22 +69,4 @@ public class Usuario {
public void setTrabajador(Trabajador trabajador) {
this.trabajador = trabajador;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Usuario))
return false;
Usuario usuario = (Usuario) o;
return Objects.equals(id, usuario.id) &&
Objects.equals(nombre, usuario.nombre) &&
Objects.equals(password, usuario.password) &&
Objects.equals(trabajador, usuario.trabajador);
}
@Override
public int hashCode() {
return Objects.hash(id, nombre, password, trabajador);
}
}