Nei titoli e nei testi troverete qualche rimando cinematografico (ebbene si, sono un cinefilo). Se non vi interessano fate finta di non vederli, già che non sono fondamentali per la comprensione dei post...

Di questo blog ho mandato avanti, fino a Settembre 2018, anche una versione in Spagnolo. Potete trovarla su El arte de la programación en C. Buona lettura.

mercoledì 15 agosto 2012

Sei sicuro delle tue stringhe ?
come trattare le stringhe nel C

Viviamo in un mondo reale. In un mondo ideale non ci sarebbe bisogno di testare il ritorno di una malloc(), prima di usare la memoria gentilmente concessaci. Anzi, non ci sarebbe neanche bisogno della malloc(). In un mondo ideale non ci sarebbe bisogno di testare la sicurezza di una applicazione, perché nessuno cercherebbe mai di attaccare, con metodi svariati, il nostro software per cercare falle strane.

Ma, viviamo in un mondo reale. E allora, visto che il più diffuso attacco craker si basa sulla nota tecnica del buffer overflow, dovremmo tenere sotto controllo tutte le stringhe di input di una applicazione, sia che vengano da un altro programma, sia che vengano direttamente da attività interattive. Ok, sembra molto complicato e dispendioso, ma se prendiamo l'abitudine di usare alcune semplici funzioni (scritte ad hoc) della nostra personale libc, il risultato finale non sarà, poi cosi antiestetico e complicato da realizzare.

Un piccolo esempio: tutte le stringhe provenienti da mondo esterno le filtriamo con una funzione che potremmo chiamare strSecure():

/* strSecure()
 * trattamento di sicurezza (buffer overflow) della string <src>: ritorna una stringa di 

 * max <len> char con terminatore
 */
char *strSecure(
    char         *dest,
    const char *src,
    size_t        len)
{
    // trattamento di sicurezza (buffer overflow) della string <src>
    if (! memccpy(dest, src, '\0', len))
        dest[len - 1] = '\0';
       
    // ritorna una stringa di max <len> char con terminatore
    return(dest);
}


Ossia: copiamo la stringa e, se memccpy() non trova il terminatore, lo forziamo noi. In pratica si potrebbe usare, più o meno, così (sarà un esempio un po' sintetico, lo ammetto...):

main()
{
    ...
    // legge input string
    char *inputstr = ...
    ...

    // usa input string
    char my_inputstr[80];
    sprintf(buf, "input string is: %s", strSecure(my_inputstr, inputstr, sizeof(my_inputstr));
    ...
}


Ah, dimenticavo: se volete vivere bene e sicuri, vestitevi pesanti in inverno, leggeri in estate, e, soprattutto, non usate mai la gets().

Ciao e al prossimo post.

1 commento: