1 00:00:01,199 --> 00:00:21,690 Bueno, pues efectivamente, esto es feo, ¿verdad? Que tan fácilmente podamos extraer toda la información de una base de datos, pues es feo. 2 00:00:22,989 --> 00:00:34,210 Vale, entonces, este tipo de sentencias hay que usarlas con limitaciones. En ciertos contextos son las más rápidas, porque el acceso a una base de datos muchas veces es el cuello de botella de una aplicación. 3 00:00:34,210 --> 00:00:37,689 Entonces lo del tiempo de acceso no es una tontería 4 00:00:37,689 --> 00:00:39,570 Y estas sentencias son las más rápidas 5 00:00:39,570 --> 00:00:40,590 Pero tienen este problema 6 00:00:40,590 --> 00:00:44,869 Entonces tenemos la posibilidad de hacer este método 7 00:00:44,869 --> 00:00:50,170 Sin que nadie pueda hacer esta inyección SQL de aquí 8 00:00:50,170 --> 00:00:52,390 Entonces vamos a hacer este método 9 00:00:52,390 --> 00:00:53,990 Pero con una versión ya segura 10 00:00:53,990 --> 00:01:08,939 Pongo aquí versión segura 11 00:01:08,939 --> 00:01:14,609 Versión segura 12 00:01:14,609 --> 00:01:15,709 Vale, de este método 13 00:01:15,709 --> 00:01:19,689 Bueno, pues la conexión es igualita 14 00:01:19,689 --> 00:01:21,650 la misma, pero ahora nuestra 15 00:01:21,650 --> 00:01:23,689 sentencia no va a ser de tipo statement 16 00:01:23,689 --> 00:01:25,829 ¿vale? 17 00:01:26,189 --> 00:01:27,810 entonces, como va a ser más larga 18 00:01:27,810 --> 00:01:29,349 vamos a quitarla del 19 00:01:29,349 --> 00:01:31,730 de este de aquí 20 00:01:31,730 --> 00:01:34,069 para no hacer un try con recursos tan grandote 21 00:01:34,069 --> 00:01:37,530 la quito de aquí 22 00:01:37,530 --> 00:01:39,909 entonces nuestra sentencia ahora va a ser 23 00:01:39,909 --> 00:01:40,489 del tipo 24 00:01:40,489 --> 00:01:42,129 prepared 25 00:01:42,129 --> 00:01:46,969 prepared 26 00:01:46,969 --> 00:01:48,769 statement 27 00:01:48,769 --> 00:01:53,269 que también se crea a partir de la 28 00:01:53,269 --> 00:01:55,430 conexión, pero en lugar de con 29 00:01:55,430 --> 00:01:57,370 createStatement, se crea con 30 00:01:57,370 --> 00:01:57,930 prepare 31 00:01:57,930 --> 00:02:02,010 prepareStatement 32 00:02:02,010 --> 00:02:02,769 está 33 00:02:02,769 --> 00:02:11,599 aquí, y aquí 34 00:02:11,599 --> 00:02:13,780 con esto 35 00:02:13,780 --> 00:02:16,060 estamos precompilando 36 00:02:16,060 --> 00:02:17,539 una primera sentencia 37 00:02:17,539 --> 00:02:19,879 ¿vale? precompilando una primera 38 00:02:19,879 --> 00:02:21,319 sentencia que todavía no se está ejecutando 39 00:02:21,319 --> 00:02:23,819 aquí le damos el SQL 40 00:02:23,819 --> 00:02:24,819 que queremos hacer 41 00:02:24,819 --> 00:02:27,460 el SQL que queremos hacer, ¿cuál es? 42 00:02:27,979 --> 00:02:29,099 queremos hacer este 43 00:02:29,099 --> 00:02:32,039 select asterisco 44 00:02:32,039 --> 00:02:33,139 from 45 00:02:33,139 --> 00:02:36,500 personas 46 00:02:36,500 --> 00:02:37,900 minúscula 47 00:02:37,900 --> 00:02:38,860 que queda más bonito 48 00:02:38,860 --> 00:02:41,900 personas 49 00:02:41,900 --> 00:02:43,780 where 50 00:02:43,780 --> 00:02:45,539 nombre 51 00:02:45,539 --> 00:02:48,039 igual y aquí era donde venía 52 00:02:48,039 --> 00:02:48,539 el problema 53 00:02:48,539 --> 00:02:52,199 que yo aquí directamente concatenaba 54 00:02:52,199 --> 00:02:54,039 con lo que me habían mandado desde fuera 55 00:02:54,039 --> 00:02:55,120 concatenaba tal cual 56 00:02:55,120 --> 00:02:57,439 pues aquí no concateno con nada 57 00:02:57,439 --> 00:02:58,819 aquí pongo una interrogación 58 00:02:58,819 --> 00:03:04,960 y digo, oye, yo voy a ejecutar una sentencia 59 00:03:04,960 --> 00:03:06,620 de esta estructura 60 00:03:06,620 --> 00:03:11,419 y aquí va a entrar algo 61 00:03:11,419 --> 00:03:14,680 que tiene que ser un parámetro válido para esto de aquí 62 00:03:14,680 --> 00:03:17,740 entonces, te estoy avisando de que esto es un select 63 00:03:17,740 --> 00:03:20,580 un select con un único parámetro 64 00:03:20,580 --> 00:03:24,819 o sea, aquí no puedes luego añadirme un or 65 00:03:24,819 --> 00:03:26,680 ni un script, ni nada 66 00:03:26,680 --> 00:03:31,060 con esto estamos diciendo, aquí solamente vas a poder añadir 67 00:03:31,060 --> 00:03:32,659 un parámetro para nombre 68 00:03:32,659 --> 00:03:35,039 y el resultado va a ser 69 00:03:35,039 --> 00:03:37,120 una select con una búsqueda 70 00:03:37,120 --> 00:03:38,360 por un único parámetro 71 00:03:38,360 --> 00:03:41,099 aquí no cabe 72 00:03:41,099 --> 00:03:42,340 ni luego un or después 73 00:03:42,340 --> 00:03:44,080 ni luego un script, no cabe nada 74 00:03:44,080 --> 00:03:46,759 en esta sentencia solo va a caber un select 75 00:03:46,759 --> 00:03:48,020 con un único parámetro 76 00:03:48,020 --> 00:03:50,219 con el valor que sea 77 00:03:50,219 --> 00:03:53,039 entonces estamos dándole un aviso de que eso es lo único 78 00:03:53,039 --> 00:03:53,919 que se va a poder hacer 79 00:03:53,919 --> 00:03:55,800 ahora ya 80 00:03:55,800 --> 00:03:59,039 esto por ahora ya lo modificaremos 81 00:03:59,039 --> 00:04:05,199 verificaremos. Ahora le damos los parámetros, le decimos, oye tú, sentencia que te estoy 82 00:04:05,199 --> 00:04:17,050 preparando, la primera interrogación que hay, sustituyela, como es un string, pongo 83 00:04:17,050 --> 00:04:23,829 setString, la primera interrogación que hay, sustituyela con lo que yo te diga. Empezando 84 00:04:23,829 --> 00:04:30,629 desde el 1. Si esta SQL, esta sentencia 85 00:04:30,629 --> 00:04:34,230 tuviera más interrogaciones, porque yo busco por más 86 00:04:34,230 --> 00:04:38,250 where nombre, and, edad, no sé qué, si tuviera más interrogaciones 87 00:04:38,250 --> 00:04:42,569 pues las iría fijando todas. Set string, 1 nombre 88 00:04:42,569 --> 00:04:44,889 set int, 2 edad, lo que fuera. 89 00:04:46,670 --> 00:04:50,470 Pero con esta estructura ya estoy diciendo exactamente lo único 90 00:04:50,470 --> 00:04:54,550 que se va a poder ejecutar. Exactamente esto. Cualquier otra 91 00:04:54,550 --> 00:04:56,569 cosa, que vaya aquí 92 00:04:56,569 --> 00:04:58,410 dentro, que no sea exactamente 93 00:04:58,410 --> 00:05:00,089 un valor de parámetro para esto, 94 00:05:01,069 --> 00:05:02,810 pues eso ya no lo va a ejecutar. 95 00:05:03,970 --> 00:05:04,410 Entonces, 96 00:05:04,550 --> 00:05:06,509 ahora ya falta ejecutarlo. Vale, pues para 97 00:05:06,509 --> 00:05:08,290 ejecutarlo, con hacer el execute query, 98 00:05:08,389 --> 00:05:09,949 ya no hay que darle nada, porque ya está hecho, 99 00:05:10,990 --> 00:05:12,089 ya estaría ejecutado. 100 00:05:13,629 --> 00:05:13,949 PS. 101 00:05:16,329 --> 00:05:16,850 Ya está. 102 00:05:18,230 --> 00:05:20,050 Ahora aquí ya es imposible hacer 103 00:05:20,050 --> 00:05:21,170 la inyección. 104 00:05:24,069 --> 00:05:26,290 100%. Podemos probarlo. 105 00:05:29,500 --> 00:05:30,379 Entonces, la clave 106 00:05:30,379 --> 00:05:32,519 en lugar de una statement normal 107 00:05:32,519 --> 00:05:34,720 hacer una prepare de statement 108 00:05:34,720 --> 00:05:36,639 que lo primero 109 00:05:36,639 --> 00:05:38,560 que hace es decir, oye, este es 110 00:05:38,560 --> 00:05:40,480 el tipo de SQL que vamos a hacer 111 00:05:40,480 --> 00:05:40,980 este 112 00:05:40,980 --> 00:05:44,860 una select con un parámetro 113 00:05:44,860 --> 00:05:46,579 de búsqueda con 114 00:05:46,579 --> 00:05:50,399 este valor, con lo cual aquí 115 00:05:50,399 --> 00:05:52,360 solo se admiten cosas 116 00:05:52,360 --> 00:05:53,939 que sean valores para nombre 117 00:05:53,939 --> 00:05:56,560 es imposible 118 00:05:56,560 --> 00:05:58,259 a partir de aquí que me aparezca 119 00:05:58,259 --> 00:06:00,360 una concatenación con cosas que no sean valores 120 00:06:00,360 --> 00:06:02,120 para nombre porque ya está avisada 121 00:06:02,120 --> 00:06:03,839 el prepara statement de que solo puede ser eso 122 00:06:03,839 --> 00:06:06,180 una vez que ya está este avisado 123 00:06:06,180 --> 00:06:07,980 con sus interrogaciones se van fijando 124 00:06:07,980 --> 00:06:10,139 una por una, en nuestro caso solo hay una 125 00:06:10,139 --> 00:06:12,279 que fijar, pues ya está fijada 126 00:06:12,279 --> 00:06:14,160 y ahora ya ejecutamos 127 00:06:14,160 --> 00:06:14,579 la query 128 00:06:14,579 --> 00:06:16,519 la ejecutamos 129 00:06:16,519 --> 00:06:20,279 y una vez que tengo los registros procedo exactamente 130 00:06:20,279 --> 00:06:27,589 igual, entonces ahora 131 00:06:27,589 --> 00:06:29,709 si nosotros 132 00:06:29,709 --> 00:06:31,129 volvemos a intentar 133 00:06:31,129 --> 00:06:35,689 voy a cambiar en el main 134 00:06:35,689 --> 00:06:37,790 para que ahora llame al 2 135 00:06:37,790 --> 00:06:38,589 al que es seguro 136 00:06:38,589 --> 00:06:41,970 que era getPersonasByNombre 137 00:06:41,970 --> 00:06:42,430 2 138 00:06:42,430 --> 00:06:44,970 cambiamos a la versión 2 139 00:06:44,970 --> 00:06:47,129 cambiamos a la versión 2 140 00:06:47,129 --> 00:06:49,670 recupera personas por nombre 141 00:06:49,670 --> 00:06:51,850 vamos a darle 142 00:06:51,850 --> 00:06:53,850 esta, que era la peligrosa 143 00:06:53,850 --> 00:06:56,490 no me saca nada 144 00:06:56,490 --> 00:06:57,790 porque entonces 145 00:06:57,790 --> 00:06:59,910 ahora ya si, lo que busca es una persona 146 00:06:59,910 --> 00:07:00,750 que se llame así 147 00:07:00,750 --> 00:07:02,930 no hay ninguna persona que se llame así 148 00:07:02,930 --> 00:07:04,850 con lo cual no recupera 149 00:07:04,850 --> 00:07:08,870 Vale, ahora ya, no, esto es solamente el parámetro nombre, eso es. 150 00:07:10,389 --> 00:07:12,050 Entonces, no lo hay, pues no lo recupero. 151 00:07:17,399 --> 00:07:19,160 Vale, entonces este tipo de sentencia, 152 00:07:19,879 --> 00:07:23,639 este tipo de sentencia es más larga de hacer, 153 00:07:24,100 --> 00:07:26,120 porque hay que ir fijando las interrogaciones, 154 00:07:26,839 --> 00:07:28,199 pero lógicamente es más segura. 155 00:07:28,199 --> 00:07:52,069 claro, imagínate, vamos a hacer 156 00:07:52,069 --> 00:07:53,589 para que tenga varios, un método 157 00:07:53,589 --> 00:07:55,610 que devuelva 158 00:07:55,610 --> 00:08:00,149 todas las 159 00:08:00,149 --> 00:08:02,209 personas cuyo nombre 160 00:08:02,209 --> 00:08:04,089 empieza 161 00:08:04,089 --> 00:08:04,829 por 162 00:08:04,829 --> 00:08:07,810 A y son mayores de edad 163 00:08:07,810 --> 00:08:08,410 por ejemplo 164 00:08:08,410 --> 00:08:11,610 a ver, public 165 00:08:11,610 --> 00:08:13,129 static 166 00:08:13,129 --> 00:08:16,639 get personas 167 00:08:16,639 --> 00:08:21,100 mayores edad 168 00:08:21,100 --> 00:08:23,339 by inicial 169 00:08:23,339 --> 00:08:27,889 venga, le damos una inicial 170 00:08:27,889 --> 00:08:40,399 que me devuelva 171 00:08:40,399 --> 00:08:42,440 todas las personas con esa inicial 172 00:08:42,440 --> 00:08:44,019 mayores de edad 173 00:08:44,019 --> 00:08:48,110 vale, vamos a copiar 174 00:08:48,110 --> 00:08:49,370 esto y lo 175 00:08:49,370 --> 00:08:51,429 retocamos 176 00:08:51,429 --> 00:09:00,789 vale, mi array list de personas 177 00:09:00,789 --> 00:09:02,809 ahora, tengo que construir el SQL 178 00:09:02,809 --> 00:09:04,909 entonces, vosotros aquí sois los 179 00:09:04,909 --> 00:09:05,850 expertos en SQL 180 00:09:05,850 --> 00:09:08,590 ¿cómo se pone la condición 181 00:09:08,590 --> 00:09:10,490 de que un nombre 182 00:09:10,490 --> 00:09:12,269 un campo 183 00:09:12,269 --> 00:09:14,129 de marchar empiece por un carácter? 184 00:09:15,690 --> 00:09:16,529 vale, vamos a 185 00:09:16,529 --> 00:09:17,509 comprobarlo aquí 186 00:09:17,509 --> 00:09:19,830 ver nombre, like 187 00:09:19,830 --> 00:09:23,629 el carácter 188 00:09:23,629 --> 00:09:24,649 ¿qué? 189 00:09:24,649 --> 00:09:25,110 ¿me has dicho? 190 00:09:26,129 --> 00:09:27,970 no, pero era comilla por sentación 191 00:09:27,970 --> 00:09:28,730 ¿comilla? 192 00:09:29,169 --> 00:09:30,690 sí, comilla simple 193 00:09:30,690 --> 00:09:34,320 bueno, debería ser 194 00:09:34,320 --> 00:09:35,539 no, a por sentación 195 00:09:35,539 --> 00:09:36,799 Ah, porcentaje 196 00:09:36,799 --> 00:09:38,480 Sí, porque 197 00:09:38,480 --> 00:09:39,820 Porcentaje significa 198 00:09:39,820 --> 00:09:42,679 Cero o más o varios 199 00:09:42,679 --> 00:09:45,279 Vale, sí, lo que pasa es que este ejemplo no nos gusta 200 00:09:45,279 --> 00:09:45,860 Porque 201 00:09:45,860 --> 00:09:49,679 Para hacer con este 202 00:09:49,679 --> 00:09:50,980 Hay que 203 00:09:50,980 --> 00:09:53,559 Habría que hacer otra sentencia 204 00:09:53,559 --> 00:09:54,659 Habría que fijarlo 205 00:09:54,659 --> 00:09:57,320 Entonces, no, no nos 206 00:09:57,320 --> 00:09:59,620 Vamos a complicar 207 00:09:59,620 --> 00:10:01,679 Ahora, porque tendríamos que incorporar otro tipo de sentencia 208 00:10:01,679 --> 00:10:04,019 Entonces, que se llamen de una manera 209 00:10:04,019 --> 00:10:05,259 Siendo mayores de edad 210 00:10:05,259 --> 00:10:06,879 Todos los pepitos mayores de edad 211 00:10:06,879 --> 00:10:08,059 Así no nos complicamos 212 00:10:08,059 --> 00:10:13,399 Vale, get personas mayores de edad 213 00:10:13,399 --> 00:10:14,259 Por nombre 214 00:10:14,259 --> 00:10:15,960 Vale 215 00:10:15,960 --> 00:10:18,259 Entonces ahora 216 00:10:18,259 --> 00:10:21,179 Añadiríamos where nombre igual a este 217 00:10:21,179 --> 00:10:22,679 And, ahora ya sí 218 00:10:22,679 --> 00:10:23,240 And 219 00:10:23,240 --> 00:10:28,679 Edad igual a otra interrogación 220 00:10:28,679 --> 00:10:29,320 ¿Verdad? 221 00:10:31,399 --> 00:10:32,779 No, mayor o igual, perdón 222 00:10:32,779 --> 00:10:36,039 Que el mayor o igual en SQL es ese 223 00:10:36,039 --> 00:10:36,179 ¿No? 224 00:10:37,480 --> 00:10:39,750 ¿Es ese? 225 00:10:40,230 --> 00:10:41,309 El mayor o igual en SQL 226 00:10:41,309 --> 00:10:47,860 vale, entonces 227 00:10:47,860 --> 00:10:50,200 ahora yo, mi nombre es este 228 00:10:50,200 --> 00:10:52,240 y me fijo la otra interrogación 229 00:10:52,240 --> 00:10:54,659 ps.setint 230 00:10:54,659 --> 00:10:56,620 la interrogación 231 00:10:56,620 --> 00:10:58,120 2 igual a 232 00:10:58,120 --> 00:11:03,659 18, ahora 233 00:11:03,659 --> 00:11:05,879 este me sacará solo los mayores 234 00:11:05,879 --> 00:11:07,159 de edad que se llaman así 235 00:11:07,159 --> 00:11:09,519 anedadman 236 00:11:09,519 --> 00:11:11,720 dos interrogaciones, fijo los dos valores 237 00:11:11,720 --> 00:11:15,759 y me saca esas personas 238 00:11:15,759 --> 00:11:16,980 entonces si pongo 239 00:11:16,980 --> 00:11:22,840 Voy a poner otra Ana 240 00:11:22,840 --> 00:11:25,179 Pero más pequeña 241 00:11:25,179 --> 00:11:27,279 Con 12 años 242 00:11:27,279 --> 00:11:31,960 Ahora tengo dos que se llaman Ana 243 00:11:31,960 --> 00:11:33,600 Pero solo una es mayor de edad 244 00:11:33,600 --> 00:11:35,799 Vamos a 245 00:11:35,799 --> 00:11:45,669 Comprobarlo 246 00:11:45,669 --> 00:11:51,289 Personas 247 00:11:51,289 --> 00:11:53,370 Mayores de edad 248 00:11:53,370 --> 00:11:59,019 De edad por nombre 249 00:11:59,019 --> 00:12:01,399 El caso 4 250 00:12:01,399 --> 00:12:02,639 Sería como el 251 00:12:02,639 --> 00:12:04,059 3 252 00:12:04,059 --> 00:12:05,860 Pero cambiando el método 253 00:12:05,860 --> 00:12:09,539 El caso 4 254 00:12:09,539 --> 00:12:10,539 Un segundito 255 00:12:10,539 --> 00:12:16,440 Operaciones de personas mayores de edad 256 00:12:16,440 --> 00:12:22,279 Vale, ya tengo el caso 4 257 00:12:22,279 --> 00:12:26,100 Que son solo las mayores de edad 258 00:12:26,100 --> 00:12:33,000 4 259 00:12:33,000 --> 00:12:39,019 Pues efectivamente solo me ha sacado la que es mayor de edad de las dos 260 00:13:00,000 --> 00:13:01,000 Este mismo 261 00:13:01,000 --> 00:13:08,639 No, no, no, esta es la interrogación 262 00:13:08,639 --> 00:13:10,019 que ya se asume que va a ser un string 263 00:13:10,019 --> 00:13:11,700 hay que poner la interrogación 264 00:13:11,700 --> 00:13:12,899 hay que ponerla entre comillas y nada 265 00:13:12,899 --> 00:13:16,159 Claro, aquí el string 266 00:13:16,159 --> 00:13:17,299 ya marca que es un string 267 00:13:17,299 --> 00:13:23,529 Vale