Attacking the front-end: Modern-day client side security

Introduction to Modern Day Client-Side Security

Kaif Ahsan opens his talk titled 'Attacking the Frontend,' focusing on modern web applications' security, particularly in the context of frameworks like React and Angular. He aims to explore both the security attacks and the development best practices to mitigate these risks.

Digital Transformation and Security Concerns

Ahsan discusses the rapid digital transformation, especially during the COVID era, which led to an increase in online presence and consequently more opportunities for cyber attacks. He emphasizes the evolution of security challenges in modern frameworks.

Code Injection Attacks and Their Persistence

He delves into the persistence of code injection attacks, one of the oldest types of cyber threats, and the inadequacy of handling unexpected data inputs in many applications.

Cross-Site Scripting (XSS) in Modern Frameworks

Ahsan focuses on cross-site scripting (XSS) attacks, particularly how they occur in frameworks like React and Angular. He gives an overview of XSS, its impact, and common scenarios where it takes place.

XSS Vulnerabilities in React Applications

The talk then moves to specific vulnerabilities in React applications, discussing aspects like user-submitted HTML, escape hatches, and handling URLs, which can lead to XSS vulnerabilities.

React Escape Hatches and Safe Practices

Ahsan explains React escape hatches and recommends best practices for safely using React components and avoiding common vulnerabilities.

Code Injection in Angular and Security Measures

He compares React and Angular in the context of code injection, highlighting Angular's superior handling of such attacks and discussing best practices for Angular security.

Cross-Site Request Forgery (CSRF) Attacks

Ahsan discusses CSRF attacks and their potential impact on web applications. He outlines when and how these attacks can happen and the importance of CSRF tokens in preventing them.

Third-Party Dependencies and Security Risks

The presentation shifts to the risks associated with third-party dependencies. Ahsan highlights common attack vectors and the importance of being vigilant about third-party code used in applications.

Conclusion and Further Resources

Ahsan concludes his talk by providing further resources for those interested in client-side security, inviting the audience to explore more in-depth content on the subject.

Welcome everyone.

Like I was telling you, I promise you this is not a security conference.

This is actually a dev conference and this is the third talk back to back.

So welcome to my talk, Attacking the Frontend, where we'll look at modern day client side security.

And in this talk I invite you to come to a journey.

And what's the journey about?

It's about to see how modern web applications, especially React and Angular, gets hacked these days.

And not just the security attacks that happen, but also what the previous speakers were telling.

What can you do about it?

How can you do better?

So not just exploring the attacks, but we will also see what kind of development best practices we can do to protect ourselves against it.

And last but not least, some just general resource sharing and Q& A.

So without any further ado, let's get started.

A very quick intro so you're not talking with a stranger, won't speak too much time.

This journey is going to be more like a road trip rather than a full Europe tour, cause it's 30 minutes.

I'm only gonna say, similar to you guys, I was actually once a developer, and then I fell in love with security, and then moved over to security around three ish, three to four years, years ago, and have been with security since then, but I still haven't figured out what do I love more, coding or security, and do both in my day to day.

Yeah, with that, let's actually jump onto the talk, and the first thing I want to do is set the landscape we're talking about.

In the past, year or so, especially, during COVID, when we were locked in our homes, we saw a rapid digital transformation, because everything and anything needs to have, online presence.

And with more online presence, there are more things that can be attacked.

I'd like to pose a question to the audience.

Can I see a quick show of hands, how many of us remember, building a website with just pure HTML, CSS and JavaScript, Just a quick show of hands.

Quite a few of us, right?

Fast forward today, we have so many different frameworks and languages and other things and technologies that are helping us do so.

In that, we've definitely had a lot of progress where a lot of these new modern frameworks come with built in protection, but we're going to see how some of those old vulnerabilities still haunt us as well as some of new ones that are popping up left, right, center.

And the first attack we still see to this day, and it's almost as old as time, is the code injection attacks.

And imagine this scenario where you have a website where you have a text box and that text box is just a search bar.

You put some text in and it gets run by a website and they show you all the products.

That is an attack surface, quote unquote.

But what if, instead of a text, a user puts in a code?

How would your website handle that unexpected data?

Chances are, in a lot of cases, it isn't still handled well, and that's one of the biggest reasons we still see code injection attacks.

I think that coffee has finally hit my system.

And the most popular type of attacks we still see is something called cross site scripting or XSS.

And in the next few slides, I'm going to focus more on how XSS happens in React and Angular.

But before I dive into that, I want to get a read of the room again.

How many of us already know what is an XSS attack, how it happens, and how to protect?

Quite a few.

Actually, quite a few.

That's awesome.

But I still saw some hands didn't go up.

I'll very, quickly go through what is XSS, how it happens.

Because if you don't understand that, it doesn't make sense how to go talk about how XSS happens in React and all.

Bear with me the folks who already know.

This will be very, quick.

But, in short, what XSS is when you put code, when the user puts code into your website and because of a vulnerability in your website, your website basically runs it.

