Curso MIT "Seguridad de sistemas informáticos". Lección 11: Ur / Lenguaje de programación web, Parte 2

Instituto de Tecnología de Massachusetts. Conferencia Curso # 6.858. "Seguridad de los sistemas informáticos". Nikolai Zeldovich, James Mickens. Año 2014


Computer Systems Security es un curso sobre el desarrollo e implementación de sistemas informáticos seguros. Las conferencias cubren modelos de amenazas, ataques que comprometen la seguridad y técnicas de seguridad basadas en trabajos científicos recientes. Los temas incluyen seguridad del sistema operativo (SO), características, gestión del flujo de información, seguridad del idioma, protocolos de red, seguridad de hardware y seguridad de aplicaciones web.

Lección 1: "Introducción: modelos de amenaza" Parte 1 / Parte 2 / Parte 3
Lección 2: "Control de ataques de hackers" Parte 1 / Parte 2 / Parte 3
Lección 3: “Desbordamientos del búfer: exploits y protección” Parte 1 / Parte 2 / Parte 3
Lección 4: “Separación de privilegios” Parte 1 / Parte 2 / Parte 3
Lección 5: “¿De dónde vienen los sistemas de seguridad?” Parte 1 / Parte 2
Lección 6: “Oportunidades” Parte 1 / Parte 2 / Parte 3
Lección 7: “Sandbox de cliente nativo” Parte 1 / Parte 2 / Parte 3
Lección 8: "Modelo de seguridad de red" Parte 1 / Parte 2 / Parte 3
Lección 9: "Seguridad de aplicaciones web" Parte 1 / Parte 2 / Parte 3
Lección 10: “Ejecución simbólica” Parte 1 / Parte 2 / Parte 3
Lección 11: "Ur / Lenguaje de programación web" Parte 1 / Parte 2 / Parte 3

Un poco más tarde, le contaré sobre solicitudes falsas de sitios cruzados. Creo que las notas explican por qué las secuencias de comandos crossite no funcionan en nuestro caso. La razón es que cada vez que crea una "pieza" de sintaxis, este objeto, árbol y diferentes partes de este árbol no son solo cadenas.



No puede convertir accidentalmente una cadena de usuario en un árbol de estructura, esto no sucede automáticamente, porque es difícil escribir dicho traductor. Pero puede intentar escribir un traductor para Ur / Web. Pronto daré un ejemplo que ayudará a reducir su preocupación por esto. Quiero mostrarle en qué se convierte esta sintaxis en el compilador.

Puede parecer que podríamos agregar comillas dobles alrededor del HTML para que luego podamos volver al mundo normal. Uno puede preguntarse por qué es tan importante omitir comillas dobles, colocando XML en su lugar.

Puede creer que este es el código equivalente para lo que hace. Aquí hay una etiqueta de función en línea que crea el nodo de árbol de un documento HTML. A continuación, coloco los argumentos que expresan el estilo CSS en este nodo. En realidad, aquí no sucede nada, por lo que hay muchas formas diferentes de decir "Ninguno", no requiere ningún atributo.

Luego pongo la etiqueta del cuerpo, esta es otra cosa de la biblioteca estándar. Todas las etiquetas estándar son funciones de primera clase en la biblioteca.



A continuación, necesitamos poner el texto "Hola Mundo" en el cuerpo, por lo que llamamos a la función cdata, donde cdata es la palabra XML para datos de caracteres o simplemente una constante de cadena, y podemos colocar el texto aquí. Esto debería darnos el mismo resultado que antes. A ver si esto funciona.

Ahora volveré a la página. Vemos lo mismo que antes, así que esto es lo mismo que la función al principio.



Esto no es solo construcción de líneas. Esto provoca una serie de operaciones que están diseñadas para que solo le permitan crear HTML válido, y nunca podrán interpretar implícitamente la línea como código en lugar de simplemente colocar contenido en la página que debería estar allí.



Ahora intentaré hacer algo menos complicado, que podría ser una preocupación. Decidamos que estamos realmente felices de ver el mundo, por lo que resaltamos la palabra "hola" en negrita y la compilamos nuevamente.



Verá lo que sucedió en la página: la palabra no se puso en negrita porque el compilador muestra cómo se interpreta el texto en lugar del marcado. Esta es una representación de la sintaxis HTML como una función que construye la sintaxis sin las convenciones de codificación habituales incorporadas. Esta función interpreta todo de la manera que quería escribir, sin pensar en nada de usted mismo.

Por lo tanto, la implementación de cdata hace lo que comúnmente se llama escapar o "escapar". Pero el programador no necesita saber que existe la posibilidad de escapar. Puede considerarlo como un conjunto de funciones convenientes para crear un árbol de objetos que describe la página.

