2011-10-11 13 views
6

Ho una funzione che restituisce una stringa:C: ritorno stringa dalla funzione

const *char getMyPassword() 
{ 
    return "mysecretpassword"; 
} 

Beh, ha funzionato perfettamente, ma ho scoperto che se vorrei correre "stringhe" su sistemi Unix si presenta in lista .. non va bene.

Qual è il modo più semplice per sostituirlo? La funzione si trova in una libreria e voglio mantenerla flessibile. Ora ho iniziato a fare il malloppo all'interno della funzione e la stringa nelle stringhe è scomparsa. Tuttavia, quando lo libererei di nuovo?

char * getMyPassword() 
{ 
unsigned char arr[] = { 'p', 'a', 's', 's', 'w', 'o', 'r' , 'd', '\0' }; 
char *return_arr = malloc(sizeof(arr)); 
strcpy(return_arr, arr); 
return return_arr; 

} 

Se ero a malloc prima e passare un puntatore, allora come potevo sapere la taglia prima di come la dimensione delle password è nota solo all'interno della funzione?

Come piano B potrei passare un array enorme, ma non sembra molto elegante. Come dovrei avvicinarmi a questo?

MODIFICA: ho aggiunto lo strcpy (return_arr, arr). In realtà l'avevo nel codice originale, ma l'ho dimenticato qui.

+0

Inseritelo all'indietro, quindi usate '' 'strrev()' ''. Oppure, rot-13 it due volte. –

+6

Se si stanno utilizzando password, si consiglia vivamente di utilizzare password con hash anziché la stringa letterale. Ciò ridurrà sicuramente la quantità di informazioni che possono essere ottenute da qualcuno eseguendo "stringhe" sul programma. È possibile personalizzare una funzione di hash in modo che le persone non possano (o perlomeno sia molto più difficile) determinare quale sia effettivamente il valore. – dbeer

+0

Per quale scopo deve essere utilizzata la password?Un accesso da qualche parte o simile? –

risposta

2

Problemi di sicurezza a parte, quello che stai cercando di fare è allocare dinamicamente il buffer.

È possibile effettuare 2 avvicini.

  1. sempre malloc all'interno vostra funzione e il documento è che restituisca malloced risultato.
  2. Seguire la strada di alcune funzioni di libreria standard, richiedere che l'utente passi un puntatore a un buffer valido e alle sue dimensioni e restituisca la dimensione effettivamente copiata. Alcune di queste funzioni consentono il passaggio check, quando si passa un buffer null, non tentano di allocarlo, ma restituiscono invece la dimensione necessaria per contenere la struttura.

Mi sembra che tu abbia già implementato l'approccio n. 1.

Per approccio # 2 uso questa firma:

int getMyPassword(char* buffer, size_t buff_size, size_t* p_num_copied) 
{ 
    unsigned char arr[] = { 'p', 'a', 's', 's', 'w', 'o', 'r' , 'd', '\0' }; 

    if (buffer == 0) 
    { 
    *p_num_copied = sizeof(arr); 
    return SUCCESS; 
    } 

    if (buff_size < sizeof(arr)) 
    { 
    *p_num_copied = sizeof(arr); 
    return BUFFER_TOO_SMALL; 
    } 

    memcpy(buffer, arr, sizeof(arr)); 

    *p_num_copied = sizeof(arr); 

    return SUCCESS; 
} 

Vantaggio del metodo # 2 è che il chiamante, in molti casi, può allocare il buffer sullo stack, soprattutto se si annuncia la dimensione massima richiesta del buffer. Un altro vantaggio è che la gestione della memoria è ora completamente gestita dal client. Nella libreria di scopi generali non si desidera creare un client a seconda di uno specifico schema di allocazione della memoria della libreria.

IN Rispondi al commento

Se si desidera utilizzare sempre il valore assegnato nel codice client, allora questo è il modo che vorrei fare questo:

char* clientGetPasswordFromLibrary() 
{ 
    // in our day and age it's fine to allocate this much on stack 
    char buffer[256]; 
    size_t num_copied; 

    int status = getMyPassword(buffer, sizeof(buffer), &num_copied); 

    char* ret_val = NULL; 

    if (status == BUFFER_TOO_SMALL) 
    { 
    ret_val = malloc(num_copied); 

    if (ret_val == NULL) 
    { 
     return NULL; 
    } 

    getMyPassword(ret_val, num_copied, &num_copied); 
    } 
    else 
    { 
    ret_val = malloc(num_copied); 

    if (ret_val == NULL) 
    { 
     return NULL; 
    } 

    memcpy(ret_val, buffer, num_copied); 
    } 

    return ret_val; 
} 
+0

Una volta ho letto che è una cattiva abitudine di malloc qualcosa e poi restituirlo ed è per questo che ho sempre cercato di astenermi dal farlo. Quindi grazie per il tuo secondo approccio Alex. Cosa ne pensi di passare il buffer e poi ridistribuirlo? –