It's as simple as that.

And with XSS, it can be a minor nuisance like someone defacing your website, to things like installing malware, to all the way full account takeover of the users as well.

So it can be very, drastic.

Let's have an example of how it can happen.

Let's say I'm a bad guy, an attacker, and my goal is to steal the user's session tokens or cookies.

And I found this vulnerable website where basically the code I can put in runs.

So I can craft a malicious URL like this one where basically in the URL I'm asking the browser to run some code in that search bar.

And trick the user to click on this link.

And when it runs on their side, if they were already logged in and had some sessions stored, that session, based on what code I have and what kind of protections you have, that token will then, be transferred to the user.

And then they can log in as that user using that session token and do all kinds of bad stuff.

That's just a very toned down example of XSS.

And it does happen still in the wild very often, even though we are getting better.

So some of the biggest bounties I've seen are from XSS and some of the most black mirror type of issues I've seen is also from XSS where people can spoof your, or get hold of your location and all.

And one of the things I want to convey is XSS can happen everywhere and anywhere.

When I talk with the developers, our common understanding is it will be mostly in the login or authentication page or common things like the navbar.

This is just one example we have from in Atlassian.

Some of you might be familiar with one of our products, Bitbucket, and it's basically same as GitHub.

And when you're doing a pull request in it.

In that pull request pop up bar, we used to have XSS.

We fixed it and we can talk about it now, but that's one of the, weird locations.

You don't expect code to run, but it can run.

Now, XSS and React.

That's the juicy part.

Let's get into it.

But before diving into it, can I, ask the audience, I'll be asking the audience a lot of times so I have apologies in advance.

What do you think is the best way to prevent a command injection attack like this, between these four?

Would it be doing some sort of encoding, data validation, context sensitive, output encoding, or, enabling CSP or content security policy?

Anyone want to shout out between the number one to four?

Four?

One?

Blast off?

Cool.

The right answer, again, this varies from context to context, but the best thing you can do is context sensitive output encoding.

Because when you're doing output encoding, that's where you exactly know where the user input is going and what kind of context it will be running on.

And that's, why you want to run it.

Number one doesn't do anything, it's just that.

Number two is, yes, it's useful, but trying to do, data sanitization is extremely hard, so you've got to be careful, and it's usually paired up with output encoding.

Number four, again, is awesome, but by itself it cannot protect against XSS if your app has vulnerabilities.

We saw context sensitive output encoding is the best thing you can do, and React does it out of the box.

So in this example, if you try to, this is just a dummy React application where, which has context sensitive output encoding turned on.

And if you put a code there, it won't run it.

It will just output it as a string.

It'll, be like, Oh, that's code.

That's not my domain.

I'm not going to run it, which is awesome.

Does that mean React, you can't do XSS and, thanks for attending my talk.

Unfortunately, no.

The most common ways we see XSS happen in React, first, is when you're trying to do, user HTML, user Submitted HTML output and you don't encode it properly or sanitize it properly.

The second thing is something called escape hatches.

And last but not least, certain HTML elements like URLs when they are not handled properly.

We're going to dive into each of them one by one.

So let's look at the first attack vector.

Okay, cool.

Outputting user HTMLs, through React.

React gives this functionality called DangerouslySetInHTML, and obviously the name gives it away.

So if you do want to take input, HTML input from users for all variety of reasons, and I'm not just talking about taking raw code, there's multiple ways users can be giving HTML specific input to your application.

You guys probably know that better than me.

And you want to output it somehow.

DangerouslySetInnerHTML is the React default way of doing things.

And by itself, it has no protection.

Which means if you give it some code and some HTML, it will actually run it and output that raw HTML.

That's alright.

That's not too bad.

Because fixing it is also easy.

You just put any known good sanitization library, it's usually a third party library, you chuck it in and you output it there and that's fine and dandy.

The issue really becomes, and that's one of the things I, I have with the React, with React is if you go to the React's official website, whoops, I've gone through two slides, and you look up, and when you research how to, output, HTML through your React application, chances are you'll go to the official DangerouslySetInnerHTML documentation.

And this is just a screenshot from the actual React website.

It tells you that yes, DangerouslySetInnerHTML is bad.

It can lead to cross site scripting attacks.

But it really doesn't give you an example of how actually to do it properly.

So it lets the developers pretty much figure out on their own what should be their remediation.

And in a lot of cases I've seen where, okay, we see it's bad, let's make our code run, let's come back and probably we'll figure it out later on how exactly to do it.

Now sometimes people actually come back and do it and sometimes they don't.

If you search GitHub with just the, text dangerously set in your HTML, you get more than one million hits.

Now, are all of them secure?

Maybe, or maybe not.

So it really is up to interpretation, and you'll find so many dangerous stack overflow code blocks where they haven't done any sanitization or anything done.

So that's where one of the, one of the challenges lie.

So how do we protect ourselves against it?

Thankfully, it is, known to be a very dangerous function.

