ANG_FRONT

Práctica 12. Protegiendo tu aplicación de amenazas comunes: Seguridad en Angular

Objetivo de la práctica

Duración aproximada

Instrucciones

  1. Principales amenazas de seguridad.

Cross-Site Scripting (XSS):

Cross-Site Request Forgery (CSRF):

Inyección de Código:

  1. Protección contra XSS.

<!-- Seguro: Angular escapa los valores por defecto -->
<div></div>
  1. Sanitización. - Angular proporciona el servicio DomSanitizer, que permite a los desarrolladores sanitizar el contenido que puede incluir HTML, URL, estilos, entre otros.

import { Component } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'app-example',
  template: `<div [innerHTML]="sanitizedContent"></div>`
})
export class ExampleComponent {
  sanitizedContent: any;

  constructor(private sanitizer: DomSanitizer) {
    const unsafeHtml = '<script>alert("XSS")</script>';
    this.sanitizedContent = this.sanitizer.bypassSecurityTrustHtml(unsafeHtml);
  }
}
  1. Protección contra CSRF.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  constructor(private http: HttpClient) {}

  realizarPeticion() {
    return this.http.get('/api/endpoint'); // El token CSRF se enviará automáticamente
  }
}
  1. Autenticación y autorización.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const isAuthenticated = // lógica de autenticación aquí

    if (!isAuthenticated) {
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}
  1. Mejoras en la seguridad.

    1. Content Security Policy (CSP).
      • Implementar una política de seguridad de contenido (CSP) ayuda a mitigar XSS y otros ataques inyectados al controlar qué recursos pueden ser cargados y ejecutados.
    2. Actualizaciones y parches.
      • Es crucial mantener Angular y sus dependencias actualizadas para protegerse contra vulnerabilidades conocidas. Regularmente se lanzan actualizaciones que corrigen problemas de seguridad.

Accesibilidad en Angular

  1. Principios de la accesibilidad.
  1. Prácticas de accesibilidad en Angular.

    1. Uso de ARIA (Accessible Rich Internet Applications).
    • ARIA proporciona un conjunto de atributos que se pueden agregar a HTML para mejorar la accesibilidad. Angular permite usar estos atributos en sus plantillas.

Ejemplo:


<button aria-label="Cerrar" (click)="cerrar()">
  <span aria-hidden="true"></span>
</button>

Ejemplo:


<a href="#" (keydown.enter)="accion()" tabindex="0">Acción</a>

Ejemplo:


<form [formGroup]="miFormulario">
  <input formControlName="nombre" aria-describedby="nombreAyuda">
  <div *ngIf="miFormulario.get('nombre').invalid && miFormulario.get('nombre').touched">
    <small id="nombreAyuda">El nombre es obligatorio.</small>
  </div>
</form>

Ejemplo:


<label for="email">Correo Electrónico</label>
<input type="email" id="email" aria-required="true">

  1. Uso de librerías y componentes accesibles.
  1. Pruebas de accesibilidad.

Mejores prácticas sobre Property Binding en Angular

  1. ¿Qué es Property Binding?

Ejemplo:


<img [src]="imageUrl" [alt]="imageDescription">
  1. Mejores prácticas.

    1. Usar Property Binding en lugar de interpolación.
      • Cuando trabajes con propiedades que afectan a elementos DOM, es preferible usar property binding en lugar de interpolación, ya que el binding es más eficiente y puede prevenir problemas de rendimiento.

<img src="" alt="">

<img [src]="imageUrl" [alt]="imageDescription">
  1. Evitar cambios frecuentes en las propiedades.
- Minimiza el número de cambios en las propiedades enlazadas para mejorar el rendimiento. Los cambios frecuentes pueden llevar a un rendimiento deficiente debido a las múltiples actualizaciones del DOM.

updateImage() {
  this.imageUrl = 'new-image-url.jpg'; // Cambiar frecuentemente
}

updateImageBatch() {
  this.imageUrls = ['url1.jpg', 'url2.jpg', 'url3.jpg'];
}

-

  1. Utilizar el cambio de detección OnPush. - Si es posible, usar la estrategia de detección de cambios OnPush en los componentes para optimizar el rendimiento. Esto reduce el número de chequeos de cambios y mejora la eficiencia al enlazar propiedades.

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent {
  // Propiedades
}

  1. Mantener el código limpio y legible. - Es esencial mantener el código claro y legible. Utilizar nombres de propiedades significativos y documentar las propiedades que se enlazan para facilitar la comprensión.

Ejemplo:


// Mejor práctica: usa nombres claros
public imageUrl: string;
public imageDescription: string;

  1. Evitar el enlace de propiedades innecesarias. - No enlazar propiedades que no sean necesarias. Cada enlace agrega carga al ciclo de detección de cambios, por lo que es mejor limitar el binding a lo que realmente se necesita.

Ejemplo:


<!-- Enlace innecesario -->
<div [class.active]="isActive" [style.display]="isVisible ? 'block' : 'none'"></div>

Ejemplo:


<input #inputElement type="text" (input)="onInput(inputElement.value)">
  1. Ejemplos prácticos.

    1. Binding de clases y estilos.
      • El property binding también se puede usar para enlazar clases y estilos de manera dinámica.

<div [ngClass]="{'active': isActive}" [style.color]="textColor"></div>

Módulos de funciones de carga diferida en Angular

  1. ¿Qué es la carga diferida?
  1. Beneficios de la carga diferida.
  1. Implementación de carga diferida.

    1. Crear un módulo
      • Primero, necesitas crear un módulo que se cargará de forma diferida. Por ejemplo, supongamos que queremos crear un módulo para una sección de administración.

ng generate module admin --route admin --module app.module

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: '**', redirectTo: '/home' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

ng generate component admin/dashboard
ng generate component admin/users

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { UsersComponent } from './users/users.component';

const routes: Routes = [
  { path: '', component: DashboardComponent },
  { path: 'users', component: UsersComponent }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class AdminRoutingModule { }