reales - Vulnerabilidades del módulo mysql de PHP(en desuso) vs. MySQLi y PDOs
sql injection php login (4)
Estoy a cargo de mantener y extender una base de código PHP que comenzó en 2007 y utiliza el módulo mysql
original. Toda la entrada del usuario se escapa usando casting para valores que se espera que sean numéricos, mysql_real_escape_string()
comillas usando comillas simples para cadenas, posiblemente se filtren adicionalmente a través de in_array()
para campos ENUM
o array_intersect()
para campos SET
. Todos los campos de cadena no restringidos se pasan a través de htmlspecialchars()
o htmlentities()
al generar HTML. Donde un valor representa una clave externa, esa clave se verifica primero.
Creo que al seguir estos procedimientos rigurosamente, la aplicación es lo más segura posible contra la inyección y otras formas de ataque. (puntos de bonificación: ¿estoy en lo cierto? Si no, ¿qué me estoy perdiendo?)
Convertir esta aplicación en mysqli
o PDO sería una tarea bastante grande (y, para evitar la rotura accidental, no es algo que quisiera automatizar). Entonces, finalmente, a mi pregunta: ¿hay vulnerabilidades específicas que no se puedan mitigar cuando se utiliza el antiguo módulo mysql
, que requiere migración a los módulos más nuevos?
Bounty Info:
Para ser claros, estoy esperando una lista de números CVE o una declaración de los desarrolladores de PHP que mysql
que el módulo mysql
está parcheado contra todas las vulnerabilidades conocidas a esa fecha. También estoy asumiendo que seguir las Mejores prácticas actuales al usar el módulo no me expone a vectores de ataque adicionales. Los BCP ya incluyen datos de escape tomados del db antes de insertarlo en una nueva declaración. Seguir y seguir sobre eso no es realmente abordar la pregunta.
Tengo pero 2 objeciones
-
All user input is escaped
es una falla crítica, lo que lleva a una inyección de segundo orden . "Todos los datos dinámicos para SQL" es el enfoque correcto y el fraseo - no hay identificadores mencionados en su publicación, pero no puedo creer que no tenga una consulta con identificador dinámico en su código desde 2007.
También hay un pequeño inconveniente: en un par de años (3-4 probablemente), su PHP comenzará a emitir errores de nivel E_DEPRECATED. Pero pueden ser simplemente desactivados.
De todos modos, solo un movimiento mecánico de una API a otra no tendrá demasiado sentido.
Refactorice su código de manejo de SQL solo para hacer uso de algún mecanismo de abstracción, ya sea ORM, AR, QueryBuilder o cualquier otra tecnología que limpie las llamadas API sin procesar desde el código de la aplicación. No solo hará que tu código esté menos hinchado, sino que también lo hará independiente de cualquier otro capricho que afectará a los desarrolladores de PHP en el futuro.
Para responder la pregunta editada.
No hay vulnerabilidades esenciales en la antigua extensión mysql. La única forma en que se usa comúnmente es vulnerable y propenso a errores.
Entonces, en lugar de buscar tensiones en el módulo, mejor audite su código. Si no está utilizando una biblioteca centralizada para la interacción de la base de datos utilizando declaraciones preparadas , lo más probable es que sea vulnerable.
No me siento capacitado para responder a su pregunta de forma definitiva, así que tenga cuidado al usar la información que proporciono, pero tengo cierta experiencia en la gestión del tipo de cambios que podría estar viendo. AFAICS, sin embargo, sus declaraciones deberían protegerlo contra XSS y la inyección SQL si lo que usted dice es cierto.
Recientemente comencé el proceso de migración de una aplicación completa de mysql_ a mysqli_ y, al hacerlo, también establecí el objetivo de que todos los comentarios del usuario pasaran por declaraciones preparadas.
EDITAR en respuesta al comentario justo de YCs a continuación: Para evitar la ambigüedad, siempre pongo todo lo que un usuario ha generado a través de una declaración preparada, incluso si ya se ha almacenado en la base de datos. Siempre que sea posible, evito utilizar la reinserción de los datos del usuario, ya que no es confiable por lo que las funciones del sistema tienden a depender de los índices generados automáticamente.
Para ser justos, las páginas son cortas (no más de 1000 líneas), por lo que corregirlas no requiere mucho tiempo por página y tienen pocas consultas, por lo que la reducción del rendimiento no se nota, y las mejoras en la tecnología de los servidores reducen el problema desde que escribí el código original. . Sospecho que descubrirá que la reducción en el escape, etc. superará con creces cualquier impacto de rendimiento en las declaraciones preparatorias, aunque tendrá que comprobar si es crítico.
Me ha desanimado la cantidad de vulnerabilidades que encontré en mi código mientras hacía esta revisión (incluí la seguridad lo mejor que pude cuando se escribió y me establecí reglas muy parecidas a las tuyas) y finalmente encontré la necesidad de reescribir grandes fragmentos de código para mejorar la seguridad El rendimiento ha mejorado notablemente como resultado de una mayor experiencia y ajustes de código también.
La forma en que voy sobre el cambio es agregar una conexión mysqli a mi archivo de encabezado de base de datos. Todo el código nuevo usa esto. Mientras encuentro el tiempo, estoy actualizando el código anterior y probando cada página usando un archivo de encabezado que no tiene la antigua conexión de MySQL. Es muy rápido encontrar bits que te has perdido de esa manera en un entorno de desarrollo y puede ser una buena manera de usar el tiempo que de otra forma se desperdicia, ya que cada página tarda solo unos minutos en actualizarse, lo que se puede hacer durante el cambio de cerebro períodos.
Una nota sobre la inyección de segundo orden, por cierto, porque esta era la vulnerabilidad más común que había incorporado:
La mayor parte de la prevención de inyección SQL asume que el ataque de inyección solo tendrá lugar al iniciar sesión, desde un usuario malintencionado no registrado que una vez frustrado nunca volverá y que puede confiar en los usuarios registrados. No tan.
Es concebible que el código pueda ser inyectado a través de su protección y luego utilizado. Es poco probable que esto funcione, ya que depende en gran medida del diseño torpe de las bases de datos y de las aplicaciones, pero algunas de las personas más inteligentes del mundo son hackers. ¿Por qué hacerles la vida más fácil?
El ataque se hace más probable si su sql es simple y su aplicación realiza una subconsulta utilizando datos previamente obtenidos de la base de datos. Recuerda eso
'' OR 1=1 gets converted to
/' OR 1=1 by mysql_real_escape_string but is stored as
'' OR 1=1 in the db
por lo tanto, si se recupera y se coloca en una variable PHP que luego se utiliza sin guardar en una consulta SQL, puede causar problemas del mismo modo que si nunca se hubiera escapado. Si solo utiliza las declaraciones de preparación para todas las consultas, el riesgo desaparece de forma permanente, aunque recuerde que la declaración de preparación aún almacenará el código malicioso, por lo que aún tendrá que usar una declaración preparada nuevamente cuando necesite utilizar los datos que se han ingresado.
Este blog ofrece una discusión decente y ejemplos para que no me expanda más, pero si se asegura de que todos los datos de entrada del usuario se pasen a través de declaraciones preparadas si se van a utilizar como parte de una consulta, incluso después de haber sido almacenada en el DB, deberías estar a salvo.
A riesgo de repetición, también vale la pena ser muy amigable con el sitio OWASP que tiene valiosas discusiones de seguridad.
Está bien, entonces investigué un poco y la única vulnerabilidad que he encontrado con respecto a la extensión mysql también parece afectar a la extensión mysqli igualmente es CVE-2007-4889, que es una vulnerabilidad de "Modo seguro puente" y se ha corregido durante mucho tiempo. Hace mucho más que los módulos mysql.so y mysqli.so comparten casi las mismas importaciones que se pueden ver:
/usr/lib/php5/20090626/mysql.so:
0x0000000000000001 (NEEDED) Shared library: [libmysqlclient.so.18]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [mysqli.so]
/usr/lib/php5/20090626/mysqli.so:
0x0000000000000001 (NEEDED) Shared library: [libmysqlclient.so.18]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [mysql.so]
También existe la posibilidad de que surjan nuevas vulnerabilidades en ambos módulos debido a su naturaleza de importación compartida. Y siempre existe la posibilidad de que se origine una falla distintiva a partir del código real de uno de estos módulos. Pero hasta ahora parece que el registro de vulnerabilidad de ambos módulos es prácticamente el mismo en esta fecha
Como mencioné aquí, invertiría más tiempo en auditar el código fuente de PHP y me aseguraré de que haya pocas cosas:
Inyecciones de SQL: las consultas SQL parametrizadas son la mejor solución contra este tipo de fallas.
XSS (Cross Site Scripting): use htmlspecialchars () para filtrar caracteres peligrosos
CSRF (falsificación de solicitudes entre sitios): realice siempre la verificación de referencia en formularios para asegurarse de que los datos llegaron del lugar correcto.
Inclusión de archivos: asegúrese de que ninguna entrada del usuario pueda afectar directamente la inclusión (require (), require_once (), include (), include_once ()) de los archivos
Carga de archivos: en caso de que la carga de archivos esté habilitada por algún motivo, asegúrese de no permitir que el usuario controle la extensión del archivo o guarde los archivos y establezca que su envío sea "no ejecutable". esto se hace para evitar que un atacante cargue un archivo malicioso y ejecute código en su servidor.
Mi respuesta será algo desalentadora, y en lugar de responder a sus preguntas específicas, preferiría sugerir el enfoque que realmente lo ayude.
No importa qué vulnerabilidades se podrían dejar o podrían surgir en el futuro usando mysql, y no importa cuán sólido se aproxime (en lugar de evitar) la base de código actual a la inyección de SQL (aunque parece que lo hace muy bien), tengo la sensación de que aún lo harías en lugar de eso, migrar a mysqli de todos modos, pero apuntar a retrasarlo al ver posibilidades a corto plazo para avanzar aún más por el mysql inseguro y completamente obsoleto.
Sugeriría refactorizar. Período. Solo haz eso. Tenga en cuenta que debe refactorizar, y no cambiar o ampliar su base de código mientras lo hace, es una trampa desagradable. A pesar de que será un trabajo - la refactorización, simplemente comience su proceso de refactorización (por supuesto, ramificado). Será muy satisfactorio al completarlo. Espere algunos problemas de cola larga.
Supongo que cada funcionalidad que describes ya está envuelta, por lo que la refactorización debería ser bastante factible. Si las cosas no hubieran sido envueltas ... ($ # @!), Encuentre una manera única de rastrear sus llamadas a funciones (incluido el contexto) en todo el proyecto (posiblemente utilizando expresiones regulares para encontrarlas todas) y reemplácelas por nuevas y exclusivas: funciones de envoltura usadas. Primero explora esto, a fondo. En medio día, podrías enlistar toda tu expresión regular que necesitarás. Así que planifícalo primero, explorando primero tu camino.
Llene las nuevas envolturas con el código funcional actual (antiguo) y vea si todo sigue funcionando como estaba.
Luego comience a migrar a mysqli, y reconstruya sus contenedores internamente.
Parece ser un enfoque tan simple como sea posible, evitando todos los asuntos y preguntas que permanecerán en el fondo de tu mente a pesar de lo que sea que intentes al hackear tu camino más profundo alrededor del mysql común. No necesito contarte sobre los beneficios que traerá mysqli, ya los conoces. Además, simplemente es una buena práctica de vez en cuando emprender ese tipo de problemas de una vez por todas. ¡Planifica, discute, ramifica, intenta, haz, prueba, completa y conquista! Además de todo: asegúrate de no aprovechar las oportunidades para ampliar tu base de código y alcance funcional mientras refactorizas: estarás tentado de hacerlo: simplemente refactoriza. Agregar, extender o mejorar más tarde.