So most security tools will pick it up, when you're running it.

But a challenge we have faced is because it's so dangerous, even though you have sanitized it, a lot of popular tools will still give you an alert.

And if you're doing that sanitization in lots of places, you have, there's a chance of lots of noise and lots of false positives.

How did we deal with that, high noise situation?

One of the things we did is, created a custom React component where we have put the, HTML handling and made sure that the, HTML input is properly being sanitized with the correct library.

And then we have given that component to the devs that, hey, instead of trying to implement DangerouslySetInnerHTML yourself, go, use this component everywhere and it's, we have that well documented and if you go to our XSS page, you will find this.

And the best part is because this is in only one place, the security scanner only picks up that specific file.

You won't see 10 different alerts for the same issue because that's wrapped up in one neat component.

And if you suddenly see DangerouslySetInnerHTML pop up somewhere else, that other than that, let's say supposed safe HTML component, that's an alert for you to go check it out that, hey, someone's going away from that paved path and we should probably have a look at it.

Cool beans.

Let's look at some more ways to hack React.

Does anyone know what is a React escape hatch?

Out of these four, is it a way to enable cross origin flows?

Is it a way to access the native DOMs?

Is it a way to access the DOM securely?

Or is it encoding?

Number four?

Yes, I see a few number fours, and that's correct.

So escape hatches are a way to bypass React's mechanisms and basically directly access the native DOM APIs.

And for obvious reasons, that is one of, also one of the dangerous things you can do, but because then you're bypassing the default output encoding, context sensitive output encoding React does, and Directly handling the DOM's APIs, which can get very, dangerous.

One of the good news is, and I apologize, I know I'm not giving enough time to read and process the code.

We don't have much time, so I'm pacing myself a bit, but, the slides will be up there.

Thankfully, some, elements like FindDOMNode is being deprecated, but things like CreateReference is still gonna be around.

CreateReference by itself is not dangerous, but it's how you use it.

There are some alternative approaches like using innerText instead of innerHTML, which is, recommended, and also most static analysis tools do pick up escape hatches when you use it.

Cool, more React XSS vectors.

Which one of these do you think can be, HTML elements can be used to run code?

Is it URLs, CSS, markdown, or all of them?

Exactly.

All of them.

That's one of the, another big issues we have seen where people don't suspect, a traditional HTML element can run code, but it actually can.

For example, one of the biggest ones we see is URLs.

In these two React blocks where you're dealing with URLs in an insecure way, if you chuck in a, a JavaScript URL there, which is still a valid URL, it will actually run that code.

That's one of the things to look out for.

The good news is, JavaScript URLs is again being blocked on the newer versions of React, but a lot of other things like resource URLs is still being able to run, and that is something like data dot dot dot dot is gonna still gonna run, so that's, not good.

Cool.

How do we defend against that?

One of the, this is probably a more hardline approach, but if you're dealing with some specific URLs, you can probably make the users give input part of it.

For example, if you need to embed a YouTube video, instead of taking the whole YouTube video link, just take the video ID and hardcode the rest of that URL so you know that nothing funky can be done.

But we do understand that many applications, it can be that rigid.

So that's where URL sanitization comes in.

But one of the biggest flaws we see with that is trying to do a blacklist rather than a whitelist.

So when you're trying to do URL sanitization, it's better to do a whitelist of good ones rather than trying to know which ones are bad and then block them, because attackers always find a way around.

A very 10, 000 feet overview.

We talked about, doing proper, input, handling, not using escape hatches and dangerous, HTML elements.

So there's some, just some resources.

If you search React Vulna or React Suspended, those are some deliberately made, deliberately vulnerable React apps you can play around with.

One quick note that I haven't, covered trusted types in React.

That's one of the other cool things you should be looking at, because, we just don't have enough time.

Move on forward, chug, chug, chug.

What about Angular?

Turns out Angular is actually better than React when it comes to code injection attacks, because Angular not only does output sensitive, context sensitive output encoding, but it also can do input validation when, where you need it.

And applies auto escaping.

What do I mean by that?

I'll give you a very quick example to explain it.

So let's say when you use Angular's innerHTML property, this is different from the DOM's innerHTML, and you put some dangerous code, it will automatically will remove the dangerous code and only keep the safe HTML which is secure to run.

And it also will give you an alert.

Like here, when it has removed something, it thinks dangerous.

But, when you need, you don't want to run any code at all.

You can use Angular's interpolation method and it will then make everything a string.

But again, if you want to run some HTML and not run some, then Angular comes out of the box to get rid of the insecure ones.

Which is, which is, great.

That means you're not fiddling around things like dangerously setting a HTML.

Does that mean Angular is also good?

It's all rainbows and sunsides.

Unfortunately, again, not.

There are a few things, ways, XSS can still happen in Angular, but unlike React, you really have to be trying.

So things like using the bypassSecurityTrustHTML function, which obviously sounds very alarming, is a key thing.

