{"id":95,"date":"2020-09-08T14:23:00","date_gmt":"2020-09-08T13:23:00","guid":{"rendered":"https:\/\/www.julianmejio.com\/blog\/?p=95"},"modified":"2020-09-11T16:39:12","modified_gmt":"2020-09-11T15:39:12","slug":"configurar-correctamente-la-integridad-de-los-subrecursos-sri-con-el-cdn-de-cloudflare","status":"publish","type":"post","link":"https:\/\/www.julianmejio.com\/blog\/2020\/09\/08\/configurar-correctamente-la-integridad-de-los-subrecursos-sri-con-el-cdn-de-cloudflare\/","title":{"rendered":"Configurar correctamente la integridad de los subrecursos (SRI) con el CDN de Cloudflare"},"content":{"rendered":"\n<p>El d\u00eda de ayer publiqu\u00e9 la nueva versi\u00f3n de mi sitio web, pero antes de publicarlo tuve problemas con el CDN \u2013<em>Content Delivery Network<\/em>, o Red de distribuci\u00f3n de contenidos en espa\u00f1ol\u2013 de <a rel=\"noreferrer noopener\" href=\"https:\/\/www.cloudflare.com\/\" target=\"_blank\">Cloudflare<\/a>: los subrecursos CSS y javascript de la p\u00e1gina estaban disponibles, pero por alguna raz\u00f3n el navegador no los cargaba.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Subresource Integrity (SRI), o la integridad de los subrecursos<\/h2>\n\n\n\n<p>El SRI es una caracter\u00edstica de seguridad que garantiza que los subrecursos de una p\u00e1gina web \u2013archivos CSS y JS principalmente\u2013 no hayan sido manipulados.<\/p>\n\n\n\n<p>Esta caracter\u00edstica es importante, ya que hoy en d\u00eda la mayor\u00eda de sitios web optan por usar una red de distribuci\u00f3n de contenidos, y se estima un crecimiento en el uso de esta tecnolog\u00edas en los pr\u00f3ximos a\u00f1os. Para entender la importancia del SRI hay que entender primero lo que es un CDN: es una red global que permite cargar las p\u00e1ginas web m\u00e1s r\u00e1pido. Servicios como Netflix, Youtube, Deezer y esencialmente todos los servicios de steaming lo usan. La estrategia principal de un CDN es copiar un v\u00eddeo subido en alg\u00fan pa\u00eds de latinoam\u00e9rica, y pegarlo en varios puntos estrat\u00e9gicos de las diferentes regiones del mundo. As\u00ed, si alguien en Espa\u00f1a quiere ver el v\u00eddeo, podr\u00e1 hacerlo rapidamente, ya que el CDN se ha encargado de hacer la transferencia de manera previa desde latinoam\u00e9rica a Europa.<\/p>\n\n\n\n<p>Este copia y pega conlleva una situaci\u00f3n de seguridad: el contenido, ya sea una imagen, v\u00eddeo o incluso los archivos CSS y JS de una p\u00e1gina web, son distribuidos a trav\u00e9s de una red que el due\u00f1o del sitio no controla y tampoco tiene acceso. Al usar un CDN est\u00e1s cediendo la distribuci\u00f3n a una red externa que no puedes controlar. T\u00fa entregas el contenido original y esperas que este contenido sea el mismo para todos los usuarios, pero hay actores malintencionados dentro de estas redes que buscan la manera de manipular dichos contenidos para sus propios beneficios.<\/p>\n\n\n\n<p>En octubre de 2019 un grupo de ciberseguridad alem\u00e1n logr\u00f3 efectuar un ataque que afect\u00f3 a redes CDN. Los sitios afectados mostraban p\u00e1ginas de error en vez del contenido leg\u00edtimo a los usuarios finales. Recalco que el grupo de ciberseguridad en ning\u00fan momento obtuvo el control del servidor donde se alojaba el sitio web ni la red CDN. Esto quiere decir que cualquier persona con conocimiento suficiente puede manipular los contenidos distribuidos por un CDN sin siquiera tener un usuario ni una contrase\u00f1a. Esto es preocupante si no se toman las medidas de seguridad correspondientes.<\/p>\n\n\n\n<p>Aqu\u00ed entra el SRI: es una peque\u00f1a cadena de texto que se usa para verificar que el contenido que entreg\u00f3 el CDN al usuario final sea el que se distribuy\u00f3 originalmente.<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-html\" data-lang=\"HTML\"><code>&lt;!-- Subrecurso sin SRI --&gt;\n&lt;script src=&quot;mi-app.js&quot;&gt;&lt;\/script&gt;\n\n&lt;!-- Subrecurso con SRI --&gt;\n&lt;script src=&quot;mi-app.js&quot; integrity=&quot;sha256-rqwup5jPgTd\u2026&quot;&gt;&lt;\/script&gt;<\/code><\/pre><\/div>\n\n\n\n<p>La cadena de texto SRI es el resultado de una funci\u00f3n hash criptogr\u00e1fica aplicada al contenido del subrecurso. Esta cadena de texto se almacena y distribuye originalmente a trav\u00e9s de un atributo <code>integrity<\/code> en los elementos HTML. Al final de la cadena de distribuci\u00f3n, el navegador web vuelve a calcular el hash del contenido entregado por el CDN, y la cadena de texto resultante debe coincidir con la original para garantizar que es el mismo contenido. Si la cadena difiere, el contenido fue manipulado y el navegador, por seguridad, no lo cargar\u00e1.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"696\" data-attachment-id=\"101\" data-permalink=\"https:\/\/www.julianmejio.com\/blog\/2020\/09\/08\/configurar-correctamente-la-integridad-de-los-subrecursos-sri-con-el-cdn-de-cloudflare\/captura-de-pantalla-2020-09-08-a-las-10-51-03\/\" data-orig-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03.png\" data-orig-size=\"1356,922\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Captura-de-Pantalla-2020-09-08-a-las-10.51.03\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-300x204.png\" data-large-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-1024x696.png\" src=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-1024x696.png\" alt=\"\" class=\"wp-image-101\" srcset=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-1024x696.png 1024w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-300x204.png 300w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-768x522.png 768w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03-1200x816.png 1200w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-10.51.03.png 1356w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Mensaje del navegador en donde informa del bloqueo de un subrecurso debido a que su hash es inv\u00e1lido.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Optimizaci\u00f3n de recursos est\u00e1ticos en Cloudflare<\/h2>\n\n\n\n<p>Cloudflare ofrece la opci\u00f3n de minimizar el tama\u00f1o de los subrecursos para acelerar la carga de las p\u00e1ginas web: entre m\u00e1s peque\u00f1o sea un archivo, menos tiempo tomar\u00e1 su descarga. La minificaci\u00f3n reduce el tama\u00f1o de los subrecursos sin alterar su funcionalidad, esto quiere decir que podemos obtener la misma funci\u00f3n que hemos programado en menos espacio. Esto es \u00fatil cuando las dependencias pesan mucho o cuando prescindimos de la optimizaci\u00f3n de nuestros propios scripts. Funciona muy bien, sin embargo hay un problema cuando hemos implementado SRI: el hash de nuestro contenido original y no minificado va a variar con respecto al contenido optimizado y minificado por Cloudflare. Aunque la funci\u00f3n es la misma, el hash es diferente, ya que la funci\u00f3n criptogr\u00e1fica no lo calcula en relaci\u00f3n a la funcionalidad del sript, sino al contenido. Al minificar el recurso, su contenido cambia, y por lo tanto el hash tambi\u00e9n. El resultado final es el bloqueo del subrecurso por el navegador.<\/p>\n\n\n\n<p>Por ejemplo: tenemos un recurso no optimizado en javascript:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-js\" data-file=\"example.js\" data-lang=\"JavaScript\"><code>var array = [];\nfor (var i = 0; i &lt; 20; i++) {\n  array[i] = i;\n}<\/code><\/pre><\/div>\n\n\n\n<p>Este recurso pesa 65 bytes. Como la funci\u00f3n hash se aplica a nivel de bytes, tenemos que su contenido representado en bytes es el siguiente:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">0000000 76 61 72 20 61 72 72 61 79 20 3d 20 5b 5d 3b 0a\n0000010 66 6f 72 20 28 76 61 72 20 69 20 3d 20 30 3b 20\n0000020 69 20 3c 20 32 30 3b 20 69 2b 2b 29 20 7b 0a 20\n0000030 20 61 72 72 61 79 5b 69 5d 20 3d 20 69 3b 0a 7d\n0000040 0a\n0000041<\/pre>\n\n\n\n<p>Y para esta cadena, el valor hash de una funci\u00f3n tipo HMAC GOST es <code>2647098b<\/code>.<\/p>\n\n\n\n<p>Al minificar el mismo recurso podr\u00edamos obtener algo similar a esto:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-js\" data-file=\"example.min.js\" data-lang=\"JavaScript\"><code>for(var a=[i=0];i&lt;20;a[i]=i++);<\/code><\/pre><\/div>\n\n\n\n<p>En la pr\u00e1ctica realiza la misma funci\u00f3n, pero su peso es de 32 bytes. La optimizaci\u00f3n ha reducido su peso a la mitad, y tambi\u00e9n ha cambiado el algoritmo a una m\u00e1s eficiente.<\/p>\n\n\n\n<p>Su contenido representado en bytes ha cambiado:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">0000000 66 6f 72 28 76 61 72 20 61 3d 5b 69 3d 30 5d 3b\n0000010 69 3c 32 30 3b 61 5b 69 5d 3d 69 2b 2b 29 3b 0a\n0000020<\/pre>\n\n\n\n<p>Y por lo tanto, el valor de la funci\u00f3n hash HMAC GOST ahora es <code>81193395<\/code>.<\/p>\n\n\n\n<p>El valor original <em>2647098b<\/em> es diferente a <em>81193395<\/em>. Ha habido una alteraci\u00f3n y por lo tanto el navegador bloquear\u00e1 el contenido por seguridad.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Solucionar el problema de SRI con la optimizaci\u00f3n de Cloudflare<\/h2>\n\n\n\n<p>Lamentablemente, ambas caracter\u00edsticas son incompatibles entre s\u00ed. Depender de caracter\u00edsticas de optimizaci\u00f3n de lado del CDN para manejar la seguridad del sitio tambi\u00e9n va en contra del principio b\u00e1sico del SRI. Yo solucion\u00e9 este problema al desactivar la minificaci\u00f3n de recursos CSS y JS de Cloudflare.<\/p>\n\n\n\n<p>Lo primero que hice fue identificar el problema. Las herramientas de desarrollador del navegador me dieron la primera pista. Ahora, mi contenido cargaba correctamente en mi entorno local y apenas sub\u00eda los cambios al servidor tambi\u00e9n cargaban correctamente, pero luego de unos minutos el contenido dejaba de cargar y volv\u00eda a aparecer el error. Esto se debe a que la minificaci\u00f3n de Cloudflare tarda unos minutos antes de aplicarse completamente. Durante ese transcurso de tiempo, el contenido cargaba. Una vez el contenido era alterado por la minificaci\u00f3n, el contenido dejaba de cargar.<\/p>\n\n\n\n<p>La soluci\u00f3n f\u00e1cil es desactivar el RSI de los recursos, pero as\u00ed perder\u00eda completamente el control de los subrecursos y ser\u00eda vulnerable a diferentes tipos de ataques. Casi nunca es recomendable desactivar una caracter\u00edstica de seguridad, y menos en un ambiente tan p\u00fablico como lo son los CDN e internet.<\/p>\n\n\n\n<p>Tambi\u00e9n hab\u00eda muchos lugares en donde se recomendaba a\u00f1adir el atributo <code>crossorigin=\"anonymous\"<\/code> al subrecurso. Esto no funciona para solucionar problemas relacionados con SRI, pero la gente los confunde ya que los s\u00edntomas son similares. Este atributo modifica el comportamiento de otra caracter\u00edstica de seguridad llamada CORS, y no tiene ning\u00fan impacto en SRI.<\/p>\n\n\n\n<p>CORS tampoco se aplicaba a mi problema ya que el dominio del CDN es igual al dominio que invoca la carga. Esto debido a que el CDN de Cloudflare funciona con el mismo nombre de dominio. Vale la pena aclarar que, si se usa otro CDN como Cloudfront, el nombre de dominio cambia y por lo tanto se este atributo s\u00ed funcionar\u00eda.<\/p>\n\n\n\n<p>As\u00ed que la soluci\u00f3n era clara: desactivar la minificaci\u00f3n. No toqu\u00e9 la configuraci\u00f3n de Cloudflare en mucho tiempo, por lo que no recordaba si hab\u00eda una opci\u00f3n similar, pero por experiencia sab\u00eda que los CDN ten\u00edan opciones y estrategias adem\u00e1s de la distribuci\u00f3n geogr\u00e1fica para optimizar los recursos. Encontr\u00e9 la opci\u00f3n Minificador autom\u00e1tico bajo la opci\u00f3n Speed. Esta opci\u00f3n permite minificar los recursos javascript, CSS y HTML. Como los subrecursos m\u00edos eran solo javascript y CSS, solo deshabilit\u00e9 esas dos opciones. De esa forma Cloudflare no alterar\u00eda mis recursos, y de esta forma los valores hash de mis recursos no cambiar\u00edan y podr\u00edan ser cargados de nuevo por el navegador.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"262\" data-attachment-id=\"105\" data-permalink=\"https:\/\/www.julianmejio.com\/blog\/2020\/09\/08\/configurar-correctamente-la-integridad-de-los-subrecursos-sri-con-el-cdn-de-cloudflare\/captura-de-pantalla-2020-09-08-a-las-14-17-40\/\" data-orig-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40.png\" data-orig-size=\"2082,532\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Captura-de-Pantalla-2020-09-08-a-las-14.17.40\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-300x77.png\" data-large-file=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1024x262.png\" src=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1024x262.png\" alt=\"\" class=\"wp-image-105\" srcset=\"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1024x262.png 1024w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-300x77.png 300w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-768x196.png 768w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1536x392.png 1536w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-2048x523.png 2048w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1200x307.png 1200w, https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/Captura-de-Pantalla-2020-09-08-a-las-14.17.40-1980x506.png 1980w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Opci\u00f3n <em>Minificador autom\u00e1tico<\/em> de Cloudflare con las opciones <em>JavaScript<\/em> y <em>CSS<\/em> deshabilitadas.<\/figcaption><\/figure>\n\n\n\n<p>Luego de hacer este cambio purgu\u00e9 toda la cach\u00e9 de Cloudflare, esper\u00e9 un pr de minutos, y el sitio web empez\u00f3 a cargar correctamente los subrecursos.<\/p>\n\n\n\n<p>Ahora, ya que la optimizaci\u00f3n est\u00e1 deshabilitada en el CDN, es necesario ocuparnos de la optimizaci\u00f3n desde nuestro lado. Gestores de paquetes y dependencias como Webpack hacen esto automaticamente, por lo que tambi\u00e9n es recomendable usar herramientas de este tipo para administrar los c\u00f3digos CSS y javascript \u2013y dem\u00e1s recursos\u2013.<\/p>\n\n\n\n<p>Si no se cuenta con Webpack, tambi\u00e9n se pueden usar herramientas como <a href=\"https:\/\/skalman.github.io\/UglifyJS-online\/\" target=\"_blank\" rel=\"noreferrer noopener\">uglifyjs<\/a> y optimizar manualmente los recursos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuraci\u00f3n en Webpack<\/h2>\n\n\n\n<p>Webpack por defecto habilita el algoritmo hash SHA-384, pero siempre es bueno tener un algoritmo retrocompatible disponible, como lo es SHA-256.<\/p>\n\n\n\n<p>En nuestro archivo de configuraci\u00f3n de Webpack, buscamos la llamada a la funci\u00f3n <code>enablentegrityHashes()<\/code> y pasamos en el segundo argumento un arreglo con los dos algoritmos hash que deseamos que Webpack calcule para nuestros subrecursos:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-js\" data-file=\"webpack.config.js\" data-lang=\"JavaScript\"><code>.enableIntegrityHashes(true, [&#39;sha256&#39;, &#39;sha384&#39;])<\/code><\/pre><\/div>\n\n\n\n<p>Ahora los valores de integridad tendr\u00e1n ambos valores hash:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-json\" data-file=\"entrypoints.json\" data-lang=\"JSON\"><code>{\n  &quot;integrity&quot;: {\n    &quot;\/mi-app.js&quot;: &quot;sha256-tPpWfL8S\u2026 sha384-\/Zh0hTCg\u2026&quot;\n  }\n}<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusi\u00f3n<\/h2>\n\n\n\n<p>SRI protege de ataques como XSS o envenenamiento de la cach\u00e9. Es muy recomendado usarlo cuando se opta por distribuir los subrecursos a trav\u00e9s de un CDN.<\/p>\n\n\n\n<p>SRI es incompatible por definici\u00f3n por posprocesamientos de recursos en el CDN, por lo que debe deshabilitarse, y preocuparse de la optimizaci\u00f3n de manera temprana.<\/p>\n\n\n\n<p>Al usar un CDN en donde los recursos se distribuyan por otro nombre de dominio, se debe configurar CORS correctamente tambi\u00e9n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Referencias<\/h2>\n\n\n\n<p>MDN contributors (2020, mayo 28). Subresource Integrity. <em>MDN web docs<\/em>. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Security\/Subresource_Integrity\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Security\/Subresource_Integrity<\/a><\/p>\n\n\n\n<p>T4 Labs Inc (2020, abril 30). CDN Market Share, <em>T4<\/em>. <a href=\"https:\/\/www.t4.ai\/industry\/cdn-market-share\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.t4.ai\/industry\/cdn-market-share<\/a><\/p>\n\n\n\n<p>Khandelwal, S. (2019, octubre 23). New Cache Poisoning Attack Lets Attackers Target CDN Protected Sites. <em>The Hacker News<\/em>. <a href=\"https:\/\/thehackernews.com\/2019\/10\/cdn-cache-poisoning-dos-attack.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/thehackernews.com\/2019\/10\/cdn-cache-poisoning-dos-attack.html<\/a><\/p>\n\n\n\n<p>Wikipedia (2020, julio 27). Minification (programming). <em>Wikipedia<\/em>. <a href=\"https:\/\/en.wikipedia.org\/wiki\/Minification_(programming)\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/en.wikipedia.org\/wiki\/Minification_(programming)<\/a><\/p>\n\n\n\n<p>Colaboradores de MDN (2019, marzo 23). Atributos de configuraci\u00f3n CORS. <em>MDN web docs<\/em>. <a href=\"https:\/\/developer.mozilla.org\/es\/docs\/Web\/HTML\/Atributos_de_configuracion_CORS\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/developer.mozilla.org\/es\/docs\/Web\/HTML\/Atributos_de_configuracion_CORS<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>El SRI es una caracter\u00edstica de seguridad que garantiza que los subrecursos de una p\u00e1gina web \u2013archivos CSS y JS principalmente\u2013 no hayan sido manipulados.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[8],"tags":[28,27,26,25],"class_list":["post-95","post","type-post","status-publish","format-standard","hentry","category-desarrollo-de-software","tag-cdn","tag-cloudflare","tag-cors","tag-sri"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/95","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/comments?post=95"}],"version-history":[{"count":9,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/95\/revisions"}],"predecessor-version":[{"id":146,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/95\/revisions\/146"}],"wp:attachment":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/media?parent=95"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/categories?post=95"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/tags?post=95"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}