+0

@Frank. Se nel tuo codice cliente vuoi sempre fare affidamento su 'malloc', va bene. Modificherò la risposta per mostrarti un esempio di come lo farei. –

+0

Molto utile. Grazie! –

2

Penso che il problema qui sia che si sta tentando di restituire un puntatore a una variabile definita localmente quando si tenta di restituire una stringa del genere. Mi aspetto che la prima funzione funzioni, poiché il puntatore restituisce l'indirizzo letterale, che è statico attraverso l'esecuzione del programma. Allo stesso modo, potresti dichiarare statica la variabile char [] nel tuo scope locale; in modo che non sia nell'ambito locale.

Ma sinceramente, non capisco perché si desideri che una funzione restituisca un puntatore a un letterale stringa; quando puoi semplicemente definire il letterale al di fuori dell'ambito locale, dove è effettivamente necessario.

+0

La ragione è che la funzione si trova in una libreria che carico dinamicamente al runtime. Lo sto facendo perché il mio sistema live utilizza una password diversa da quella del sistema di test. –

2

Ho un paio di idee:

  1. Conservare la versione hash della password. In getMyPassword(), sfoglia la variabile e restituiscila.

  2. Archiviare la password in un file protetto (crittografato, con autorizzazioni di lettura solo per l'utente, ecc.). Carica la password dal file e ritorna nella tua funzione.

  3. Combina 1 e 2: consente di memorizzare la password con hash nel file protetto, sbrogliarla e restituirla.

Tutto dipende dalla sicurezza che si desidera essere.

+0

Mi piace molto l'idea e ho già usato il tuo rot13 hasher. Lo metto nella libreria crittografato e viene decodificato nel file binario dove è necessario. L'ho lasciato nello stile dell'array per assicurarmi che nessuno possa semplicemente usare la stringa. Volevo provare ora, se posso applicare anche diverse autorizzazioni alle librerie senza rompere la mia app esistente. –

1

È un modo più o meno futile (si sa, chiunque inversione del proprio programma può ottenere facilmente la password) esercizio di steganografia. Ad esempio, per migliorare ulteriormente la sicurezza, effettuare le seguenti operazioni:

  1. Selezionare un valore "seme" da XOR con tutti i caratteri.
  2. La funzione getMyPassword accetta questo carattere. In questo modo, la funzione è quasi inutile se non conosci il seme.

Quindi, ad esempio, prendi il valore 55 come seme.Si può avere qualcosa di simile:

char * getMyPassword(char seed) 
{ 
const char* str = "[email protected]"; 
char *return_arr = malloc(9); /* 8+1 */ 
for (int i=0 ; i < 9 ; ++i) 
    return_arr[i] = str[i]^seed; 
return_arr[i] = 0; 
return return_arr; 
} 

e si deve chiamare getMyPassword(55) per ottenere il risultato corretto. Giuro, il numero 55 è stato scelto a caso, e non so cosa sia DDVG :)

+0

Molto semplice ed efficace. grazie per il tuo consiglio Diego. Potrei combinarlo come ho appena aggiunto un hash rot13 molto semplice. –

+0

Questo è troppo facile. Se guardassi i simboli pubblici di una biblioteca e vedessi una funzione getMyPassword, raddoppierei i miei sforzi per smontare quella funzione. Se in seguito sarò premiato con i dati dei clienti come le informazioni sulla carta di credito ... Ci deve essere un altro modo per ottenere quella password nel programma. Vorrei aprire/dev/tty dopo l'avvio del programma e leggerlo dalla tastiera. Metterlo in una lib o in un file di configurazione è troppo insicuro. –

0

Per quanto riguarda i problemi di sicurezza, Un modo comune per passare le password in sicurezza a un processo è l'utilizzo dell'ambiente. Ad esempio, se alla fine il tuo programma viene chiamato da una pagina web, puoi impostare la password una volta nei file di configurazione di Apache protetti (tramite SetEnv PASSWORD "segreto") e sarà trasmessa a ogni script cgi che esegue e qualunque cosa eseguano . Quindi nel tuo programma devi solo incorporare getenv ("PASSWORD").

Un errore comune è quello di accettare password sulla riga di comando di un programma, questo non dovrebbe essere fatto perché la riga di comando è accessibile da qualsiasi processo in/proc. Questo è come 'ps' può mostrare ciò che è in esecuzione, per esempio.

Inoltre, è possibile impostare il permesso dei programmi su eseguibile ma non leggibile (programma chmod -r + x). Quindi può essere eseguito ma il suo contenuto non può essere effettivamente letto. Sempre una buona idea per qualsiasi cosa nella tua web serving tree per evitare di esporre le cose per errore tramite un errore di configurazione del server. Se questo funziona per gli script di shell dipende dall'implementazione, ma funzionerà con programmi compilati.

Problemi correlati