Similarly, there's other ways of reacting the native DOM element, such as the element reference function, or the render to API.

These allow you to directly handle the native DOM, which again, is quite risky.

One more thing with Angular is certain versions of Angular is prone to this attack called a template injection attack.

Again, due to time I'm not going to dive too deep into it, but when you're using Angular you definitely need to check what kind of versions you're using and whether template injection is a thing for you or not.

Very, quick 10, 000 feet of protect, how to protect your Angular apps.

By default, Angular does a better job.

So you stick to Angular's default ways and you would be fine.

Avoid using custom DOM manipulation unless you really, have to.

And if you do have to, please know what you're doing.

And last but not least, protect against template injection attacks.

Let's move away from code injection and let's look at something different.

In this, scenario, we have Bob, whose website, has a functionality of storing their, phone, user's phone number.

And you can, recover your password using that phone number.

Someday, one of Bob's friends come and say, Hey, I was using your website, my number has actually changed, what happened?

If your website is prone to something called the cross site request forgery attack, an attacker can craft a malicious request from their site and change certain things in your website, which is, again, something we don't want.

And it can lead to things like full account takeover, like TikTok had earlier this year.

Although that meant no dance videos for a day or so, which I'm sure a lot of you were sad, but they fixed it quite quickly.

When does a CSRF attack can happen?

When you have a state changing action, like updating your phone number, changing your name, etc.

And you're doing authentication, not authentication, sorry, session management purely based on cookie and nothing else.

And there's no unpredictable request parameters as well.

That's where the attacker can craft a malicious page like this one, where in their malicious page, they have hidden a form where when the user visits that form and it will basically send a request to your website using their tokens and or cookies and if your cookies is stored and tokens stored on the browser, will just, okay, this request is going to malicious website XYZ, I'm just going to fetch that cookie that is stored there, plug it in and make that request happen.

How do we protect ourselves against that?

So there's this fabulous thing called CSRF tokens.

It is unpredictable.

It is associated with user sessions.

It has a limited lifespan and it is action specific.

It seems like I'm trying to sell a tool, but it's not.

CSRF tokens come by default with most of the React and Angular frameworks.

But the important part is turning it on.

By default, CSRF tokens are not turned on.

So for your application, you do need to go and check it out.

Apologies for the rushed nature of the talk.

This is not...

yeah, this thing is giving me a hard time.

It doesn't work that much.

Anyways, a quick shout out that CSRF tokens can only do so much.

If your website has XSS attack in the first place, then CSRF tokens can't do much.

It's, already a god case.

What kind of CSRF tokens to use, based on whether the application is stateful or stateless.

There can be various kinds.

And, yeah, the names are up there.

Sorry, you're going to rush slightly.

Cool.

Some strategies Atlassian has taken to protect against CSRF.

We let no state changing actions happen through get HTTP methods.

Yes, I know that some people still try to do it, but that's why your protections are not fall through.

So please, no state changing requests using get.

Similarly, having the sameSite attribute turned on is fantastic.

Last but not least, we make sure on a proxy level, or, sorry, on a gateway level that all requests have a valid CSRF token, no CSRF token, no request, that's a hard policy.

And last but not least, CORS, cross origin requests off, so to ensure we have a layered approach to security rather than, I know I just said a bunch of jargon and not explained them much.

Apologies for that, but, you can always go back to the slides and maybe take a picture and look them up later.

Cool.

We have talked about our protecting our own code, but what of other people's code?

Because as we know, as we're developing sites, we, are pulling in stuff from all kinds of places.

And this is one of the, favorite images I have about third party dependencies.

Again, a very quick question.

I know I'm going over time, so I'm just going to take one or two more minutes.

If you're using a third party dependency, you're just, if that third party dependency gets hacked, you're just as much impacted.

And in the past, how many of these ways do you think a NPM dependency or a PyPy package has been popped?

Did the attacker hack them by asking nicely to hand the package over?

Did they buy the package from them?

Did they socially engineer them and trick them to hand it over?

Or, last but not least, did they, did the package just run out of, got deprecated?

They registered something?

Any guess?

All four.

Yes, you're correct.

All four.

All four ways someone has managed to pop an npm dependence, npm package.

And the funniest of all is probably the most ironic where the attacker pretended to be a genuine contributor and then said that, hey, your, dependence is awesome.

Can I buy it from you and maintain it?

And the guy was like, sure, but I don't get any money.

I don't get paid for it, let alone much recognition.

Here you go.

Next thing like the previous guys were showing, Monero is running and they're mining Bitcoins.

I'm actually a bit disappointed that they only ran Bitcoin miners rather than not doing much, which is a bit sad.

But yeah, a third party library is a big risk, and this is just a snapshot of the top NPM packages at that time when I was preparing the talk, and how many vulnerabilities that existed in the top 10, and as you can see, most of them actually had a critical vulnerability or a vulnerability high enough.

Similarly, it's not just...

so how can we protect ourselves against it?

