Consideraciones de seguridad

La seguridad es un tema complejo y en esta sección no se puede explicar ni de lejos todo lo relacionado. Intentaremos indicar las situaciones más comunes donde tus programas deben interesarse por la seguridad.

Es muy fácil crear hoyos de seguridad a través de la creación incorrecta de archivos temporales en /tmp. Debes garantizar que los archivos que usarás no existen al momento de su creación. Usar un nombre de archivo «único» e «impredecible» no es suficiente; debes garantizar que el archivo con ese nombre no será creado por alguien más entre el tiempo en que se determina el nombre y el tiempo en que es efectivamente creado (básicamente los ataques involucran que un tercero cree un enlace simbólico al archivo que ellos quieren sobreescribir).

Afortunadamente, esto es fácil de hacer. Usa el siguiente trozo de código:

	char *filename;
	int fd;

	do {
		filename = tempnam (NULL, "foo");
		if (!filename) {
			fprintf (stderr, "Could not create temporary file name\n");
			exit (EXIT_FAILURE);
		}

		fd = open (filename, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
		free (filename);
	} while (fd == -1);

Recuerde liberar filename usando la función free() y llamar a las funciones close() y unlink() con el archivo respectivo cuando haya terminado; aquí liberamos filename con free() inmediatamente y así no causará una pérdida de memoria.

Si deseas usar la biblioteca estándar de E/S, puede usar la función fdopen() para transformar el descriptor de archivo en FILE *, o puedes usar la función tmpfile() para hacerlo en un solo paso.

Intenta no usar buffers de tamaño fijo. Los buffers de tamaño fijo para cadenas constituyen los típicas fuentes de hoyos explotables que pueden llegar a oscuros errores. Si definitivamente debes usar buffers de tamaño fijo para cadenas, usa la función g_snprintf() para especificar el tamaño máximo del buffer.

Glib proporciona la, muy conveniente, función g_strdup_printf(), la cual funciona como sprintf() pero automáticamente localizará un buffer con el tamaño correcto. El valor de retorno de esta función debiera ser liberada usando g_free(). A menudo es más conveniente de usar que g_snprintf(), ya que esta no limita el tamaño de las cadenas que un programa puede manipular.

Si deseas concatenar un grupo de cadenas, puedes usar la función g_strconcat(), la cual recibe una lista variable de cadenas y un puntero a NULL como último argumento.

Bajo ninguna circunstancia crees un programa GTK+ con setuid root. Las bibliotecas de GTK+ y GNOME son grandes y complejas y no han tenido auditorías de seguridad. En cualquier caso, no debieras querer que una pieza tan grande código sea setuid root. Si definitivamente requieres usar privilegios de root para algo, escribe un programa que sea la interfaz de usuario como un proceso normal, sin privilegios y crea un programa nexo que tenga setuid y se encargue de realizar la operaciones «peligrosas». Además, notifica a las listas de correo de desarrollo de GNOME indicando que requieres que alguien realice una auditoría de seguridad a tu programa nexo.

En general, si no estás seguro si puedes crear un riesgo de seguridad, pregunte en las listas de correo de desarrollo de GNOME.

Puedes leer más sobre temas de seguridad que debieras encontrar cuando programes una aplicación Unix en el documento «Murphy's Law and Computer Security», de Wietse Wenema. Hay otros documentos de seguridad en el sitio fish.com que podrías encontrar interesante.

Puedes encontrar muchas otras guías útiles para escribir programas seguros en «Secure Programming for Linux and Unix HOWTO».