*Questo argomento è stato trattato in secureProgramming *


Introduzione alla programmazione sicura

Nel contesto di sviluppo di un software è fondamentale ricordare che la sicurezza non può essere aggiunta come una fase “conclusiva” del processo di sviluppo software; basti pensare che, una singola falla può compromettere un intero sistema. Per questo, molte compagnie adottano processi che includono pratiche di sicurezza già dall’inizio del ciclo di sviluppo, come il processo SDL di Microsoft1.
Affinché sia garantita la sicurezza, non è sufficiente l’attività di testing: questa attività punta a garantire la correttezza di un programma dal punto di vista logico (dato un input che soddisfi i requisiti, l’output deve essere conforme con ciò che è richiesto dalle specifiche del programma stesso). È anche vero che, con l’attività di testing, è possibile controllare anche il corretto comportamento del programma in caso di input accidentalmente non conformi alle specifiche, ma non si considera il fatto che, in caso di attacco, il software riceve degli input che sono intenzionalmente e malevolmente costruiti col fine di indurre un comportamente non previsto del programma.

Garantire la sicurezza mediante l’analisi del codice

Di contro, delle attività che invece possono essere svolte per migliorare la sicurezza di un programma possono essere le attività di revisione, a partire con la code review con cui è possibile identificare falle che possono condurre a problemi di sicurezza. La pratica di revisione deve essere svolta da una persona diversa rispetto a quella che ha scritto il codice da rivedere e, tipicamente, possiede esperienza riguardo pratiche di programmazione non sicure.

Static Analysis Security Testing (SAST)

A coadiuvare l’analisi di revisione può esserci uno strumento software che analizza il codice sorgente prima della compilazione, rilevando gli errori più comuni.
Si tratta di uno strumento automatico e, in quanto tale, non può rilevare tutte le falle di un programma. Deve essere trattato come un’aggiunta e non come un rimpiazzo dell’attività di code review.

Dynamic Analysis Security Testing (DAST)

Un software DAST si affianca all’attività di SAST aggiungendo la possibilità di analizzare il comportamento di un programma quando è in esecuzione. Si tratta di uno strumento che esegue il programma da testare in un ambiente controllato e compie alcuni attacchi predefiniti, oppure monitora il comportamento del programma per determinare problemi di sicurezza.

Glossario

  • weakness (debolezza): un tipo di errore nella produzione del software (o hardware) che rende possibile una minaccia. Può avvenire in fase di implementazione, progettazione o altre fasi e rappresenta un “anti-pattern”, cioè una pratica scorretta che deve essere evitata;
    • collegato al concetto di weakness c’è il concetto di CWE (Common Weakness Enumeration), un repository di weakness conosciute per facilitare la comunicazione e diffondere consapevolezza contro le pratiche scorrette, da evitare. Ogni weakness ha un un identificativo univoco e contiene liste per apprendere i problemi più importanti.
  • vulnerability (vulnerabilità): una particolare occorrenza di vulnerabilità all’interno di un prodotto, che lo rende soggetto a potenziali attacchi. La differenza con una weakness è che se questa è di interesse solo per uno sviluppatore, una vulnerabilità riguarda anche l’utente e, nonostante non sia necessariamente un bug;
    • analogamente a quanto avviene per le weakness, anche alle vulnerabilità viene associato un “catalogo”, cioè le CVE (Common Vulnerability Enumeration); per le vulnerabilità, esiste anche un secondo indice, l’NVD (National Vulnerability Database), curato dal NIST.
  • severity (gravità): è una misura - qualitativa o quantitativa - di un potenziale impatto di una vulnerabilità. Tiene in conto due fattori, che sono la probabilità che un attaccante sfrutti la vulnerabilità e le conseguenze di un attacco condotto con successo;
    • la severity di una vulnerabilità viene calcolata algoritmicamente e deterministicamente con una scala, detta CVSS (Common Vulnerability Scoring System), in cui si assegna uno score da 0 a 10 per qualificare la gravità. Questo metodo tiene conto di alcuni parametri, che sono:
      • attack vector (considera la necessità di una presenza in locale dell’attaccante);
      • complessità dell’attacco;
      • livello di privilegio per condurre l’attacco;
      • necessità di azione da parte della vittima;
      • compromissione di altri componenti, oltre quello attaccato (scope);
      • in caso di successo, parziale o totale perdita di CIA2.
  • exploit: un componente software o dato che sfrutta una vulnerabilità per compromettere un sistema (ottenendo accesso a funzionalità per cui non ha autorizzazione, alterare il comportamento del sistema, ottenere informazioni riservate, causare indisponibilità - Denial of Service - a utenti legittimi);
  • zero-day exploit: exploit per una vulnerabilità non pubblicamente conosciuta (l’autore dell’exploit è colui che ha scoperto la vulnerabilità oppure la vulnerabilità era nota ma non pubblicata e l’informazione è leakata). Si tratta di exploit molto pericolosi siccome non vi è stato modo di sviluppare contromisure;
  • trust boundary: un punto oltre il quale un programma (o sistema) le assunzioni sul livello di fiducia nei dati cambiano. Ogni volta che i dati attraversano un trust boundary (passando dalla untrusted part alla trusted part) devono essere validati, controllando in modo esplicito che tutte le assunzioni siano soddisfatte. Quando una trust boundary non viene chiaramente identificata, si incorre in un problema di design e si deve essere a conoscenza del problema di sicurezza.

Regola zero della Secure Programming

La maggior parte delle vulnerabilità può essere ridotta al fatto che il sistema riponga un livello di fiducia non adeguato nelle informazioni che si ricevono dall’esterno, facendo delle assunzioni che possono essere intenzionali, ma anche - spesso - non intenzionali. La debolezza nasce poiché il sistema non controlla se le assunzioni sono vere per i dati che ha ricevuto, dunque la regola zero della secure programming è: mai fidarsi dei dati che provengono dall’esterno del sistema.
Una lista non esaustiva di cosa va considerato dato esterno al sistema include: dati inseriti dall’utente (anche comandi passati da CLI), dati letti da file, dati ricevuti da altri programmi in esecuzione o dalla rete, file (o database) di configurazione, file di libreria dinamici (DLL e shared objects).
Più nello specifico, l’uso di dati esterni diventa pericoloso ogni volta che possono essere modificati da un utente diverso da quello che esegue il programma (un server che processa richieste da utenti normali sulla rete, un client usato da un utente per accedere a risorse su un sistema remoto, un programma usato per aprire file scaricato da un server o ricevuto per email). Oltre a questo, va considerato anche che, in alcuni casi, la vittima è indotta ad auto-attaccarsi.

Footnotes

  1. Security is everyone’s job. Developers, service engineers, and program and product managers must understand security basics and know how to build security into software and services to make products more secure while still addressing business needs and delivering user value. (Estratto)

  2. Confidentiality, Integrity, Availability.