Mejores técnicas que el cifrado de parámetros url

17

Soy un programador que trabaja en una aplicación donde la única opción / vs / deadline era implementar un cifrado simétrico en los valores de los parámetros de URL. Los datos son de naturaleza insensible, pero necesitábamos evitar que los agentes de ventas se asomaran entre ellos. (Las claves se generan al crear la sesión y son criptográficamente sólidas). Se espera que las sesiones terminen con frecuencia.

La jerarquía de funciones era Administrador - > Supervisor - > Agentes. Las estructuras de datos actualmente no tienen en cuenta estos roles de manera que se haga cumplir estrictamente quién puede ver qué. Obtener esta información de la base de datos NO fue en absoluto algo sencillo. (Base de datos recursiva).

Sé que esta técnica está muy abajo en la lista como defensa contra la manipulación de parámetros. ¿Cuál hubiera sido una técnica mejor?

Restricciones:
La verificación basada en roles no es una opción.

[Información adicional] Las direcciones URL creadas y enviadas al cliente antes de realizar cualquier cambio parecían:

https://www.example.com/agent/?producerId=12345

La superficie de amenaza específica aquí es la manipulación de parámetros contra? agentId = 12345. Las identificaciones de los agentes se asignan de forma única a cada agente. Entonces, si el Agente A quiere ver las estadísticas del Agente B, podría haber ingresado a agentId = 22222 para ver las cotizaciones de ese agente y las estadísticas de ventas actuales.

Una vez más, la comprobación basada en roles no era una opción para mí: no pude realizar cambios en la base de datos O en el nivel de persistencia.

Mi solución fue utilizar una clave de cifrado creada por la sesión (utilizando la clase KeyGenerator de Java) y cifrar las direcciones URL de salida enviadas al cliente. Así que ahora, la url se ve como:

https://www.example.com/agent/?producerId=<ciphertext>

Ahora, si alguien intenta agentId = 22222, el servidor descifra lo que piensa es texto cifrado y, en última instancia, creará una secuencia de caracteres no válida.

