[{"data":1,"prerenderedAt":342},["ShallowReactive",2],{"post-\u002Fsubresource-integrity-taghelper-using-asp-net-core-part-2\u002F":3},{"id":4,"title":5,"author":6,"body":7,"comments":273,"date":318,"dateModified":319,"description":320,"extension":321,"headings":322,"heroImage":329,"meta":330,"path":25,"permalink":25,"published":72,"stem":331,"tags":332,"timeToRead":341},"posts\u002Fposts\u002F2016\u002Fsubresource-integrity-taghelper-using-asp-net-core-part-2\u002Findex.md","Subresource Integrity TagHelper Using ASP.NET Core - Part 2","Muhammad Rehan Saeed",{"type":8,"value":9,"toc":270},"minimark",[10,26,52,73,76,79,102,105,112,120,123,126,160,171,182,193,207,218,221,224,232,243,246,266],[11,12,13,21],"ol",{},[14,15,16],"li",{},[17,18,20],"a",{"href":19},"\u002Fsubresource-integrity-taghelper-using-asp-net-core\u002F","Subresource Integrity TagHelper Using ASP.NET Core - Part 1",[14,22,23],{},[17,24,5],{"href":25},"\u002Fsubresource-integrity-taghelper-using-asp-net-core-part-2\u002F",[27,28,29,30,39,40,45,46,51],"p",{},"Last week I wrote part one of a blog post discussing a Subresource Integrity (SRI) tag helper I wrote for ASP.NET Core. It turns out the post was featured on the ASP.NET Community Standup and discussed at length by ",[17,31,38],{"href":32,"rel":33,"target":37},"http:\u002F\u002Ftwitter.com\u002Fshanselman",[34,35,36],"nofollow","noopener","noreferrer","_blank","Scott Hanselman",", ",[17,41,44],{"href":42,"rel":43,"target":37},"http:\u002F\u002Ftwitter.com\u002Fdamianedwards",[34,35,36],"Damian Edwards"," and ",[17,47,50],{"href":48,"rel":49,"target":37},"http:\u002F\u002Ftwitter.com\u002Fjongalloway",[34,35,36],"Jon Galloway",". Here is the discussion:",[53,54,57,58],"div",{"className":55},[56],"youtube-embed","\n    ",[53,59,61,62,57],{"style":60},"width: 100%; margin: 0 auto;","\n        ",[53,63,65,66,61],{"style":64},"position: relative; padding-bottom: 56.25%; padding-top: 25px; height: 0;","\n            ",[67,68,65],"iframe",{"style":69,"src":70,"allow":71,"allowFullScreen":72},"position: absolute; top: 0; left: 0; width: 100%; height: 100%;","https:\u002F\u002Fwww.youtube-nocookie.com\u002Fembed\u002FMu2jol8EmVo","autoplay; encrypted-media",true,[27,74,75],{},"The overall impression from the standup was that the SRI tag helper I wrote was a good first step but there was more work to be done. It was however, still more secure than \"the rest of the internet\" according to Jon Galloway. The main issue raised during the standup was that the first call made to get the resource could retrieve a version of it that was compromised.",[27,77,78],{},"My initial thinking was that you could check the files at deployment time when the tag helper first runs. Then the tag helper would have calculated the hash and cached it without any expiration time, so you are good from then on. In hindsight checking the files on every deployment is not great for the developer.",[80,81,83,101],"h1",{"id":82},"the-2nd-iteration",[17,84,87],{"href":85,"aria-hidden":86},"#the-2nd-iteration","true",[88,89,95],"svg",{"xmlns":90,"xmlns:xlink":91,"viewBox":92,"version":93,"width":94,"height":94,"aria-hidden":86},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","http:\u002F\u002Fwww.w3.org\u002F1999\u002Fxlink","0 0 16 16","1.1",22,[96,97],"path",{"fill":98,"fill-rule":99,"d":100},"currentColor","evenodd","M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z","The 2nd Iteration",[27,103,104],{},"So for the next iteration I have added a new alternative source attribute, basically a local file from which the SRI is calculated. Now the tag helper looks like this when in use:",[106,107],"pre",{"className":108,"language":109,"meta":110,"style":110,"html":111},"language-html shiki shiki-themes light-plus monokai","html","","\u003Cspan class=\"line\">\u003Cspan class=\"sNflI\">&lt;\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"https:\u002F\u002Fajax.googleapis.com\u002Fajax\u002Flibs\u002Fjquery\u002F2.2.0\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-subresource-integrity-src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"~\u002Fjs\u002Fjquery.min.js\"\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;\n\u003C\u002Fspan>\u003C\u002Fspan>",[27,113,114,115,119],{},"You can also customize the hashing algorithm used in your SRI. You can choose between SHA256, SHA384 and SHA512, by default the tag helper uses the most secure option SHA512 which seems to be supported by all browsers. Should you choose to use a different hashing algorithm or even use more than one algorithm, you can set the ",[116,117,118],"code",{},"asp-subresource-integrity-hash-algorithms"," attribute which is just a flagged enumeration (Note that I am using ASP.NET Core RC2 syntax, where the name of the enumeration can be omitted):",[106,121],{"className":108,"language":109,"meta":110,"style":110,"html":122},"\u003Cspan class=\"line\">\u003Cspan class=\"sNflI\">&lt;\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"https:\u002F\u002Fajax.googleapis.com\u002Fajax\u002Flibs\u002Fjquery\u002F2.2.0\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-subresource-integrity-src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"~\u002Fjs\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-subresource-integrity-hash-algorithms\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"SHA256 | SHA384 | SHA512\"\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;\n\u003C\u002Fspan>\u003C\u002Fspan>",[27,124,125],{},"What is it doing behind the scenes?",[11,127,128,131,134,144,157],{},[14,129,130],{},"Reads the local file specified using the asp-subresource-integrity-src  attribute.",[14,132,133],{},"Calculates a SHA512 hash (or your custom selection) for the file.",[14,135,136,137,45,140,143],{},"Adds the ",[116,138,139],{},"integrity",[116,141,142],{},"crossorigin"," attributes to the script tag.",[14,145,146,147,150,151,156],{},"Adds the hash value to the distributed cache (",[116,148,149],{},"IDistributedCache",") built in to ASP.NET Core with no expiry date. If you are using a distributed cache like ",[17,152,155],{"href":153,"rel":154,"target":37},"http:\u002F\u002Fredis.io\u002F",[34,35,36],"Redis"," (Which you should for the pure speed of it) then the hash will be remembered.",[14,158,159],{},"The next time the page loads, the hash is retrieved from the cache, so there is very little performance impact of this tag helper.",[80,161,163,170],{"id":162},"microsoft-cdn-still-broken-for-sri",[17,164,166],{"href":165,"aria-hidden":86},"#microsoft-cdn-still-broken-for-sri",[88,167,168],{"xmlns":90,"xmlns:xlink":91,"viewBox":92,"version":93,"width":94,"height":94,"aria-hidden":86},[96,169],{"fill":98,"fill-rule":99,"d":100},"Microsoft CDN Still Broken for SRI",[27,172,173,174,177,178,181],{},"In my last post I noted that SRI requires that the resource has a valid ",[116,175,176],{},"Access-Control-Allow-Origin"," HTTP header (usually with a ",[116,179,180],{},"*"," value). Microsoft's CDN does not supply this header for all it's resources. I did reach out to Microsoft to see if this could be fixed. I've not heard back yet. I would imagine that with a CDN of that size, fixing this issue is a non-trivial thing so it might take time but I'll do some more chasing.",[80,183,185,192],{"id":184},"browser-extensions-and-sri",[17,186,188],{"href":187,"aria-hidden":86},"#browser-extensions-and-sri",[88,189,190],{"xmlns":90,"xmlns:xlink":91,"viewBox":92,"version":93,"width":94,"height":94,"aria-hidden":86},[96,191],{"fill":98,"fill-rule":99,"d":100},"Browser Extensions and SRI",[27,194,195,196,199,200,203,204,206],{},"Last week, I noted that leaving out the scheme in the URL for your CDN resource e.g. ",[116,197,198],{},"\u002F\u002Fexample.com\u002Fjquery.js"," caused Firefox to error and fail to load the resource completely and I recommended that you always include the ",[116,201,202],{},"https:\u002F\u002F"," scheme. It turns out that this was not Firefox causing the issue at all but a Firefox browser extension. I've yet to figure out which one yet as I have quite a few installed (most of them security related because I'm paranoid) but it's probably an extension called HTTPS Everywhere which attempts to use HTTPS if it is available. To be on the safe side and avoid this problem, always specify the ",[116,205,202],{}," scheme.",[80,208,210,217],{"id":209},"cdn-fallbacks",[17,211,213],{"href":212,"aria-hidden":86},"#cdn-fallbacks",[88,214,215],{"xmlns":90,"xmlns:xlink":91,"viewBox":92,"version":93,"width":94,"height":94,"aria-hidden":86},[96,216],{"fill":98,"fill-rule":99,"d":100},"CDN Fallbacks",[27,219,220],{},"So what happens when a CDN script is maliciously edited or (much more likely) you messed up and your local copy of the CDN script is different from the one in the CDN? Well, this is where CDN script fallbacks come in. There is already a tag helper provided by ASP.NET Core that does this:",[106,222],{"className":108,"language":109,"meta":110,"style":110,"html":223},"\u003Cspan class=\"line\">\u003Cspan class=\"sNflI\">&lt;\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"https:\u002F\u002Fajax.googleapis.com\u002Fajax\u002Flibs\u002Fjquery\u002F2.2.0\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-subresource-integrity-src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"~\u002Fjs\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-fallback-src\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"~\u002Fjs\u002Fjquery.min.js\"\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan class=\"snDo4\">  asp-fallback-test\u003C\u002Fspan>\u003Cspan class=\"sfK3G\">=\u003C\u002Fspan>\u003Cspan class=\"squEy\">\"window.jQuery\"\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"sjbfc\">script\u003C\u002Fspan>\u003Cspan class=\"sNflI\">&gt;\n\u003C\u002Fspan>\u003C\u002Fspan>",[27,225,226,227,231],{},"I should also mention that although the fallback tag helper is cool and very simple to use, it adds inline script which is not compatible with the ",[17,228,230],{"href":229},"\u002Fcontent-security-policy-for-asp-net-mvc\u002F","Content Security Policy (CSP)"," HTTP header. If you care about security and you probably do if you are reading this, that means using the fallback tag helper is not possible. I myself prefer to move all my fallback checks to a separate JavaScript file.",[80,233,235,242],{"id":234},"where-can-i-get-it",[17,236,238],{"href":237,"aria-hidden":86},"#where-can-i-get-it",[88,239,240],{"xmlns":90,"xmlns:xlink":91,"viewBox":92,"version":93,"width":94,"height":94,"aria-hidden":86},[96,241],{"fill":98,"fill-rule":99,"d":100},"Where Can I Get It?",[27,244,245],{},"This tag helper is available in a few ways:",[11,247,248,257],{},[14,249,250,251,256],{},"The ",[17,252,255],{"href":253,"rel":254,"target":37},"https:\u002F\u002Fwww.nuget.org\u002Fpackages\u002FBoxed.AspNetCore.TagHelpers\u002F",[34,35,36],".NET Boxed Boxed.AspNetCore.TagHelpers"," NuGet package.",[14,258,259,260,265],{},"Check out source code in the ",[17,261,264],{"href":262,"rel":263,"target":37},"https:\u002F\u002Fgithub.com\u002FDotnet-Boxed\u002FFramework",[34,35,36],".NET Boxed Framework"," GitHub repository.",[267,268,269],"style",{},"html pre.shiki code .sNflI, html code.shiki .sNflI{--shiki-default:#800000;--shiki-dark:#F8F8F2}html pre.shiki code .sjbfc, html code.shiki .sjbfc{--shiki-default:#800000;--shiki-dark:#F92672}html pre.shiki code .snDo4, html code.shiki .snDo4{--shiki-default:#E50000;--shiki-dark:#A6E22E}html pre.shiki code .sfK3G, html code.shiki .sfK3G{--shiki-default:#000000FF;--shiki-dark:#F8F8F2}html pre.shiki code .squEy, html code.shiki .squEy{--shiki-default:#0000FF;--shiki-dark:#E6DB74}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":110,"searchDepth":271,"depth":271,"links":272},2,[],{"issue":274,"comments":278},{"number":275,"title":276,"html_url":277},118,"[Comment] Subresource Integrity TagHelper Using ASP.NET Core - Part 2","https:\u002F\u002Fgithub.com\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002F118",[279,291,299,310],{"id":280,"html_url":281,"body_html":282,"created_at":283,"user":284,"reactions":288},627276987,"https:\u002F\u002Fgithub.com\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002F118#issuecomment-627276987","\n\u003Cp>\u003Ca target=\"_blank\" rel=\"nofollow noopener noreferrer\" href=\"https:\u002F\u002Fcamo.githubusercontent.com\u002Fb84381a789673f65540ebb7595d8a8f0bf19f60cd2bdfa5fc473488ccffdd1d8\u002F68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f30323465333136643530663963366434613930306564353730356530303839643f733d393626643d6d6d26723d67\">\u003Cimg alt=\"coder1\" height=\"40\" width=\"40\" src=\"https:\u002F\u002Fcamo.githubusercontent.com\u002Fb84381a789673f65540ebb7595d8a8f0bf19f60cd2bdfa5fc473488ccffdd1d8\u002F68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f30323465333136643530663963366434613930306564353730356530303839643f733d393626643d6d6d26723d67\" \u002F>\u003C\u002Fa> \u003Cstrong>coder1\u003C\u002Fstrong> commented on \u003Cstrong>2016-03-14 15:26:09\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>How can this concept be applies to check the integrity of drop down list values?\u003C\u002Fp>","2020-05-12T11:15:29Z",{"login":285,"avatar_url":286,"html_url":287},"RehanSaeed","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F2270364?v=4","https:\u002F\u002Fgithub.com\u002FRehanSaeed",{"url":289,"total_count":290,"+1":290,"-1":290,"laugh":290,"hooray":290,"confused":290,"heart":290,"rocket":290,"eyes":290},"https:\u002F\u002Fapi.github.com\u002Frepos\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002Fcomments\u002F627276987\u002Freactions",0,{"id":292,"html_url":293,"body_html":294,"created_at":295,"user":296,"reactions":297},627277034,"https:\u002F\u002Fgithub.com\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002F118#issuecomment-627277034","\n\u003Cp>\u003Ca target=\"_blank\" rel=\"nofollow noopener noreferrer\" href=\"https:\u002F\u002Fcamo.githubusercontent.com\u002F8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca\u002F68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67\">\u003Cimg alt=\"Muhammad Rehan Saeed\" height=\"40\" width=\"40\" src=\"https:\u002F\u002Fcamo.githubusercontent.com\u002F8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca\u002F68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67\" \u002F>\u003C\u002Fa> \u003Cstrong>\u003Ca rel=\"nofollow noopener noreferrer\" target=\"_blank\" href=\"https:\u002F\u002Frehansaeed.com\u002F\">Muhammad Rehan Saeed\u003C\u002Fa>\u003C\u002Fstrong> commented on \u003Cstrong>2016-03-15 08:28:41\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>How can this concept be applies to check the integrity of drop down list values?\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>That is not it's purpose. SRI is intended to ensure the integrity of link and script tags only for now and later on, the integrity of other resources coming from external resources.\u003C\u002Fp>","2020-05-12T11:15:37Z",{"login":285,"avatar_url":286,"html_url":287},{"url":298,"total_count":290,"+1":290,"-1":290,"laugh":290,"hooray":290,"confused":290,"heart":290,"rocket":290,"eyes":290},"https:\u002F\u002Fapi.github.com\u002Frepos\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002Fcomments\u002F627277034\u002Freactions",{"id":300,"html_url":301,"body_html":302,"created_at":303,"user":304,"reactions":308},1057630500,"https:\u002F\u002Fgithub.com\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002F118#issuecomment-1057630500","\u003Cp>Just so your aware, the website you link to in this blog article links to a porn site!\u003Cbr \u002F>\nsritest.io\u003C\u002Fp>","2022-03-03T03:29:54Z",{"login":305,"avatar_url":306,"html_url":307},"djorchard","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6267434?v=4","https:\u002F\u002Fgithub.com\u002Fdjorchard",{"url":309,"total_count":290,"+1":290,"-1":290,"laugh":290,"hooray":290,"confused":290,"heart":290,"rocket":290,"eyes":290},"https:\u002F\u002Fapi.github.com\u002Frepos\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002Fcomments\u002F1057630500\u002Freactions",{"id":311,"html_url":312,"body_html":313,"created_at":314,"user":315,"reactions":316},1057795953,"https:\u002F\u002Fgithub.com\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002F118#issuecomment-1057795953","\u003Cblockquote>\n\u003Cp>Just so your aware, the website you link to in this blog article links to a porn site! sritest.io\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>I'm so sorry! It looks like the author of that site must have given up the domain since I wrote this post. I've now removed the offending link.\u003C\u002Fp>","2022-03-03T08:26:47Z",{"login":285,"avatar_url":286,"html_url":287},{"url":317,"total_count":290,"+1":290,"-1":290,"laugh":290,"hooray":290,"confused":290,"heart":290,"rocket":290,"eyes":290},"https:\u002F\u002Fapi.github.com\u002Frepos\u002FRehanSaeed\u002Frehansaeed.github.io\u002Fissues\u002Fcomments\u002F1057795953\u002Freactions","2016-03-12T00:00:00+00:00",null,"Use an ASP.NET Core TagHelper to implement Subresource Integrity (SRI) to ensure that external resources have not been tampered with. With is part 2.","md",[323,325,326,327,328],{"depth":324,"value":101},1,{"depth":324,"value":170},{"depth":324,"value":192},{"depth":324,"value":217},{"depth":324,"value":242},"\u002Fimages\u002Fhero\u002FMake-Security-Easy-1366x768.png",{},"posts\u002F2016\u002Fsubresource-integrity-taghelper-using-asp-net-core-part-2\u002Findex",[333,334,335,336,337,338,339,340,44,50],".NET","ASP.NET Community Standup","ASP.NET Core","ASP.NET MVC",".NET Boxed","C#","Content Delivery Network (CDN)","Cryptography",4,1792876122197]