Skip to content

Seguridad

Juan Manuel Sanchez Fin edited this page Jun 2, 2024 · 5 revisions

Web Site

Se aplicó el uso de Guards en Angular, protegiendo las rutas a nivel de la UI.

Los Guards en Angular son interfaces que se encargan de dar o no dar acceso a rutas dependiendo de la autenticación del usuario. Actualmente, en nuestro sitio web, si no somos autenticados a través de los servicios correspondientes, la aplicación no nos dará acceso a la vista de "Mi cuenta", implementada en el path "/user", generando un redireccionamiento al formulario de login.

Estos Guards se implementan mediante servicios que pueden activar o desactivar el acceso a ciertas rutas.

En nuestro proyecto, se utilizaron Guards para proteger las rutas críticas de la siguiente manera:

  1. Implementación de Guards:

    • Se creó un servicio de Guard que implementa la interfaz CanActivate. Esta interfaz define el método canActivate, el cual devuelve un valor booleano o un Observable/Promise que resuelve a un valor booleano.
    • En el método canActivate, se verificó si el usuario está autenticado mediante un servicio de autenticación.
    import { Injectable } from '@angular/core';
    import { CanActivate, Router } from '@angular/router';
    import { AuthService } from './auth.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AuthGuard implements CanActivate {
    
      constructor(private authService: AuthService, private router: Router) {}
    
      canActivate(): boolean {
        if (this.authService.isAuthenticated()) {
          return true;
        } else {
          this.router.navigate(['/login']);
          return false;
        }
      }
    }
  2. Protección de Rutas:

    • Se configuraron las rutas en el módulo de rutas (AppRoutingModule) para usar el Guard. Las rutas que requieren autenticación fueron protegidas asignando el Guard a su propiedad canActivate.
    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    import { AuthGuard } from './auth.guard';
    import { UserComponent } from './user/user.component';
    import { LoginComponent } from './login/login.component';
    
    const routes: Routes = [
      { path: 'user', component: UserComponent, canActivate: [AuthGuard] },
      { path: 'login', component: LoginComponent },
      { path: '', redirectTo: '/login', pathMatch: 'full' }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
  3. Proceso de Autenticación:

    • El AuthService es responsable de manejar la lógica de autenticación. Este servicio verifica si el usuario está autenticado, generalmente comprobando un token almacenado en el localStorage o sessionStorage.
    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AuthService {
    
      constructor() {}
    
      isAuthenticated(): boolean {
        // Lógica para verificar si el usuario está autenticado
        return !!localStorage.getItem('token');
      }
    
      login(username: string, password: string): void {
        // Lógica de autenticación y almacenamiento del token
        localStorage.setItem('token', 'your-token');
      }
    
      logout(): void {
        localStorage.removeItem('token');
      }
    }

Con esta configuración, nos aseguramos de que solo los usuarios autenticados puedan acceder a las vistas protegidas, como "Mi cuenta", redirigiendo a los usuarios no autenticados al formulario de login. Esto proporciona una capa de seguridad en la interfaz de usuario de nuestra aplicación.

API Endpoints

Se implementó la autenticación básica (Basic Authentication) en Django para proteger los endpoints de la API.

La autenticación básica en Django se utiliza para restringir el acceso a los endpoints de la API, asegurando que solo los usuarios autenticados puedan interactuar con ellos. Este mecanismo requiere que los clientes envíen un encabezado Authorization con sus credenciales (nombre de usuario y contraseña) codificadas en base64 en cada solicitud.

En nuestro proyecto, se configuró la autenticación básica de la siguiente manera:

  1. Configuración del Middleware: En el archivo settings.py, se añadió rest_framework.authentication.BasicAuthentication en la configuración de DEFAULT_AUTHENTICATION_CLASSES del framework Django Rest Framework (DRF):

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.BasicAuthentication',
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
    }
  2. Protección de los Endpoints: Con esta configuración, todos los endpoints de la API requieren autenticación. Si un usuario no está autenticado, recibirá una respuesta con el código de estado HTTP 401 (Unauthorized).

  3. Proceso de Autenticación:

    • Cuando el cliente intenta acceder a un endpoint protegido, debe incluir el encabezado Authorization en la solicitud HTTP. El formato del encabezado es Authorization: Basic <credentials>, donde <credentials> es la cadena resultante de concatenar el nombre de usuario y la contraseña con dos puntos (username:password), y luego codificar esta cadena en base64.
    • Django decodifica las credenciales y verifica que el usuario existe y que la contraseña es correcta.
    • Si las credenciales son válidas, el usuario obtiene acceso al endpoint. De lo contrario, se le deniega el acceso.

