Quando si memorizzano dati sensibili dei nostri utenti, per esempio numeri di carte di credito, dobbiamo assolutamente prendere tutte le precauzioni necessarie per evitare leak di queste informazioni, anche in caso di data breach: in parole povere, anche se un utente malintenzionato riuscisse ad avere accesso al nostro database, questi dati non devono essere consumabili e comprensibili. Al di là di una buona etica professionale, inoltre, con l'avvento di GDPR questo diventa un vero e proprio requisito legale.
Fortunatemente ASP.NET Core espone una serie di API per la protezione dei dati che rendono operazioni quali encryption e hashing estremamente semplici: stiamo parlando delle Data Protection API.
Immaginiamo, per esempio, di avere una form di input dei dati cliente, e che tra questi sia contenuto un numero di carta di credito. Ovviamente non vogliamo memorizzarlo in chiaro nel database, e pertanto vogliamo criptarlo prima del salvataggio. Per farlo, dobbiamo prima di tutto creare un IDataProtector nel nostro controller:
private IDataProtector _protector; public CustomerController(IDataProtectionProvider provider) { _protector = provider.CreateProtector("Customer.Data"); }
Questo oggetto non può essere istanziato direttamente, ma richiede un IDataProtectionProvider che, comunque, è già per default configurato come servizio nel motore di DependencyInjection di ASP.NET Core - questo perchè è utilizzato per diversi altri scopi, tra cui AntiForgeryToken e cookie di autenticazione. Da questo nostro provider, possiamo costruire un protector tramite il metodo CreateProtector, a cui dobbiamo passare quella che nella documentazione è chiamata una Purpose String. Si tratta fondamentalmente di una stringa che viene utilizzata (in concomitanza con altri dati) per generare la chiave di cifratura.
Un protector con una differente Purpose String non sarà in grado di decodificare quanto generato da quello del codice in alto: questo accorgimento aggiunge un ulteriore layer di protezione alla nostra applicazione, perchè se differenti moduli usano diverse chiavi, il rischio di leak di dati nel caso di un bug di sicurezza in uno di questi sarà circoscritto ai suoi dati.
Una volta ottenuto questo protector, possiamo usarlo per crittografare il numero di carta di credito, prima di salvarlo su database, semplicemente invocando il metodo Protect:
public ActionResult Create(Customer customer) { try { customer.CreditCard = _protector.Protect(customer.CreditCard); _customerRepository.Save(customer); return RedirectToAction(nameof(Index)); } catch { return View(); } }
Quando poi dobbiamo visualizzare il customer, se vogliamo decriptare il dato possiamo utilizzare la stessa classe Protector e il metodo Unprotect:
public ActionResult Details(int id) { Customer customer = _customerRepository.GetCustomerById(); customer.CreditCard = _protector.Unprotect(customer.CreditCard); return View(); }
Le chiavi di crittografia utilizzate da Data Protection API vengono normalmente generate sulla singola macchina. In condizioni di server farm o quando vanno condivise tra più applicazioni, possiamo condividere le chiavi con le stesse tecniche che abbiamo illustrato nei precedenti script (https://www.aspitalia.com/script/1282/Usare-AntiForgeryToken-Scenario-Web-Farm-ASP.NET-Core-MVC.aspx e https://www.aspitalia.com/script/1283/Sfruttare-Redis-Storage-AntiForgeryToken-ASP.NET-Core.aspx).
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Usare le navigation property in QuickGrid di Blazor
Creare un'applicazione React e configurare Tailwind CSS
Generare HTML a runtime a partire da un componente Razor in ASP.NET Core
Usare un KeyedService di default in ASP.NET Core 8
Effettuare il binding di date in Blazor
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Miglioramenti nelle performance di Angular 16
Popolare una classe a partire dal testo, con Semantic Kernel e ASP.NET Core Web API
Migliorare l'organizzazione delle risorse con Azure Policy
Referenziare un @layer più alto in CSS