Again, there's lots of ways built in into GitHub, bitbucket that help you do it, but on top of that, there are tools.

I'm not going to mention any anyone specific, but go check it out.

There's lots of great tools out there and it's a whole different subject.

Actually, I have another talk just on this topic in another conference, so I'm just going to leave it there as a next thing.

Utilize frameworks like Salsa or S2C2F.

I know more jargon, but it's "Secure Software Consumption Framework", and it's by Microsoft, they have open sourced it, fantastic.

These can really guide you a lot.

And my hot take is, when you have a dependency, staying actually one version behind the bleeding edge is often something we recommend because you never know where that latest version came from.

It could be a genuine thing or it could be a Bitcoin miner.

You really don't know these days.

Very quickly, it's not just consumption, it's also when you're producing it.

If you're an open source, package maintainer, there are things you should check out.

This article is awesome.

I haven't maintained any, so this is not my forte.

I'm not gonna talk about it, but do check it out.

What's next?

I'm gonna Skip over these because she's getting nervous, and these are some holistic ways we are approaching security.

Just some shameless plug, if you like this and want more security content, I, just host a YouTube channel where I talk, me and my mate, talk about security and just do different experiments, Go check it out if you're interested, I'll leave the link there.

But yeah, thank you so much, for listening to it.

Thank you very much.

It was, I learned, I think someone wanted to take a photo.

I'll let you take a quick photo.

AGENDA

Common Dangerous Security Issues

Highlight some frequently occurring high-impact security issues on the client-side.

Best Practices & Secure Development

How to reduce the probability and impact of these happening?

Resource Sharing + Q&A

Share helpful resources and answer any questions from the audience.

Hi, I'm Kaif

Technology & Cybersecurity enthusiast

  • THE UNIVERSITY OF MELBOURNE
  • MELBOURNE SPACE PROGRAM
  • Microsoft
  • ATLASSIAN

THE LANDSCAPE

  • Rapid digital transformation

    More and more services are needed to digitise because of the pandemic.

  • Big leaps in how we create web apps

    Very few ecosystems have matured as much as JavaScript.

  • New and old vulnerabilities

    Some very persistent issues and the rise of new ones.

CODE INJECTION ATTACKS

CODE INJECTION ATTACKS

Attack Surface

How does our app handle unexpected data?

Example Scenario

What if someone inputs JavaScript code in a forum instead of text?

Will the browser run that code? Or does the website have defences?

CROSS-SITE SCRIPTING (XSS)

QUICK OVERVIEW OF XSS

When Attacker Submitted Code Run in Browser.

The browser will always run code if given. It's up to the website to ensure it's not giving the browser code it doesn't want to run.

It can result in minor annoyance or FULL account takeover.

Attackers can deface websites, steal sensitive info or hijack a user's session.

<input type="search" value="potatoes" />
  
<input type="search" value="Attacker" /><script>StealCredentials()</script>
  
Source: OWASP XSS Guide

VISUAL EXAMPLES

  1. The user clicks the link and it executes in the browser
  2. Website
  3. Attacker sends user cookies to attacker
A flow diagram with three numbered steps showing a process involving a user, a website, and an attacker. Step 1 is labeled and indicates "The user clicks the link and it executes in the browser". Step 2 is called "Website", while Step 3 says "Attacker sends user cookies to attacker".

DRASTIC REAL WORLD IMPACT

Screenshots of two articles "Facebook pays out $25k bug bounty for chained DOM-based XSS" and "Multiple XSS vulnerabilities in child monitoring app Canopy 'could risk location leak'"

REALLY CAN HAPPEN IN ANYWHERE

XSS IN REACT

HOW TO BEST PREVENT XSS ATTACKS?

Select the best one.

  • Use base64 encoding to store the data.
  • Data validation / sanitisation during input.
  • Context-sensitive output encoding
  • Enabling Content Security Policy (CSP)

REACT AND XSS

Thankfully most modern web frameworks come with some default protections

React automatically does output encoding for us

React outputs all elements and data inside them using auto escaping.

const validateMessage=async()=>{ 
  setTimeout(()=>{ 
    setValidationMessage('Invalid referral code, <script></script>') 
  },1000) 
}
Source: StockHawk

REACT AND XSS

The most common reasons XSS vulnerabilities happen in React

Improper Sanitisation while outputting HTML

Direct output of DOM can be done via dangerouslySetInnerHTML but does not sanitise by default.

Usage of React Escape Hatches

Using React Escape Hatches is quick but very dangerous and bad code practice.

Improper encoding of URLs

Mishandling of dynamic URL is another common source of XSS.

OUTPUTTING USER HTML INPUTS

React uses the dangerouslySetInnerHTML function to allow output user-generated content.

return (
  <div>
    <h3>{title}</h3>
    <p> dangerouslySetInnerHTML={{ __html: review }}</p>
  </div>
);

As the name suggests, it is dangerous. Because it does not do any sanitisation and encoding by default.

Input