Escuché que quieres ver el HTML que se genera aquí. Bien, eso no será lo más emocionante. Intentaré agrandarlo en la pantalla, pero luego no cabe en una línea.



Estudiante: Dado que está utilizando XHTML, ¿podría usar la ruta para los datos de caracteres cdata en lugar de hacerlo manualmente?

Profesor: Supongo, pero eso requeriría más XML de mí que los que tengo. Había otra buena pregunta sobre las URL de JavaScript. Si permitimos URL de JavaScript, creamos una puerta trasera para interpretar automáticamente las cadenas como programas en tiempo de ejecución. Y eso causa todo tipo de problemas.

Intentemos evitarlo. Volveré, en primer lugar, a la versión abreviada, y haré algunas líneas dentro del cuerpo. Y pongamos un enlace que intentará hacer algo apropiado. Aquí dejamos espacio para mensajes de error.



A continuación, ejecute el compilador y vea cómo funciona.



URL no válida, luego entrada de JavaScript y la frase "pasado para bendecir" o "bendición pasada". Bless está integrado en la función, que es el controlador de acceso que resuelve la URL. De forma predeterminada, las URL no están permitidas, por lo que, por supuesto, esta opción no está permitida. En general, es una mala idea escribir su propia política de URL para poder crear valores que representen las URL de JavaScript. Porque entonces se requerirán todo tipo de garantías, debido a que estas direcciones pueden ser inválidas.

Para aclarar un poco cómo funciona esto, permítanme descomponer este código en una función separada que llama al enlazador que acepta la URL. Por lo tanto, una URL es un tipo, no una cadena. Este es el tipo que denota la URL, que está explícitamente permitido por la política de su aplicación.

Utilizo llaves, como en algunos marcos de plantillas HTML populares, para indicar la inserción de algún código del lenguaje host dentro del HTML que creamos. Y todo esto se hace de tal manera que el tipo se verifica estáticamente. Entonces el sistema verificará: "sí, este es el lugar al que pertenece la URL, y dice que realmente es una URL, por lo que todo está bien".



Y luego puedo organizar explícitamente la llamada de bendición diciendo: "simplemente llamemos a la función de enlace aquí en función de los resultados de la" bendición "de esta URL". Después de eso, deberíamos recibir el mismo mensaje de error que antes.



Desafortunadamente, no puedo ejecutar esto por usted y esperar hasta que falle, pero puedo decir que definitivamente fallará, porque intencionalmente cometí un error de compilación. Esta URL no será aceptada por la política de URL.

Si me perdí esta llamada de bendición, sería un error más grave en el momento de la compilación, porque tiene la cadena y la URL correcta, y son de diferentes tipos.



Hagámoslo más interesante. Voy a abrir un archivo de configuración para esta demostración. Es bastante corto, al menos si nos fijamos en cualquier marco de aplicación web Java. Tienen estos archivos XML gigantes para la configuración, por lo que todo es mucho mejor con nosotros.



Podemos agregar una regla que indique que todo en Wikipedia está permitido, y luego poner la URL de Wikipedia en el cuerpo.



Ahora vaya a la página y haga clic en Haga clic en.



Esto es lo que obtuvimos: no se encontró la dirección de Wikipedia.



Entonces, la idea principal es tener un tipo abstracto de URL, como podría tener un tipo abstracto de tabla hash que codifica variaciones de cómo se ve la tabla hash y evita que el código entre en la matriz de la tabla hash. Podemos hacer lo mismo para la URL. Usando esta función de bendición, el sistema asegura que cada valor de este tipo pase una verificación apropiada en algún momento.

Por ejemplo, con esta política, sabemos que nunca tendremos una URL de JavaScript, por lo que puede tomar con seguridad el valor de la URL y usarla como un enlace. Esto no romperá las abstracciones básicas del lenguaje.

Estudiante: ¿es posible usar JavaScript "puro" insertándolo en la cadena del cuerpo?

Profesor: sí y no. En lugar de JavaScript, incrusta el código Ur / Web que realiza algún tipo de tarea. Ahora escribiré el comando:

return <xml><body onload = {alertLOADED”}> 

Y verá lo que sucedió: el intérprete colocó una ventana en la pantalla con la inscripción "Cargado" - "Cargado".



Intentar interpretar el código JavaScript en forma de cadena como un programa sería un desastre. Verá, podemos poner el código en el mismo lenguaje de programación con el que está trabajando, ya limitado por estas llaves. Y luego se compila automáticamente en JavaScript para ejecutarse en el lado del cliente.