(Esto deja abierta la posibilidad de que se pueda encontrar un AgentId , pero es poco probable que sea relevante para la persona que realiza el ataque.

Enfatizaré que esta pregunta no se trata de la seguridad óptima (que sería una verificación basada en roles para garantizar el acceso a los recursos) y de tratar de exprimir algo de seguridad en un área gris.
=============== Actualización ============ Uno de nuestros tipos de seguridad me recomendó la solución de cifrado de parámetros aquí. Obtuve una información para llevar que no había considerado en esta solución - urls rotas - y utilizaré que , así como el problema de mantenimiento creado por esta solución para discutir el tiempo para hacer cumplir las reglas de acceso De una manera menos provisional.

    
pregunta avgvstvs 16.07.2012 - 15:24
fuente

5 respuestas

12

Buena pregunta! Gracias por explicar la amenaza contra la que intentas defenderte. He editado mi respuesta en consecuencia.

Resumen. Su defensa principal debe ser control de acceso . Debe limitar qué usuarios pueden ver qué páginas. Detalles a continuación.

Control de acceso en aplicaciones web. Lo que debe hacer es verificar que el usuario esté autorizado para acceder a los datos que va a mostrar en una página, antes de permitirles ver esos datos. Básicamente, esto se reduce al control de acceso: desea controles que limiten qué usuarios pueden ver qué datos, según una política de autorización.

Parece que tiene una secuencia de páginas, una para cada agente:

http://www.example.com/agent/?producerId=12345
http://www.example.com/agent/?producerId=12346
http://www.example.com/agent/?producerId=12347
...

donde los ID de productor (agentIds) son potencialmente adivinables o predecibles. Desea asegurarse de que el agente 12345 pueda ver http://www.example.com/agent/?producerId=12345 pero no cualquiera de las otras páginas. Ok.

Esta es una situación estándar de bog, y la defensa estándar de bog es: control de acceso.

Para implementar el control de acceso, codifique la aplicación web para que cada página verifique si el usuario está autorizado para ver esa página antes de permitirle ver esa página. Por ejemplo, para la página mencionada anteriormente, la lógica que implementa esa página verificará la identidad del usuario que ha iniciado sesión actualmente. Si la identificación del usuario que ha iniciado sesión coincide con el ID de productor del parámetro de página, entonces les muestra la información. Si la identificación no coincide, no les muestra la información: si es otro usuario, les muestra una página de error (con información sobre cómo obtener acceso), o si el usuario aún no ha iniciado sesión, redirige ellos a una página de inicio de sesión.

Esto no romperá los marcadores. No requiere cambios en la base de datos, cambios en la capa de persistencia o control de acceso basado en roles. Requiere que tengas una forma de buscar la identidad del usuario que ha iniciado sesión y asociarlo con su ID de proveedor. Además, si desea permitir que el administrador y los supervisores vean los datos de todos los demás agentes, entonces necesita una forma de buscar al usuario que ha iniciado sesión y determinar si es un administrador o supervisor o no. Si desea permitir que solo el gerente / supervisor del agente vea su página (no todos los demás gerentes / supervisores), debe tener una forma de determinar el gerente / supervisor de cada agente. Estos son requisitos bastante básicos, mínimos; es difícil ver cómo podrías evitarlos.

Como @symbcbean señala correctamente, este es un error muy común que se encuentra con frecuencia en las aplicaciones web. Un ejemplo típico podría ser un sitio que utiliza un valor de parámetro que se puede adivinar para identificar un recurso y que no autentica adecuadamente al usuario. Por ejemplo, supongamos que a los pedidos se les asigna un número de orden secuencial:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

y suponga que cualquiera que conozca la URL puede ver el pedido. Eso sería malo, porque significa que cualquiera que sepa (o adivine) el número de pedido puede ver el pedido, incluso si no está autorizado para hacerlo. Este es uno de los Top Ten de los riesgos de seguridad de las aplicaciones web: Referencias de objetos directos inseguros . Para más información, recomiendo leer los recursos disponibles en OWASP. OWASP tiene muchos recursos excelentes sobre seguridad de aplicaciones web.

Otros comentarios. Otros han sugerido el uso de SSL. Si bien eso no evitará la manipulación de parámetros, es una buena práctica de seguridad general que se defiende contra otros tipos de problemas. El uso de SSL es sencillo: simplemente configure su sitio web para usar https, en lugar de http (e idealmente, habilite HSTS y configure el bit secure en todas las cookies).

Además, a menudo es mejor evitar almacenar información confidencial en parámetros de URL, todo lo demás es igual. Puede almacenar la información confidencial en el estado de la sesión o en la base de datos.

    
respondido por el D.W. 16.07.2012 - 20:29
fuente
6

En resumen: No encripte los parámetros de la URL, use una buscar .

Además, el uso de HTTPS es básicamente no negociable si desea cualquier medida de seguridad de la aplicación web. Es obligatorio en 2015. Siéntase cómodo con TLS 1.1+.

Lo que los desarrolladores quieren hacer

Loquelosdesarrolladoresdeberíanhacerensulugar

    
respondido por el Scott Arciszewski 30.09.2015 - 15:51
fuente
3
  

pero teníamos que evitar que los agentes de ventas se asomaran entre ellos mismos.

Esto implica que el cliente es un navegador, ¿está enviando la clave como texto simple en algún momento?

El polinomio es correcto, debes usar SSL. Eso no solucionará el problema de los usuarios que escriben valores adyacentes a una URL con un aspecto como:

https://www.example.com/show_order.php?id=1234
https://www.example.com/show_order.php?id=1235
https://www.example.com/show_order.php?id=1236
...

Es bastante posible generar un token de autenticación del lado del servidor en función de los parámetros que se deben presentar para validar la solicitud. Lo ideal sería utilizar un código de autenticación de mensaje (MAC) para esto, pero un hash también funcionaría si tiene cuidado. p.ej. en PHP ...

 print "<a href='show_order.php?id=" . $id . "&valid=" . md5($id . crypto_key()) . "'>...

Lo cual es validado simplemente por:

if ($_GET['valid'] != md5($_GET['id'] . crypto_key()) {
   die('not authorized');
}

Aquí crypto_key() devuelve una clave criptográfica estática (genérela al extraer, por ejemplo, 128 bits de /dev/urandom y almacenándola en la base de datos).

Pero aún debe controlar el acceso al código que genera la URL.

    
respondido por el symcbean 16.07.2012 - 17:27
fuente
2

Aquí está mi solución

$id=1234;
$en_id = encrypString( $id);

y creo la url como

https://www.example.com/show_order.php?id=$en_id

la url se verá como

https://www.example.com/show_order.php?id=9muEYh4lShFDeCnXqoNpxucs42Fuz5Nexq1IUGWYEffffe88yRbJu

y en el otro lado descifro

$en_id= decryptString($_GET['id']);

las funciones para cifrar y descifrar son

function encrypString($plaintext) {
         # --- ENCRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";


        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        # creates a cipher text compatible with AES (Rijndael block size = 128)
        # to keep the text confidential 
        # only suitable for encoded input that never ends with value 00h
        # (because of default zero padding)
        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                                     $plaintext, MCRYPT_MODE_CBC, $iv);

        # prepend the IV for it to be available for decryption
        $ciphertext = $iv . $ciphertext;

        # encode the resulting cipher text so it can be represented by a string
        $ciphertext_base64 = base64_encode($ciphertext);

        return  rawurlencode($ciphertext_base64);//important rawurlencode for + symbol in url

    }


decryptString($ciphertext_base64) {
        # --- DECRYPTION ---

        $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");//change this

        # show key size use either 16, 24 or 32 byte keys for AES-128, 192
        # and 256 respectively
        $key_size =  strlen($key);
        //echo "Key size: " . $key_size . "\n";

        # create a random IV to use with CBC encoding
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);

        $ciphertext_dec = base64_decode($ciphertext_base64);

        # retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
        $iv_dec = substr($ciphertext_dec, 0, $iv_size);

        # retrieves the cipher text (everything except the $iv_size in the front)
        $ciphertext_dec = substr($ciphertext_dec, $iv_size);

        # may remove 00h valued characters from end of plain text
        $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
                                    $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

        return rawurldecode($plaintext_dec);
    }
    