This restaurant is absolutely horrible.
The service is <b>slow</b> and the food is <i>disgusting</i>.

Output

1/10 Horrible!
This restaurant is absolutely horrible. The service is slow and the food is disgusting.

OUTPUTTING HTML SECURELY

Thankfully most modern web frameworks come with some default protections

return (
    <div>
        <h3>{title}</h3>
        <p dangerouslySetInnerHTML={{ __html: review }}></p>
    </div>
);

Dangerous as no sanitisation.

import DOMPurify from "dompurify";

return (
    <div>
        <h3>{title}</h3>
        <p dangerouslySetInnerHTML={
            { __html: DOMPurify.sanitize(review) }
        }></p>
    </div>
);

DOMPurify turns untrusted HTML into safe HTML.

REACT AND XSS

Screenshot shows Github search for dangerouslySetInnerHTML returns 1,064,345 results

REACT AND XSS

No proper guidance in the actual documentation!

A developer is left on their own to find the proper library and implement it.

dangerouslySetInnerHTML

dangerouslySetInnerHTML is React's replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it's easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it's dangerous. For example:

function createMarkup() {
  return { __html: 'First · Second' };
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

HOW TO DEFEND AGAINST THAT?

Most modern static code analysis tools will pick it up.

function TestComponent2(foo) {
  // ruleid:react-dangerouslysetinnerhtml
  let params = {smth: 'test123', dangerouslySetInnerHTML: {_html: foo},a:b};
  return React.createElement('div', params);
}
  

semgrep-test.js

typescript.react.security.audit.react-dangerouslysetinnerhtml.react-dangerouslysetinnerhtml

Detection of dangerouslySetInnerHTML from non-constant definition. This can inadvertently expose users to cross-site scripting (XSS) attacks if this comes from user-provided input. If you have to use dangerouslySetInnerHTML, consider using a sanitization library such as DOMPurify to sanitize your HTML.

Details: https://sg.run/Tx5d

let params = {smth: 'test123', dangerouslySetInnerHTML: {_html: foo},a:b};

HOW TO DEFEND AGAINST THAT?

Creating a secure component to securely handle HTML and using it everywhere.

import React from 'react';
import DOMPurify from 'dompurify';

// This function will render HTML safely using DOMPurify
function SafeHtml({ element, html }) {
  return React.createElement(element, { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(html) } });
}

export default SafeHtml;
import SafeHtml from "./SafeHtml";

return (
  <div>
    <h3>{title}</h3>
    <SafeHtml element="p" html={review}/></SafeHtml>
  </div>
);

MORE REACT XSS ATTACK VECTORS

WHAT IS A REACT ESCAPE HATCH?

Select the best one.

  • 1 A way to enable cross-origin interactions between frames.
  • 2 A way to encode data to avoid XSS vulnerabilities.
  • 3 A way to access the DOM through secure React APIs
  • 4 A way to directly access the native DOM APIs.

REACT ESCAPE HATCHES

Direct DOM Manipulation

React provides you with findDOMNode and createRef as escape hatches.

Escape hatches return native DOM elements with their full API, allowing the application to manipulate the element directly without going through React.

// Using Refs as an escape hatch to access the raw DOM
function App() {
  const messageBoxRef = React.createRef();

  useEffect(() => {
    let messages = "...";
    messageBoxRef.current.innerHTML = messages;
  });

  return (<div ref={messageBoxRef}>No new messages</div>);
}

HOW TO TACKLE ESCAPE HATCHES