Observo que las versiones más recientes de los navegadores pueden evitar errores de interpretación de caracteres, pero algunos navegadores más antiguos pueden confundir algo. En cualquier caso, todos los elementos de caracteres se interpretarán como UTF-8 si ingresan al documento. Si hay algún problema con una codificación diferente, entonces esta codificación no debe aplicarse aquí.

Estudiante: el compilador verifica si la cadena contiene una URL válida. Pero si calcula una cadena en tiempo de ejecución, ¿bendice verifica en tiempo de ejecución si una cadena dada es válida o no?

Profesor: creemos un formulario para probar esta afirmación y colóquelo aquí. Ingresamos nuestra URL en el cuadro de texto de la URL y luego insertamos el botón de enviar enviar.



Cuando haga clic en él, se llamará a la función de enlace con la escritura de un valor para cada campo en el formulario. En este caso, solo hay un campo llamado "URL", por lo que el vinculador procesará la entrada que contiene la URL como un tipo de cadena. Y luego tratamos de aplicarle la función de bendición y ver si funciona.



Verá un ejemplo de mensajes de error al escribir el tipo incorrecto de URL, una de esas cosas que no tendrá sentido si no está familiarizado con Haskell. Olvidé insertar la función de retorno aquí. Al menos ahora es más como un programa Java. Y también olvidé decir que ahora es una página completa. Por lo tanto, no podemos usar la etiqueta a hasta que estemos dentro de la etiqueta del cuerpo.



Ahora ejecute el compilador, vaya a nuestra página, haga clic en el botón Por favor, haga clic, ingrese alguna dirección inexistente.



Luego hacemos clic en Enviar consulta - "Enviar una solicitud" y recibimos un mensaje de error: la dirección de este tipo no se resuelve.



Si ingresamos la URL correcta como se muestra en la siguiente pantalla y luego hacemos clic en Enviar consulta, no aparecerá ningún mensaje de error.



Creo que la respuesta a su pregunta fue larga y no muy emocionante.

Estudiante: ¿existen condiciones más estrictas para las URL además de la prohibición de usar JavaScript?
Profesor: Actualmente, las restricciones más estrictas son simplemente constantes y prefijos. Pero también puede crear sus propias reglas de prohibición, y funcionarán en el orden en que las escriba.

Estudiante: resulta que si se adhiere a la prohibición de JavaScript, pero coloca un salto de línea en el medio de la palabra "JavaScript", el compilador puede interpretar esto ...

Profesor: sí, eso sería muy malo. Por eso es bueno seguir el enfoque de la lista blanca en lugar de usar el enfoque de la lista negra. Probablemente desee que todas las reglas comiencen con un protocolo específico, como HTTP, y solo permitan lo que se ajuste a su conjunto de protocolos aprobado. Recomiendo hacer eso.

Estudiante: para muchos sitios, puede permitir que los usuarios intercambien enlaces, en cuyo caso debe permitir enlaces en todas partes.

Profesor: puede permitir enlaces si desea que sus usuarios compartan enlaces JavaScript o, no sé, enlaces flash, o lo que esté permitido allí. Verá, puede crear una "lista blanca" de todos los HTTP, HTTPS, URL y, por lo tanto, garantizar el funcionamiento seguro de la mayoría de los sitios. Este enfoque es solo un poco más débil que permitir solo URL específicas. Pero al menos puede eliminar por completo la posibilidad de ejecución automática de una cadena como programa.

Permítame darle un ejemplo de un resumen, que es un ejemplo de un sistema simple de sala de chat presentado en la base de datos. El usuario puede hacer clic en el enlace para ir a la sala y luego enviar un mensaje. Esta es la primera de varias opciones para el esquema.



En primer lugar, notaré que voy a recompilar esto. Y luego, mágicamente, todas las tablas de bases de datos declaradas se agregarán a la base de datos, y podemos comenzar a usar la aplicación. Pero primero necesitamos agregar algunas salas de chat. Entonces, abramos nuestra interfaz a la base de datos de demostración e inserte los valores "uno" y "dos" en la sala de tablas.



Ahora han aparecido aquí.



Ahora entramos en la primera sala de chat y podemos entretenernos todo el día enviando líneas de texto, por ejemplo, una primera línea. Será más interesante intentar enviar HTML, y se procesará de inmediato. Este es un ejemplo de la funcionalidad principal del programa.



Una vez más, veamos rápidamente cómo funciona, así que tenemos estas dos tablas SQL: sala de tabla y mensaje de tabla, que simplemente se declaran en esta primera clase dentro del lenguaje de programación. Y damos un diagrama de cada tabla. Y luego, cuando intentamos acceder a estas tablas, el compilador se asegura de que se acceda a ellas de acuerdo con un prometedor esquema de escritura.



