Cómo escapar de las vulnerabilidades SQL
En resumen, Redis es una poderosa base de datos clave-valor, y lo es por dos razones: primero, tiene una gran capacidad de respuesta (por lo que los datos se almacenan en la memoria y solo se escriben en el disco cuando es necesario). y la segunda es que tiene muchas funciones (admite una amplia gama de tipos de datos y operaciones complejas en cada tipo).
De hecho, una de las características principales de Redis es que no es una base de datos en el sentido habitual; aunque se llama base de datos porque almacena y mantiene datos para usted, no los proporciona
p>Cualquier dialecto SQL como una base de datos relacional. Pero no se preocupe, Redis no es un agujero negro que se alimenta de datos. Simplemente no admite SQL y funciones relacionadas, pero proporciona un protocolo poderoso para interactuar con él.
En Redis, no existe el concepto de tablas de datos, no tienes que preocuparte por las selecciones, conexiones, vistas u otras operaciones o funciones, y no hay campos de datos como int o varchar. Trabajará con colecciones y tipos de datos relativamente primitivos.
Exploración n.º 2: tipos de datos disponibles
Echemos un vistazo más de cerca a cómo funciona esta extraña base de datos. Como se muestra arriba, Redis almacena datos según el paradigma clave-valor, así que primero centrémonos en el concepto de "clave".
Las claves son esencialmente cadenas simples, como "nombre de usuario", "contraseña", etc. Al definir claves, puede usar caracteres comunes, números, etc., pero no puede usar espacios
, como ".", ":", "_", etc., que se pueden usar normalmente. al definir claves, por lo que "user_name", "user:123:age",
"user:123:username", etc. son buenas formas de definir claves.
A diferencia de los nombres de campos en RDBMS, las claves aquí son una parte importante de Redis, por lo que debemos tener más cuidado al manejar las claves. En la descripción siguiente, Redis no tiene ningún concepto de tablas
, por lo que tareas simples como "SELECCIONAR el nombre de usuario de los usuarios DONDE
user_id=123;" deben realizarse de manera diferente. En Redis, una La forma es obtener el valor del resultado a través de la clave
"usuario:123:nombre de usuario". Como puede ver, las claves contienen información oculta (como el
id de usuario) en su definición. En Redis, la importancia de la clave es evidente. (
Ahora que debe tener una comprensión clara de las claves, lo siguiente lo llevará al mundo mágico de los tipos de datos disponibles.
Cadenas
Las cadenas son El tipo de datos más básico en Redis es simplemente una cadena binaria segura y la longitud máxima de datos admitida es 1 GB. Puede configurar los datos del tipo de cadena como una clave mediante el comando SET y pasar GET. El comando obtiene el resultado según la clave. Si desea almacenar información numérica (como un contador), también puede almacenarla en datos de cadena e incrementarla y disminuirla usando INCR y DECR
List<. . /p>
Una lista es una colección de datos de cadena en la que los elementos de datos están organizados en orden de inserción. Puede pensar en una lista como una cadena, por lo que puede agregar elementos a la izquierda (la cabeza de la cadena). ) o a la derecha (la cabeza de la cadena) para agregar un nuevo eslabón también puedes agregarlo al medio de la cadena, pero para romper un eslabón
Puedes usar el LPUSH; y comandos RPUSH para agregar un nuevo enlace a la lista (L: izquierda,
R: derecha) Agregar datos, usar el comando LPOP o RPOP para extraer elementos (y eliminar elementos al mismo tiempo), y use el comando LRANGE para obtener elementos en un rango específico (este comando solo devuelve datos y no elimina ningún elemento
).
También es posible agregar un elemento en una posición específica mediante LSET, pero generalmente esta operación es mucho más lenta que un simple LPUSH o RPUSH.
Hashing
Hashing almacena datos más estrechamente relacionados de forma concisa, implementando pares clave-valor integrados para cada clave de almacenamiento para almacenar datos, por ejemplo, para el "usuario" clave, cuyo valor puede ser una combinación de múltiples campos y un par de valores correspondiente a cada carácter. Si estás familiarizado con lenguajes de programación como Ruby o JavaScript, el concepto de cenizas es muy parecido al de esos lenguajes.
Conjunto
El significado de un conjunto es el mismo que su nombre matemático "conjunto", que es una colección de elementos que no se repiten. En Redis, estos objetos se convierten en tipos de cadenas en Redis. Como puede imaginar, los conjuntos se diferencian de las listas en que los elementos de un conjunto están desordenados y no se pueden repetir dos datos idénticos en un conjunto;
Puede agregar datos a una colección a través de SADD, eliminar datos a través de SREM o devolver y eliminar datos a través de SPOP. Además, puede utilizar los comandos SUNION, SINTER y SDIFF para realizar operaciones de unión, intersección y diferencia en conjuntos.
Conjuntos ordenados
Los conjuntos ordenados son similares a los conjuntos, pero cada elemento de un conjunto ordenado tiene un peso que se utiliza para compararlo con otros elementos y ordenar.
Por supuesto, los conjuntos ordenados también tienen operaciones similares a los conjuntos ordinarios que se utilizan para agregar y eliminar elementos respectivamente. Los conjuntos ordenados también tienen sus propias operaciones únicas, a saber, ZINCR y ZSCORE. El primero se usa para sumar 1 al peso del elemento y el segundo se usa para devolver el valor de peso del elemento.
Exploración 3: ¿Dónde está mi reloj?
Usar Redis es completamente diferente a las tablas SQL que usábamos antes. No existe ningún lenguaje que le permita consultar datos en el servidor y solo hay unos pocos comandos que le ayudan a manipular claves en la base de datos.
Los comandos en Redis son sensibles al tipo de datos, lo que significa que no puede ejecutar el comando set en una lista o obtendrá un error de ejecución. Puede enviar comandos al servidor Redis a través de redis-cli u otras interfaces
en el lenguaje de programación que utilice. En el siguiente ejemplo, solo nos centraremos en el comando en sí y no en cómo enviar el comando al servidor Redis
.
Imagínese una tabla de base de datos SQL simple, como la que algunas aplicaciones usarían para almacenar datos de usuario:
id nombre de usuario contraseña nombre
1 usuario1 contraseña1 Bob Smith
2 usuario2 pase2 Mario Rossi
Almacenamiento de datos
Si queremos almacenar los datos anteriores en Redis, ¿cómo diseñarías la solución de base de datos en el plan Redis? Quizás sería más intuitivo pensar en ello como una aplicación. Usando SQL, podemos obtener información del usuario especificando el ID de usuario en
SELECT. En otras palabras, necesitamos usar algunos métodos para distinguir diferentes entidades de datos para que podamos usar identificadores únicos p><. p>información para identificar y obtener información del usuario. Por lo tanto, si agregamos la información de identificación del usuario a la clave en redis, nuestras necesidades de consulta se resuelven fácilmente.
En redis, los datos se almacenan en la siguiente forma:
Valor clave
usuario: 1: nombre de usuario usuario1
usuario: 1: contraseña contraseña1
usuario: 1: nombre Bob
usuario: 1: apellido Smith
usuario: 2: nombre de usuario usuario2
usuario: 2: contraseña contraseña2 p >
usuario: 2: nombre Mario
usuario: 2: nombre Rossi
Luego, dado un ID de usuario, podemos ingresar usuario: id: nombre de usuario, usuario Leer usuario información en forma de :id:contraseña, usuario:id:nombre, usuario:id:apellido.
Inicio de sesión de usuario
El almacenamiento anterior también se puede utilizar para el inicio de sesión de usuario, pero requiere una forma de buscar la identificación del usuario según el nombre de usuario, lo que significa que también necesitamos un enlace. entre el nombre de usuario y la identificación Crear enlaces. Esto se puede lograr agregando otra clave de Redis "usuario: nombre de usuario: id".
valor clave
usuario: usuario1: id 1
usuario: usuario2: id 2
Ahora, si Mario Rossi quiere iniciar sesión En , podemos usar la clave "usuario: usuario2: id" para averiguar primero el nombre de usuario y luego podemos obtener toda la información sobre el usuario.
Clave principal
Cómo garantizar la unicidad de los valores de identificación en Redis. En SQL, esto se puede lograr definiendo una clave primaria de incremento automático usando "id int clave primaria
auto_increment". Ahora necesitamos un método similar para generar una identificación diferente para cada usuario. Según los datos numéricos mencionados en los tipos de datos disponibles en la sección anterior, la solución de Redis es la siguiente: cree una clave "usuario", luego obtenga toda la información del usuario y luego cree una clave "usuario": next_id". y utilícelo como contador para ejecutar un comando INCR en la clave "usuario:next_id" cada vez que se vaya a agregar un nuevo usuario.
SELECT * FROM usuarios;
La siguiente pregunta es consultar la lista de usuarios. Podría pensar que el almacén de datos anterior es suficiente para consultar una lista de usuarios: podría obtener el valor actual del contador "user:next_id" y luego obtener los datos del usuario yendo de 0 al contador en uno o más pasos. Sin embargo, si un usuario es eliminado del sistema (analizaremos la eliminación a continuación) y repetimos todos los identificadores desde 0 hasta
contador, entonces no podremos obtener ningún dato con certeza. identificaciones.
Aunque esto no suele ser un problema, no queremos perder tiempo con datos de usuario que no existen, por lo que necesitamos crear otra clave "usuario:lista" con un valor de lista o
.
Eliminar usuarios
Otro problema a afrontar es el de la "integridad de los datos" y ver qué sucede cuando eliminamos un usuario.
Necesitamos eliminar todas las referencias a este usuario, es decir, eliminar todos los ID de usuario en las claves "usuario:id:*", "usuario:nombre de usuario:id" y "usuario:lista".
Exploración 4: Un caso de uso simple
Para conocer el caso de uso, intentemos diseñar una biblioteca virtual con funcionalidad para agrupar libros por tema. El siguiente ejemplo es un poco más complejo que la tabla de usuarios anterior, pero aprenderá a manejar las relaciones en Redis.
En la aplicación necesitamos recopilar libros y almacenar su título, autor, materia, número de páginas, precio,
ISBN y descripción. Obviamente, algunos libros tienen más de un autor y pueden cubrir diferentes temas (por ejemplo, un libro puede tratar sobre temas de programación o puede tratar sobre descripciones de codificadores Ruby). Otro autor puede haber escrito muchos libros y un tema debe contener muchos libros. Como puede ver, existen relaciones de muchos a muchos entre autores y libros, y temas y libros.
Escenarios de aplicaciones SQL
Primero, intentemos usar tablas de datos SQL para modelar los datos de dichos escenarios de aplicaciones para simular estos escenarios de aplicaciones de manera más intuitiva en el dominio de Redis:
Libros
ID Título Página Precio ISBN Descripción
1 Programación Ruby 829 $26 0974514055 lenguaje de programación ruby
2 Erlang Programación 496 $42 0596518188 erlang Introducción
Autor
ID Nombre
1 Dave Thomas
2 Chad Fowler
3 Andy Hunt
p>
4 Francesco Cesarini
5 SimonThompson
Temas
id nombre descripción
1 programación Libros sobre programación
2 libros de ruby sobre ruby
3 libros de erlang sobre erlang
Libros-Autores
book_id Author_id
1 1
p>1 2
1 3
2 4
2 5
Libros-Temas
book_id topic_id
1 1
1 2
2 1
2 3 p>
Escenarios de Redis p>
Ya hemos cubierto cómo almacenar datos en Redis, por lo que comprender los libros, los autores y las tablas de temas aquí no debería ser un problema. Sin embargo, el problema se complica cuando se enfrentan relaciones de muchos a muchos entre tablas como Libros-Autores y Temas de libros. Tomemos Temas como ejemplo para explicar cómo resolver la relación entre libros y Asociación de Temas. Una vez que la relación sea clara, la relación entre libros y autores se resolverá fácilmente.
Para cada libro, necesitamos saber a qué temas pertenece, y para cada tema, necesitamos procesar cada libro que contiene, es decir, para cada libro, necesitamos
p; >Una lista de identificadores para los temas asociados con él, y para cada tema, necesitamos una lista de identificadores para los libros asociados con él. Aquí es donde entra en juego el conjunto.
Crearemos dos conjuntos: "book:id:topic" y "topic:id:books". El primero almacena la lista de ID de temas de libros y el segundo almacena la lista de ID de libros. temas
. Tomando como ejemplo los datos del escenario SQL anterior, la clave del libro "Programación
Erlang" (el ID en la tabla de libros es 2) es "libro:2:topics", el valor es el tipo establecido y los datos son (1, 3);
La clave del conjunto de datos del tema "Programación" es "tema:1:libros", y el valor es (1,2 );
Y el tema La clave del conjunto de datos "Programación" es "tema:1:libros" y el valor es (1, 2).
Después del análisis, derivamos el modelo de datos de la aplicación Redis:
Autor
Cadena
- autor: id
- autor: id: nombre
- autor: id: apellido
Colección
- autor: id: libros
Listas
- lista de autores
Libros
Cadenas
- libro:id:páginas
- libro: id:título
- libro:id:páginas
- libro:id:precio
- libro:id:isbn
- libro:id:descripción
Conjuntos
- libros:id:autores - libros:id.topic
Lista
- libro: lista
Temas
Cadena
- tema: id
- tema: id: nombre
- tema : id: descripción
Colección
- tema: id: libros
Listas
- tema: lista
Como puede ver, las relaciones de muchos a muchos en SQL se pueden implementar en Redis con dos colecciones. Esta implementación le resultará muy útil, ya que nos permite obtener libremente información adicional sobre libros que pertenecen a múltiples temas al cruzar todos los conjuntos de interés "topic:id:books".
Por ejemplo, la intersección
"topic:1:books" (tema de programación) y "topic:2:books" (tema de Ruby) dará como resultado una colección con un solo elemento (1)
, obteniendo así el libro con id=1: Programación Ruby.
Con esta implementación se debe prestar especial atención al borrado de datos.
Dado que hay referencias a libros en el tema y hay referencias a temas en los libros, ¿cómo se realiza la operación de eliminación?
Tomando como ejemplo eliminar datos en un libro, lo primero que me viene a la mente es eliminar cada dato con la clave "libro:id:*", pero antes de hacer esto, debes recorrer todas las claves del tema. p>
colección "topic:id:books" y elimine la identificación del libro que desea eliminar, por supuesto, también elimine la clave del libro "
Si desea eliminar el tema, la operación es similar: borrar todo en el tema Antes de eliminar la información con la clave "topic:id:*", es necesario recorrer el tema establecido con la clave
"books:id: topic"
y elimine la clave "libros: id:topic"
El conjunto de ID.
Elimine el conjunto de ID del ID del tema que se va a eliminar. y elimine la identificación de la lista "topic:list".
Exploración n.º 5: Regreso a casa
Esto concluye nuestra exploración de Redis, revisemos el contenido de la bolsa de viaje. p>
Aprendimos sobre los tipos de datos en Redis y los comandos, así como algunas otras cosas interesantes. También hay algunas historias inolvidables:
El problema de las claves primarias únicas de incremento automático. se resuelve ejecutando el comando INCR en datos de cadena
Usando la clave significativa: "usuario:nombre de usuario:id" para manejar escenarios de inicio de sesión de usuario
Realice asociaciones de muchos a muchos entre datos a través de colecciones
¡Finalmente, el viaje de Redis ha llegado a su fin! Espero no haberte avergonzado. Finalmente, quiero dejarte un mensaje: ¡Diviértete escribiendo software libre!