respondido por el Valentin Ursuleac 18.07.2014 - 00:16
fuente
1

Para evitar la manipulación de parámetros, siempre he enviado un hash con los valores de texto sin formato.

por ejemplo toma esta url que quieres asegurar

https://www.mysite.com/somepage?param1=abc&param2=xyz

En el servidor, su modelo haría un hash de todos los valores de URL con una sal secreta

string salt = "A1B2C3D4...";
string param1 = "abc";
string param2 = "xyz";
string hash = YourFavoriteHashingAlgorithm(param1 + param2 + salt);
// result hash = "Y83YMB38DX83YUHFIEIGKDHSEUG"

luego envías este hash junto con los otros valores de url

https://www.mysite.com/somepage?param1=abc&param2=xyz&hash=Y83YMB38DX83YUHFIEIGKDHSEUG

Ahora, cuando recibe una solicitud a esta URL, nuevamente toma los parámetros que se le presentan y los revisa a través del mismo algoritmo. El hash que acaba de generar debe coincidir con el hash que se le presenta, de lo contrario, envíe un resultado de 400 "Solicitudes incorrectas".

Lo bueno es que sus parámetros aún son legibles por los humanos, y toda su lógica de validación existente puede permanecer igual.

    
respondido por el raterus 01.12.2017 - 03:02
fuente

Lea otras preguntas en las etiquetas