Good news is React is deprecating it. But createRef is not :(

findDOMNode is deprecated in StrictMode.

Alternative approaches**

  • If you are using refs to add some content inside your HTML elements, use innerText instead. Source: StackHawk

Utilise static code analysis tools to identify escape hatches.

  • Look out for innerHTML, outerHTML, document.write and document.writeln

EVEN MORE REACT XSS ATTACK VECTORS

JAVASCRIPT AND RESOURCE URLS

JavaScript & Resource URLs can be a potential sink.

When the URL is hardcoded, there is no XSS vulnerability.

However, when the URL is provided by the user, as shown below, there is a potential XSS vulnerability.

Code Examples:

// React code using a dynamic URL for an anchor tag

return (
  <a href={url}>Open web page</a>
);

// React code using a dynamic URL to load an iframe

return (
  <iframe src={url}></iframe>
);

javascript:alert('Don't laugh, this is not a joke!')

JAVASCRIPT AND RESOURCE URLS

React is moving towards blocking JS URLs in future versions

But in older and current versions, it only gives a warning.

Unfortunately, it only covers JS URLs

It does not mention other resource URLs

HOW TO DEFEND AGAINST THAT?

Avoid taking the full URL as an input

For example, an application that accepts Youtube URLs as input could only accept the video ID as input. The rest of the URL can be created when needed by embedding the video ID into a static URL.

https://www.youtube.com/watch?v=4Ojv7cno4

This strategy prevents the attacker from controlling the URL scheme, eliminating the risk of XSS through a URL.

Do URL sanitization

Make sure your sanitisation is based on allowing 'known good' url types rather than trying to prevent 'known bad' kinds.

PREVENTING XSS IN REACT

A 10,000 ft view

1 Securely handle HTML outputs.

Creating a safe component is advised.

2 Don't use escape hatches

If you have to access the the DOM directly, involve security.

3 Be mindful of injections in other HTML elements

URLs, CSS, Markup can also be potential sinks.

PREVENTING XSS IN REACT

Vulnerable React Apps to play with

ReactVulna, React Suspended

NOTE - I HAVE NOT COVERED TRUSTED TYPES

ANGULAR AND XSS

Very good baseline protection against XSS.

Angular, out of the box has great options to automatically encode the data.

In case HTML formatting is required, Angular also does sanitisation.

Angular applies auto-escaping.

Applications can put data into the page using Angular's interpolation mechanism.

Angular's Strict Contextual Escaping is crucial baseline protection.

Name: Jane <script>alert("Evil code");</script> Doe

Interpolated input:

Jane <script>alert("Evil code");</script> Doe

ANGULAR - DEFAULT SANITISATION

Provide input sanitisation for HTML formatting from user.

We can use Angular's [innerHTML] property to bind the user input and automatically sanitise.

Note that this is different from the innerHTML in the native web APIs.

Dangerous user input
This restaurant is absolutely horrible.
The service is <b>slow</b> and the food is <disgusting>.
<img src="nonexistent.png" onerror="alert('This restaurant got voted worst in town!');" />
Automatically sanitised
This restaurant is absolutely horrible.
The service is <b>slow</b> and the food is <i>disgusting</i>.
<img src="nonexistent.png" />
Image source: StockHawk

ANGULAR - ENCODING & SANITISATION

User Comment

Comments

Received package. Excellent service. <script>alert("Evil code");</script> Highly recommended.

Angular Interpolation

Comment after interpolation:

Received package. Excellent service. <script>alert("Evil code");</script> Highly recommended.

Auto sanitisation

Comment as inner HTML:

Received package. Excellent service. Highly recommended.

The image shows a presentation slide titled "ANGULAR - ENCODING & SANITISATION", with examples of user comments and how Angular handles the comments through interpolation and auto sanitisation processes. The slide is designed to demonstrate how Angular can mitigate security risks such as cross-site scripting by sanitising inputted comments, with before-and-after states. The console output in the image illustrates a warning message regarding HTML sanitisation

ANGULAR XSS ATTACK VECTORS

BYPASSING ANGULAR'S SECURITY – I

Hard but not impossible.

Angular offers a way to output raw HTML without any XSS protections applied. This functionality is available through the function bypassSecurityTrustHtml().

The only acceptable use case would be to output a static piece of code.


constructor(private sanitizer: DomSanitizer) {}
getHtmlSnippet() {
    let safeHtml = '<img src="..." onerror="alert('Failed to load image')">';
    return this.sanitizer.bypassSecurityTrustHtml(safeHtml);
}
    

Creating a custom component using the bypassSecurityTrustHtml function


<div [innerHTML]="getHtmlSnippet()"></div>
    

Assigning a safe snippet to [innerHTML] does not trigger Angular's sanitizer

Code snippets: Pragmatic Web Security

BYPASSING ANGULAR'S SECURITY - 2

Using native DOM elements

Angular has ElementRef to directly access HTML elements. This code is extremely insecure and sidesteps Angular's built-in XSS defences.

@ViewChild("myDiv") div : ElementRef;

Using an ElementRef to refer to a specific HTML element

this.div.nativeElement.innerHTML = this.inputValue;

Dangerous behaviour using native DOM elements

BYPASSING ANGULAR'S SECURITY - 3

The Renderer2 API

With ElementRef, you can also use the Renderer2 API to manipulate the DOM. This mechanism is perhaps even more dangerous since the Renderer2 API is a legitimate Angular API.

@ViewChild("myDiv") div : ElementRef;

constructor(private renderer2 : Renderer2) {}

loadDivWithRenderer2() {
  this.renderer2.setProperty(this.div, "innerHTML", this.inputValue);
}
  

Image source: Pragmatic Web Security

TEMPLATE INJECTION ATTACK

  • Older versions of angular are vulnerable to Template Injection attacks
    Sandbox escape possible and run JavaScript code out of context.
  • Sandbox is deprecated from Angular 1.6.
  • It is a very common issue so please investigate it further.

PREVENTING XSS IN ANGULAR

A 10,000 ft view

1. Stick to Angular's default ways

If you stick to the Angular way of doing this, Angular will help you guarantee the security of your application.

2. Avoid custom DOM manipulation

To ensure you let Angular do its job, avoid direct DOM manipulation through ElementRef, the Renderer2 API, or native DOM APIs.

3. Protect against template injection

Understanding what template injection is and whether your code has protection against it is vital.

SCENARIO

Bob's website has account recovery method

Users can specify a phone number in the profile. A passcode can be sent to their phone if they ever lose their password.

One day Bob gets a phone call from his friend Alice saying she can't get into her account anymore.

Upon investigating, Bob discovers someone else mysteriously swapped their number for Alice's recovery phone n.

CROSS-SITE REQUEST FORGERY (CSRF)

HUGE SECURITY IMPLICATIONS

Article from BleepingComputer. Title is "TikTok fixes bugs allowing account takeover with one click"

HOW DOES CSRF HAPPEN?

A relevant action / state-change

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: sessionId=ythzwstzyeQKAPze05gHTvLyxfHsAfE

[email protected]

Cookie-based session handling

The application relies solely on session cookies to identify the user who has made the requests.

No unpredictable request parameters

The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess.

DELIVERING THE PAYLOAD

HTTP actions hidden in a malicious page.

<html>
<body>
  <form action="https://vulnerable-website.com/email/change" method="POST">
    <input type="hidden" name="email" value="[email protected]" />
  </form>
  <script>
    document.forms[0].submit();
  </script>
</body>
</html>
  

Malicious URL to exploit CSRF vulnerability

<img src="https://vulnerable-website.com/email/[email protected]" />
  

CSRF TOKENS - PROTECTION

  • Unpredictability - Attackers cannot replicate the value
  • Association with user's session - Disregard requests without a valid CSRF token.
  • Limited lifespan - The attacker cannot reuse.
  • Action-specific Tokens - Valid only for a specific action.
<form action="/transfer.do" method="post">
<input type="hidden" name="CSRFToken" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZ1YWVwZU1Y[...]">
[...]
</form>

CSRF TOKENS - PROTECTION

For stateful software, use the synchronizer token pattern.

For stateless software use double submit cookies

Implement defence in depth instead of one single mitigation.

Remember that any Cross-Site Scripting (XSS) can be used to defeat all CSRF mitigation techniques!

POST /email/change HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: session=2YQT0pci4MWaTFtPjqvm9t0kDvkVLvM

csrf=wF1fsz2MUhIOkx9ApHfylSbL2xAOfjRkE5emeaLi=kaif@normal-user.com

SOME STRATEGIES ATLASSIAN HAS TAKEN

  • State-changing operations must not use GET requests, as CSRF tokens cannot protect these.
  • Session cookies should have the SameSite attribute set to Strict when possible.
  • All state-changing requests must transmit a valid CSRF token for the request to be accepted.
  • API gateway with a CORS whitelist. Layered defense.

BUT WHAT ABOUT OTHER PEOPLE'S CODE?

The image contains a a classic XKCD cartoon depicting a large and complex structure labeled as "ALL MODERN DIGITAL INFRASTRUCTURE," which sits upon a small block labeled as a project maintained by a random person in Nebraska since 2003.

HOW HAS OPEN SOURCE BEEN HACKED SO FAR

Select the best ones.

  • 1 The attacker asked the maintainer nicely.
  • 2 The attacker socially engineered the maintainer.
  • 3 The attacker bought the open source package from the maintainer.
  • 4 Attacker registered expired / outdated resource used by the package.

THIRD-PARTY DEPENDENCY RISKS

  • lodash

    3 vulnerabilities (1 high sev)

  • request

    1 vulnerability (17 typosquatting attempts)

  • chalk

    0 vulnerabilities (1 typosquatting attempt)

  • react

    2 vulnerabilities (1 high sev)

  • express

    1 vulnerability

  • commander

    0 vulnerabilities

  • moment

    3 vulnerabilities

  • debug

    1 vulnerability

  • async

    0 vulnerabilities

  • prop-types

    0 vulnerabilities

Source: Snyk

SECURING THE SOFTWARE SUPPLY CHAIN

Context-driven usage of tools.

On top of npm-audit, OWASP Dependency check etc. many great tools like Snyk SCA exist, but they require active triaging.

Utilise frameworks like SLSA or S2C2F.

SLSA or S2C2F can provide a roadmap to achieve supply chain maturity.

Hot-take: remain one version behind the bleeding edge.

Unless the latest update is fixing a security issue or a big feature update, it's worthwhile staying a version behind.

SECURING THE SOFTWARE SUPPLY CHAIN

Screenshot of article titled "10 npm Security Best Practices" from Liran Tal

Source: Snyk

SOME OF OUR HIGHLIGHTS AT AT LASSIAN

Secure by default.

The 'paved way' concept. We're trying to create resources, components and tools that help the developers build securely from the start.

Humans + Machine = Magic.

Ensuring proper triage and integration of tools like Snyk, Semgrep etc.

You can't protect what you don't know.

Asset management and identifying the crown jewels is a core step.

MORE CONTENT IN EVERYTHING CYBER

Cybersecurity and beyond

LinkedIn

Everything Cyber

Screenshot of the site "Everything Cyber"

THANK YOU

For listening. Shout out to Marco Cantarella for inviting me and arrange this talk.