Por lo tanto, tenemos una tabla de habitaciones, donde cada habitación es un registro que consta de un identificador de identificación, que es un número entero, y un título, que es una cadena. Este es el tipo de vista en el que simplemente creamos registros. Acabo de crear algunas salas en la consola SQL. También tenemos una notificación de que cada mensaje pertenece a una sala en particular, la hora en que se creó y el texto que es el contenido del mensaje.
Ahora déjame saltar rápidamente a la función principal.



Ejecutamos una consulta SQL: puede ver un ejemplo de sintaxis SQL integrada en Ur / Web. No quiero entrar en llamadas a funciones a través de esta extensión desde la biblioteca estándar. Será bastante detallado, es suficiente recordar mis palabras sobre el hecho de que la biblioteca estándar tiene métodos para llamar a funciones que son formas válidas de construir una consulta SQL.

Y estas funciones tienen tipos que las hacen imprimir solicitudes para usted, y no solo garantizan que la sintaxis sea válida. Este código simplemente itera sobre todas las líneas que salieron de esta consulta y genera partes del código HTML para cada una de ellas.

En particular, vamos a poner el resultado de la consulta en el campo Título y convertirlo a HTML con una notación que incluya llaves. Los corchetes también indican que esto aún no es una pieza real de HTML, pero conviértalo de una manera estándar. Entonces podemos hacer con cadenas y enteros y todos los datos de otros tipos.

Estudiante: si contuviera HTML malicioso u otra cosa, ¿se filtraría?

Profesor: sí, lo haría. En Ur / Web, puedes pensar que es como construir un árbol. Este es un nodo que representa algún texto. Obviamente, el texto no puede hacer nada.

Estudiante: entonces, si este encabezado estuviera bajo el control del usuario y alguien tuviera una conversación con el encabezado Alerta, ¿no sería JavaScript?

Profesor: no se interpretará automáticamente como JavaScript, HTML o cualquier otra cosa. El programa lo percibirá como texto sin formato.

Entonces, volvamos a nuestra imagen de pantalla. Tenemos este título Título, enmarquémoslo con etiquetas. Y en lugar de href, la forma habitual de enlazar en HTML, usamos el atributo de enlace, que es una especie de pseudoatributo Ur / Web, que toma como argumento no la URL, sino principalmente las expresiones Ur / Web. El punto es que cuando haces clic en este enlace, esta expresión se inicia para crear una nueva página que debería mostrarse.
En este caso, hacemos una llamada a la función de chat, que se define aquí en la siguiente pantalla, esto es lo que es.



No entraré en detalles. Pero tenemos algunas consultas SQL más usando varias funciones de biblioteca estándar para varias formas de usar los resultados solicitados.

Generamos esta página HTML y decimos que está en un chat con dicho título, tenemos un formulario donde el usuario puede ingresar texto. Este es el formulario que utilicé para demostrar cómo funcionaba el programa hace unos minutos. El botón de enviar formulario tiene este atributo Agregar que contiene say, que es el nombre de la función Ur / Web. Por lo tanto, cuando enviamos el formulario, llamamos a esta función.

Ejecutar algunos SQL más inserta nuevas filas en la tabla. Saltamos automáticamente de la ID de la sala de chat a los campos de texto que vinieron aquí desde el formulario, y se ocultan automáticamente según sea necesario. Pero, de nuevo, en Ur / Web, no necesita pensar en "escapar" de la función de esta manera. Porque es solo la sintaxis para construir un árbol, no para una cadena. Por lo tanto, no hay forma de que ocurran cosas extrañas al analizar que no se espera de la forma elegida de interpretar la sintaxis.

Entonces, el hecho de que tengamos un widget en este formulario en forma de GUI gráfica, y este es un campo de texto, el compilador concluye que el registro que resulta de completar el formulario de cuadro de texto debe tener un elemento llamado "texto" de tipo cadena . Esta codificación del formulario y las reglas para escribir en él no están integradas en el lenguaje, sino que se toman de la biblioteca Ur express, que realmente controla estos formularios, determinando los tipos de funciones válidas.
Si no tiene más preguntas sobre esta parte del programa, pasaré al siguiente paso. Voy a usar una forma de forzar la encapsulación de varias partes de una aplicación que admite Ur / Web y que rara vez admite otros idiomas. Voy a tomar esta habitación. Voy a tomar algunas definiciones y ponerlas en un módulo que encapsula algunas de ellas como privadas. En particular, las tablas de la base de datos serán privadas, por lo que nadie podrá acceder directamente a ellas.

