2011-10-11 16 views
6

Tengo una función que devuelve una cadena:C: Volviendo cadena a partir de la función

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

Bueno, funcionó perfectamente, pero he descubierto que si iba a funcionar "cadenas" en sistemas Unix que aparece en el lista ... no es bueno

¿Cuál es la forma más fácil de reemplazarlo? La función se encuentra en una biblioteca y quiero mantenerla flexible. Ahora comencé mallocing dentro de la función y la cadena en cadenas desapareció. Sin embargo, ¿cuándo lo liberaría de nuevo?

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; 

} 

Si tuviera que malloc antes y pasar un puntero, entonces, ¿cómo iba a saber el tamaño antes de que el tamaño de las contraseñas sólo se conoce dentro de la función?

Como un plan B que podía pasar una enorme variedad, pero eso no parece muy elegante. ¿Cómo debería abordar esto?

EDITAR: He añadido el strcpy (return_arr, arr). De hecho, lo tenía en el código original, pero lo olvidé aquí.

+0

Ponlo allí hacia atrás, luego usa '' 'strrev()' ''. O bien, rot-13 dos veces. –

+6

Si vas a usar contraseñas, te recomiendo usar contraseñas hash en lugar de la cadena literal. Eso definitivamente reducirá la cantidad de información que alguien puede obtener al ejecutar 'cadenas' en el programa. Puede personalizar una función hash para que la gente no pueda (o al menos sea mucho más difícil) determinar cuál es realmente el valor. – dbeer

+0

¿Con qué propósito se debe usar la contraseña?¿Iniciar sesión en algún lugar o tal? –

Respuesta

2

Problemas de seguridad aparte, lo que está tratando de hacer es asignar dinámicamente el búfer.

Puede tomar 2 enfoques.

  1. Siempre malloc dentro de su función y documentarla que vuelva malloced resultado.
  2. Siga el camino de algunas funciones de biblioteca estándar, solicite que el usuario pase un puntero a un búfer válido y su tamaño y devuelva el tamaño realmente copiado. Algunas de estas funciones permiten el pase check, cuando pasa en un buffer null, no intentan asignarlo, sino que devuelven el tamaño requerido para mantener la estructura.

Me parece que ya ha implementado el enfoque n. ° 1.

Para la aproximación # 2 utilizan esta 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; 
} 

ventaja del método de # 2 es que la persona que llama, en muchos casos, puede asignar el almacenamiento intermedio en la pila, sobre todo si se anuncia el máximo requerido tamaño del búfer. Otra ventaja es que la administración de memoria ahora está completamente manejada por el cliente. En la biblioteca de propósito general, no desea crear un cliente dependiendo de un esquema de asignación de memoria de la biblioteca en particular.

respuesta a la observación

Si siempre desea utilizar el valor asignado en su código de cliente, entonces así es como me gustaría hacer esto:

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 vez leí que es una mala práctica mallocar algo y luego devolverlo, por lo que siempre traté de evitar hacerlo. Así que gracias por tu segundo enfoque, Alex. ¿Qué piensas sobre pasar el buffer y luego reasignarlo? –

+0

@Frank. Si en su código de cliente siempre quiere confiar en 'malloc', está bien. Editaré la respuesta para mostrarte un ejemplo de cómo haría esto. –

+0

Muy útil. ¡Gracias! –

2

Creo que el problema aquí es que está tratando de devolver un puntero a una variable que se define localmente cuando está tratando de devolver una cadena como esa. Esperaría que tu primera función funcione, ya que el puntero devuelve la dirección a un literal, que es estático a través de la ejecución del programa. Del mismo modo, puede declarar que la variable char [] en su ámbito local es estática; para que no esté en el ámbito local.

Pero, sinceramente, no entiendo por qué querría que una función devuelva un puntero a un literal de cadena; cuando puedes simplemente definir el literal fuera del alcance local, donde realmente se necesita.

+0

La razón es que la función se encuentra en una biblioteca que cargo dinámicamente en tiempo de ejecución. Lo hago porque mi sistema en vivo usa una contraseña diferente a la del sistema de prueba. –

2

Tengo un par de ideas:

  1. Store la versión hash de la contraseña. En getMyPassword(), deshaga la variable y regrésela.

  2. Almacene la contraseña en un archivo protegido (encriptado, con permisos de lectura solo para su usuario, etc.). Cargue la contraseña del archivo y regrese en su función.

  3. Combine 1 y 2 - almacene la contraseña hash en el archivo protegido, desactívela y devuelvala.

Todo depende de qué tan seguro desee estar.

+0

Me gusta mucho la idea y ya usé tu hasher Rot13. Lo puse en la biblioteca encriptado y se descifra en el binario donde se necesita. Lo dejé en el estilo de matriz para asegurarme de que nadie pueda usar una cadena. Quería probar ahora, si puedo aplicar diferentes permisos a las bibliotecas sin romper mi aplicación existente. –

1

Es más o menos inútil (ya sabes, cualquiera puede realizar una inversión inversa en tu programa puede obtener la contraseña fácilmente) ejercicio de esteganografía. Puede, por ejemplo, mejorar un poco más la seguridad, haga lo siguiente:

  1. Seleccione un valor de "semilla" para ser XOR con todos los caracteres.
  2. Realice la función getMyPassword para aceptar ese carácter. De esta manera, la función es en gran medida inútil si no conoce la semilla.

Por lo tanto, por ejemplo, tome el valor 55 como su semilla.Puede tener algo como:

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; 
} 

y hay que llamar getMyPassword(55) para obtener el resultado correcto. Lo juro, el número 55 fue elegido al azar, y no sé qué DDVG es :)

+0

Muy simple y efectivo. gracias por tu consejo Diego. Podría combinarlo ya que acabo de agregar un hasher rot13 muy simple. –

+0

Esto es muy fácil. Si miraba los símbolos públicos de una biblioteca y veía una función getMyPassword, duplicaría mis esfuerzos para desmontar esa función. Si luego me recompensan con datos del cliente como la información de la tarjeta de crédito ... Debe haber otra forma de ingresar esa contraseña en el programa. Abría/dev/tty después del inicio del programa y lo leía desde el teclado. Ponerlo en una lib o en un archivo de configuración es demasiado inseguro. –

0

En lo que respecta a los problemas de seguridad, Una forma común de pasar contraseñas de forma segura a un proceso es usar el entorno. Por ejemplo, si su programa finalmente es llamado desde una página web, puede establecer la contraseña una vez en los archivos seguros de configuración de Apache (a través de SetEnv PASSWORD "secret") y se pasará a cada script cgi que se ejecute, y lo que sea que ejecuten . Luego, en su programa solo necesita incrustar getenv ("CONTRASEÑA").

Un error común es aceptar contraseñas en la línea de comandos de un programa, esto no se debe hacer porque se puede acceder a la línea de comandos mediante cualquier proceso en/proc. Así es como 'ps' puede mostrar lo que se está ejecutando, por ejemplo.

Además, puede configurar el permiso de sus programas para ejecutable pero no legible (programa chmod -r + x). Por lo tanto, se puede ejecutar pero su contenido no se puede leer realmente. Siempre es una buena idea para cualquier cosa en su árbol de servicio web para evitar exponer las cosas por accidente a través de un error de configuración del servidor. Si esto funciona para los scripts de shell depende de la implementación, pero funcionará para los programas compilados.

Cuestiones relacionadas