Ejemplo de una solicitud con autenticación básica usando curl:

curl -u username:password http://yourdomain.com/api/your-endpoint/

Con esta configuración, garantizamos que solo los usuarios autenticados puedan interactuar con los datos sensibles a través de nuestra API, proporcionando una capa adicional de seguridad en nuestra aplicación.

App mobile

Se implementó la librería BCrypt en Java para hashing de passwords.

Actualmente la aplicación guarda las contraseñas de cada usuario aplicando un algoritmo de cifrado Blowfish que genera un hash. De esta manera, las contraseñas no son guardadas en texto plano y por más que un administrador con permisos tenga acceso a estos datos, no podrá conocer dichas claves originales.

La implementación se realizó de la siguiente manera:

  1. Dependencia de BCrypt:

    • Se añadió la dependencia de BCrypt en el archivo de configuración de dependencias (por ejemplo, pom.xml para proyectos Maven).
    <dependency>
        <groupId>org.mindrot</groupId>
        <artifactId>jbcrypt</artifactId>
        <version>0.4</version>
    </dependency>
    
  2. Hashing de Contraseñas:

    • En el servicio de gestión de usuarios, se utilizó BCrypt para hashear las contraseñas antes de guardarlas en la base de datos.
    import org.mindrot.jbcrypt.BCrypt;
    
    public class UserService {
    
        public String hashPassword(String plainPassword) {
            return BCrypt.hashpw(plainPassword, BCrypt.gensalt());
        }
    
        public boolean checkPassword(String plainPassword, String hashedPassword) {
            return BCrypt.checkpw(plainPassword, hashedPassword);
        }
    }

Este código muestra cómo se utiliza la librería BCrypt para hashear las contraseñas antes de almacenarlas en la base de datos, y también cómo verificar si una contraseña ingresada por el usuario coincide con el hash almacenado.

  1. Almacenamiento Seguro:

    • Cuando un usuario registra una nueva contraseña, esta es hasheada utilizando BCrypt y solo el hash resultante es almacenado en la base de datos.
    public void registerUser(String username, String plainPassword) {
        String hashedPassword = hashPassword(plainPassword);
        // Lógica para almacenar el usuario con la contraseña hasheada
    }

Este fragmento de código muestra cómo se utiliza BCrypt para hashear la contraseña antes de almacenarla en la base de datos. Solo se guarda el hash resultante, lo que garantiza que las contraseñas de los usuarios estén protegidas adecuadamente.

  1. Verificación de Contraseñas:

    • Durante el proceso de autenticación, se compara la contraseña ingresada por el usuario con el hash almacenado en la base de datos utilizando el método checkPassword.
    public boolean authenticateUser(String username, String plainPassword) {
        // Lógica para obtener el hash almacenado de la base de datos
        String storedHash = getStoredHashForUser(username);
        return checkPassword(plainPassword, storedHash);
    }

Este fragmento de código muestra cómo se verifica la contraseña ingresada por el usuario durante el proceso de autenticación. Se obtiene el hash almacenado en la base de datos para el usuario correspondiente y se compara con el hash de la contraseña ingresada utilizando el método checkPassword de BCrypt. Si coinciden, la autenticación es exitosa.

Con esta implementación, garantizamos que las contraseñas de los usuarios estén protegidas mediante hashing, dificultando que sean descubiertas en caso de un acceso no autorizado a la base de datos. Esto añade una capa importante de seguridad a nuestra aplicación.

Clone this wiki locally