Puede acceder a ellos solo mediante el conjunto de métodos que proporcionamos. Un método se ejecuta dentro de una transacción y crea una lista de registros con campos de ID y título para las salas de chat disponibles.

A continuación, solo ampliamos esta operación de chat. Y lo único que hice aquí fue ingresar un nombre para la ID de concepto - ID de tipo. Así que no solo digo que la ID es un número entero, sino que es un tipo nuevo.



La única forma en que el mundo exterior puede comunicarse con el chat es obtener una lista de todas las salas, y la única forma en que el mundo exterior puede usarlo es llamar a la función de chat en él. Digamos que este es un tipo abstracto de tabla hash dentro de la clase de tablas hash, donde se almacenan detalles que explican qué son los ID y cómo se producen internamente, son privados para este módulo, y el código del cliente que llama a este módulo no debe usarlos.

Ahora transferiré toda esta sintaxis hacia abajo y la colocaré dentro del módulo, para que, de forma predeterminada, no quede expuesta al resto del código. A continuación, implemento este método de habitaciones. Ya tenemos la oportunidad de organizar un chat. Pero podemos implementar las salas de una manera más simple utilizando otra función de biblioteca estándar para interpretar la solicitud en el formulario actual.
Simplemente seleccionemos todo de la lista de habitaciones, ordenadas por nombre. Como de costumbre, esta consulta es un tipo de datos validados para nosotros. Y el sistema determina: "OK, esta expresión generará una lista de registros que coinciden con el tipo declarado en la firma de este módulo". Entonces, fuera de este módulo, ningún otro código puede mencionar una tabla de sala o tabla de mensajes.



Por lo tanto, al menos desde el punto de vista de esta aplicación, podemos aplicarle la invariancia requerida. Incluso podemos ocultar secretos dentro del módulo para que no haya problemas de seguridad si cualquier otra parte del código puede obtenerlos.

Estudiante: ¿ podría algún otro código también implementar este método de sala?

Profesor: Esa sería una mesa completamente diferente. En realidad, podemos hacer esto insertando un fragmento de 4 líneas en otro módulo.



Entonces podemos hacer lo que queramos con esta tabla. Lo compilaré, tal vez en 30 segundos, y veremos qué sucede. Pero en realidad esta es una tabla diferente, como si tuvieras el mismo nombre privado, pero para dos clases Java diferentes.

Entonces, asume que dentro de este módulo hay un tipo abstracto llamado room, que contiene el identificador de identificación y el título. Esto no es correcto Chat acepta parámetros de sala como entrada. Cuando llamamos a la función de chat, se llamará a través de la URL. La identificación y el título se pasan fuera de la representación de la URL que llama a la función. Solo necesitamos la ID para implementar esta función. Entonces, cuando llamamos a la función, en realidad llamamos a la URL.
Sería un desperdicio en términos de uso de espacio y sería grosero para el usuario si el encabezado se pasara como un argumento adicional al invocar el chat a través de la URL. ¿Eso tiene sentido? Veamos la barra de URL en esta diapositiva.



El identificador del canal que estamos siguiendo se serializa automáticamente en la URL al final de la línea. Y si transmitimos un registro que contiene la identificación y el título del título, ese título también se serializaría, lo que es al menos un poco ilógico.

54:10

Curso MIT "Seguridad de sistemas informáticos". Lección 11: Ur / Lenguaje de programación web, Parte 3


La versión completa del curso está disponible aquí .

Gracias por quedarte con nosotros. ¿Te gustan nuestros artículos? ¿Quieres ver más materiales interesantes? Apóyenos haciendo un pedido o recomendándolo a sus amigos, un descuento del 30% para los usuarios de Habr en un análogo único de servidores de nivel de entrada que inventamos para usted: toda la verdad sobre VPS (KVM) E5-2650 v4 (6 núcleos) 10GB DDR4 240GB SSD 1Gbps de $ 20 o cómo dividir el servidor? (las opciones están disponibles con RAID1 y RAID10, hasta 24 núcleos y hasta 40GB DDR4).

VPS (KVM) E5-2650 v4 (6 núcleos) 10GB DDR4 240GB SSD 1Gbps hasta diciembre de forma gratuita al pagar por un período de seis meses, puede ordenar aquí .

Dell R730xd 2 veces más barato? ¡Solo tenemos 2 x Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100 TV desde $ 249 en los Países Bajos y los Estados Unidos! Lea sobre Cómo construir un edificio de infraestructura. clase utilizando servidores Dell R730xd E5-2650 v4 que cuestan 9,000 euros por un centavo?

Source: https://habr.com/ru/post/es425999/


All Articles