Video details

NG-BE 2021 - Philippe De Ryck - Securing Angular with Trusted Types

Philippe De Ryck helps developers protect companies through better web security. His Ph.D. in web security from KU Leuven lies at the basis of his exceptional knowledge of the security landscape. As the founder of Pragmatic Web Security, Philippe delivers security training and security consulting to companies worldwide. His online course platform allows anyone to learn complex security topics at their own pace. Philippe is a Google Developer Expert and an Auth0 Ambassador for his community contributions on the security of web applications and APIs.


We'll go to our next speaker. I personally think he doesn't need any introduction, but for those who don't know who that is, Philip is top notch security expert with a PhD from Kleven, so he's like a real scientist. But Covet was also real and Philip Unfortunately couldn't join in person out of precaution. So we will see his talk on the screen here and still can learn about those famous trusted types. So Internet for the win and we can start the recording. Hi everyone, I hope you're having a great time at Ngpe. I really wish I could be there because I really love the conference and it's an absolutely amazing place to be. Unfortunately, the circumstances are what they are, but nonetheless, I'm here to talk about securing Angular applications with trusted types. I'm filiperek image source. None on error alert. Oh my God. Well, not really though. My name is not that complicated, but you can kind of recognize what's going on here. If you've ever looked at cross site scripting, you can see that this is a textbook cross site scripting attack factor. If I, as a user of an application can change my name to this and have somebody else sees that name in a web application, it can look something like that. The browser will pick up that image tag, the browser will try to load an image source non image that doesn't exist, and instead the browser executes that unerroro event handler. And that's cross site scripting and popping up an alert dialogue is not really that dangerous, though. I mean, it's annoying, but that's about it. However, once you have a cross site scripting vulnerability that can pop up an alert on the victim's machine, the attacker can do whatever they want. Cross site scripting is really dangerous and give the attacker the control over the application. They can change the page, they can prompt the user for information, they can present a fake login form, send request to a backend, steal data from the browser, and so on, and so on. Just to give you a couple of examples of how serious cross site scripting is, here's a child monitoring application with XSS vulnerabilities that could result in leaking the location of your child, which is kind of counterintuitive if you're using a child monitoring application for security leaks to the location of your kids. So yeah, that's problem number one at Facebook. They also know what cross site scripting means. Here's an example of a Dom based cross site scripting vulnerability at Facebook, which cost them 25,000 USD in bug bounty awards. That's not the only vulnerability. There's plenty of other stories here's. One from Oculus, also a Facebook product which results in a Facebook account takeover because of cross site scripting. And to show you how important it really is, that 300 USD bug bounty definitely tells a big story. Cross site scripting is absolutely dangerous, and we need to stop cross site scripting attacks from happening in our applications. The good news is, in this talk I'm going to talk about trusted types and how trusted types has the ability to eradicate domestic cross site scripting vulnerabilities in your applications. That's a big promise. I'm going to fulfill that promise, and by the end of this session, you'll know what trusted types can do for you and how to use that in your Angular applications before we do that a small word about myself. I am Philip Drake and I'm from Belgium, and usually I am at Ngbe as one of the speakers on security. That's what I do. I help developers with security. I do that with indepth onsite training training on security practices in Angular applications and so on. But I also do online courses and security consulting on advanced topics such as API Security, OAuth and Openended Connect. I run my own company called Pragmatic Web Security, and I'm also a Google developer expert at an Altzero Ambassador, which are recognitions from these companies with their Dev RL programs for people contributing to the community with conference talks like this one. But enough about me. Let's talk about this guy fledge image source NUM. What happens when we put this data into the page using an Angular template? That's a good question, right? Well, in this case, Angular will use the double curly braces to database to bind this variable into the page, and Angular is going to automatically escape that value. Angular knows what's going on here. Angler knows like how long you're going to put data inside an HTML element. We should make sure that the browser doesn't get confused about any of that. So you know what? I'm going to auto escape that data. If there is a dangerous character in there, like the open brackets for the image tag, we're going to translate that to M present Lt semicolon, because that will tell the browser show me that's a character instead of interpret that as a code character. That's essentially how we protect against cross site scripting in applications, and that's an awesome defense. However, that doesn't work very well if you want to render HTML. What if we want to allow the user to render a pretty document like this CK editor document? If we escape that, or if Angular escapes that, we would see all the HTML elements, but we wouldn't see the nicely rendered HTML. So that wouldn't make us very happy. That's why Angular has an inner HTML attribute we can use to bind HTML into the page. And that inner HTML is between square brackets, and that means something. Those square brackets mean it's an Angular property that we're using, not the browser's interhtml property that is part of Dom APIs. And that's really important because that property is sanitized before the data ends up in the Dom. So basically, Angular will take that data will be like, we'll see if this is safe. It analyzes the data, it removes things for which it knows that are unsafe, or it only keeps the things it knows are safe and puts the rest into the page. And that process is called sanitization. And if you look at what's happening under the hood, it looks something like this. We have our application code on top, and we have the browser at the bottom, and our data goes through our Angular application, which applies escaping when you use data binding or sanitization when you use inner HTML. And once that is done, that data ends up in the page, usually through a dangerous sync such as inner HTML. And that sync will call the HTML parser, which will in turn process the data and render our CK editor documents. That's pretty awesome. So far, so good. However, what happens if there's a code pad in your application that sidesteps that escaping or sanitization step? Well, in that case, that Codepad reaches the dangerous sync, which will trigger the HTML parser, which will find a payload in there. Image source, non error through something, pick up the JavaScript code, throw it over to the JavaScript engine, which will parse and interpret the JavaScript and execute that code in your application context. That's essentially how a Dom based cross site scripting attack works in practice. Now, why would such a code path exists? Like why on Earth would you bind something into the page without going through Angular sanitizer? Does that even happen in practice? Well, I wish I could say no, not at all, but unfortunately that's not the case. This actually does happen in practice, and there's a few common ways in which this can happen. The first one is bypass security trusthtml. That's a legitimate Angular function, which does exactly what you think it does. It bypasses the security mechanism of Angular. So if you use this function on a piece of untrusted data, you're basically marking it as safe telling angler when you put it in the page, don't touch it, it's going to be fine, which in this case it really isn't. So this is a cross that scripting vulnerability in your application. This junction is intended to be used on either static code snippets or on code snippets that you know are safe to begin with, not on data like this. That doesn't sound too bad, right? Well, it doesn't, but that's not all. There's a second way that you can sidestep Angular, and that's by leaving the Angular environment, you can do that by using native Dom elements through Elementref. And this piece of code should scare you. Whenever you use an Element ref, you should be absolutely scared, because what you're doing is you're basically reaching out of angler's safe environment and you're going out into the wild nature of JavaScript applications running in the browser. It's absolutely bonkers security device to do that. What does this allow you to do? Well, once you have that element, you can grab the native Dom elements by calling native elements on that Element ref, and that gives you raw access to the Dom APIs. That now means you can call inner HTML, which you shouldn't do directly with any value. And that means if you do that, you have a massive cross site scripting vulnerability in your application. And the worst of this example is that angler, which has done all they can to protect you can't cover this because you're outside of the Angular environment. Absolutely horrible piece of code. Never, ever do this. There's a second way this can happen as well. You can use the Renderer two API in Angular to set that inner HTML property on that. If elements different piece of code, but the same effect, input value will be assigned to inner HTML, causing a crossside scripting vulnerability. So the first takeaway here. The first takeaway is that cross site scripting in Angular is difficult, but not impossible. Angular does a whole lot of things to help you prevent cross site scripting vulnerabilities in your applications, but there are still ways that they can occur. It's not a given that your Angular application is free of excesses. And that brings us to trusted types. What is trusted types, and how can it help you protect your applications? Back to our overview example here. How do we enable trusted types? That's step one. Well, you enable trusted types by setting a content security policy. Content security policy is this elaborate security policy with a whole bunch of features. And this feature enables trusted types. Specifically, you send that as a response header on your index HTML when you load or bootstrap your Angular application. Once that is set, the browser will change its internal behavior. The browser will observe this policy and be like, Trust the type. Say, I'm going to respond by making my sinks. Trusted Typesy s. No more dangerous things, but trusted type syncs, what does that that mean? Means whenever you assign something to inner HTML in the Dom and that something is not a trusted type of text, if you assign data to that inner HTML sync, the browser will simply refuse to honor that. The browser will be like, Absolutely not. I am not going to do that. That's not a trusted type. That's text based assignments to an HTML thing that will trigger the parser are dangerous. I do not want to do that anymore. That's the effect of trusted types. Trusted types comes from Google. It's a Google technology that has been used internally for a while, and that actually works quite well. And they came up with that because they noticed that their static analysis pipeline, where they analyzed the code for these potential vulnerabilities, couldn't catch them all. In fact, it missed quite a few of them. And we trusted types, they can catch at least 61% of these missed vulnerabilities. So by strengthening the platform in the browser, changing the browser behavior, they can catch these Dom based XSS vulnerabilities and effectively fix them or avoid them. That's pretty awesome. If you ask me. One important side note is that trusted types only applies on text based assignments to a dangerous sync because text based assignments can contain untrusted data which can be transformed into code. And that's potentially dangerous if you create Dom elements directly using the Dom APIs. Trusted types doesn't even apply because there's no parsing going on. This is the by design way to create elements we call the Create Element API. We set an attribute, we set a text content, and we insert it into the page. This does not trigger the browser's HTML parser. It simply tells the browser what to do, and that is considered to be SAFECode. This does not allow the Apache to provide malicious data like a name and transform that into executable code. That's impossible with this code example. That's also an observation that Google made. So here's a second snippet of the trusted types report that was released a while back. And that snippet says like, yeah, in 75% of cases, when trusted types shows an error, we can actually fix the application to write or to create elements in a cleaner way. We can use proper Dom APIs. Awesome. And by applying trusted types, they keep monitoring the applications for vulnerabilities, of course. And by applying trusted types, they have discovered zero additional Dombased XS vulnerabilities. So when they apply trusted types, it really works well to avoid Dombased XSS. That's the power of trusted types. Let that sink in for a minute. Of course, using Dom APIs is fine if you want to create an element yourself. But what do you do when you get this from the user? How the hell do you create that in a safe way? Well, you don't. Basically, this is not how that works. You can't really take a CK editor document as input and transform that into API calls to the Dom. This is where you actually need inner HTML to make that work. So how can we enable inner HTML? We trust the types in Angular. Good question, right? We don't. We don't. Because Angular does this by default. Angular has built in support for trusted types. Awesome. Seriously, since Angular Eleven, they added this in Angular Eleven, it became very useful in Angular Twelve. And it's just enabled, not enabled, supported by default. All you need to do is enable that Angular trusted types mechanism and you're good to go. So how do you do that? Well, you set that content security policy header. You add line two require trusted types for script that enables trusted types. And the third line says trusted types. Angular. It enables the Angular specific policy for trusted types that's it doing. This allows you to use Angular inner HTML, assign a Jquery document. Angular will sanitize that, assign it into the Dom in a safe way, and render the CK editor document. That in my book is pretty awesome. I can hear you thinking. Yes, I can hear you thinking. In the future, because this is prerecorded. I can hear you thinking like how the hell what do we gain here? Because this is the same slide as we saw in the beginning of this presentation. Angular did that by default. So what the hell do we gain by using trusted types? And that's a good question. What we gain is basically the assurance that no data will ever end up in an HTML parser without going through a trusted types policy first. So if somebody makes a mistake, if somebody uses bypass security trust HTML or uses those element refs to get to the Dom APIs directly and assigns data, the browser will simply refuse to do that. The browser will be like no, you have enabled trusted types, and this is not a trusted type piece of data. I am not going to assign it to Interhuman and the problem goes away. So what you gain is basically the assurance that all assignments to inner HTML have to be a trusted type. That assurance is not a strict security mechanism because trusted types doesn't automatically secure your data. It's just a type annotation on a piece of data. So instead of a string, you have to provide a trusted type. And the only way to get a trusted type is by feeding that to a trusted types policy. So what trusted types really does is type checking your data. It says, hold on, this tax has not been passed through a trusted types policy. Are you sure you want to do that? Well, I'm not going to do it. If you want to do that, make it a trusted type first. And that's the security nudge that you need to be like, OK, how do I make it a trusted type? I can pass it through the sanitizer to make it safe, or through a custom trusted types policy. That's also an option, but in Angular you typically don't need that pretty great if you ask me. There's one caveat. I really hate talking about this, but I kind of have no choice because you're going to run into that anyway. If you use the bypass security trust HTML function, Angular is not going to allow to do that by default. You have to enable that explicitly when using trusted types, and you do that by adding the Angular hashtag unsafe bypass policy as well. Now this is dangerous because if you do that, you re enable the use of bypass security trust HTML. And that means if somebody in your application uses that in an insecure way, you still have a vulnerability. So I strongly recommend against the use of this trusted types configuration. And I also strongly recommend against the use of bypass security trust HTML if you need to use it anyway. You are responsible for making this secure, and you can do that by using either the Angular built in sanitizer yourself or a custom sanitizer such as Dumpurfi. But adding this to your trusted types policy configuration allows the use of bypass security trust HTML, so be careful with that. That brings us to another takeaway. Trusted types avoids unsafe Dom assignments. Basically, by enabling trusted types, we only allow safe assignments in Angular. That means things that have passed through the Angular sanitizer, those are safe and that can be assigned to the Dom. Everything else is not assigned. That's rejected. And that's awesome. You can hear her thinking like, wow, Philip got us all hyped up about trusted types, so how can we start using that? Do browser support that? Well, not really. As in Chrome supports it and the Chromium based browsers, but not Firefox or Safari. And I'm sure you're now looking like a sad Panda. Like, oh wow, I really wanted to use that, but it doesn't seem very useful. That's not necessarily true. Let's make that a happy Panda or a high Panda depends on how you look at the image. By the way, I was totally committed to the sad Panda image, and I tried to find a happy Panda image, but apparently Pendas are never happy. There's literally no image of a happy Panda, so I had to revert to PowerPoint smiley face, which looks absolutely high if you ask me. But that's a different story. No wonder it's happy if it's high. Not sure. Back to trusted types here. Sorry for the interruption. Back to Trusted Types So why doesn't it matter that Firefox doesn't support that? Doesn't it screw over Firefox users? On one hand, yes, but in reality, probably not. Let's take a look at an example here. Chrome Browser Chrome supports trusted types. We can enable trusted types when we're developing our application, and Chrome will enforce that. Whenever you do something like this, which is absolutely not recommended, the browser will be your development browser will be like, what the hell are you doing? No, I'm not going to assign this data to Interhml. Screw you. Big error. And as a developer, you're going to be like, oh yeah, whoops my bad? And you're going to fix that issue and do that the right way, the Angular way, and that way you will have built a more secure application just by having trusted types enabled in development. And you build a secure application, you deploy that and a Firefox user comes around and uses that your Firefox user sees. Well, Firefox sees a trusted types policy if you deploy that in production, and it's like, I don't know what that means. I'll just ignore that. However, the application itself has code like this because you fix that in development, and that means that your application is secure. So even Firefox users, or Safari users, for that matter, benefit from having trusted types enabled in development mode or in production for Chrome. And that's absolutely awesome, by the way. You can take it a step further. If you really want trusted types in enforcement mode in your application, you can use polyfills for nonsupporting browsers. There's a polyfill to enable the trusted types API. And there's a polyfill to enable enforcement mode specifically as well. In general, trusted types improves the security of your code. Trusted types makes your entire application more secure, which benefits all of your users. All right, so what do we have now? We have our Angular application, Angular Resuming Sanitization really well and escaping really well with the curly braces, and we are doing a good job in building secure applications. Awesome. How much of your application code is yours or your colleagues? 2%, maybe 5% and everything else is third party code and dependencies. Actually, this slide doesn't really look right. Maybe it's better if I make that a bit bigger, because third party code and your dependencies are the majority of the code in your application. And what happens if one of these third party libraries or dependencies contains a vulnerability? We've seen that in Bootstrap. For example, Bootstrap had a feature to set tooltips, and they allowed HTML in that tool tip. And that means if somebody is able to insert a button with a tool, tip would transform that data for the tool tip into executable code, triggering cross site scripting vulnerabilities in legitimate applications. And how do you fix that? Well, we can update Bootstrap. Yeah, sure. Good luck with that. Updating it is one thing, and then fixing all of the existing installations by upgrading to the new version, that's going to be a massive challenge. Nobody ever updates their CSS library basically, however, and this is pretty awesome. Trusted types can help here. Trust the types changes the behavior of the browser. That's why I have that line in the middle of my slide to separate the application and the browser, because we trusted types. When Bootstrap tries to assign a tooltip with HTML with inner HTML, the browser is like, Yea, no, nice try, Bootstrap, but no, go away. Thank you very much. And that protects our application. Even when a vulnerability exists in third party code, it also breaks stuff. That's the price we have to pay here. It will break the application because Bootstrap cannot assign that tooltip. But I have an answer on that as well. Trusted types can be used in a default mode. You can specify a default trusted types policy. As you can see on line five in the bottom code snippet, the default policy is what the browser applies whenever you assign a stringbased value to inner HTML. Whenever you assign a piece of text to inner HTML, a browser will be like, hold on, that doesn't look right like, oh, I have a default policy. Okay, let's feed that through the Create HTML function, which takes unsafe data as input and returns save data as output. Or at least that is what it's supposed to do. Browser feeds it through there, gets a savedata as output, and assigns a save data into the Dom. And this piece of code will allow you to fix insecure behavior in bootstrap GS in this case absolutely really powerful. Of course, doing something like this requires support for trusted types so that means in practice if you want to use that default policy in production, you'll have to rely on browser supporting trusted types or you have to load the polyfill yourself. And that brings us to the most important takeaway of this presentation. Trusted types is a browser level security measure. It changes the way the browser behaves, covering your code and other code running in your environment, third party code and dependencies and that is what makes trusted types really powerful. If you want to know a bit more about trusted types and look at some examples, here's a page from Google by the author of Trusted Types, Christopher Coloitz detailing a couple of these scenarios in a lot more useful way to get your hands dirty with trusted types. My advice is to get started with trusted types, even only in development because it's going to result in better and more secure applications. All right, if you want to learn more about security, I have some online security courses as well that you might want to check out. There's one on react security, maybe not relevant for you but also on API security and OAuth and OpenIt connect. And with that I want to thank you for being here. Thank you for listening to me talk. I hope this was useful to help you secure applications and if you have any questions about this feel free to reach out to me on social media and enjoy the rest of the conference. Basically.