The React Show

A podcast focused on React, programming in general, and the intersection of programming and the rest of the world. Come join us on this journey.

Listen

[95] How To Build Secure React Apps

In this episode, delve into the world of web application security and discover practical insights to safeguard your code. Join Thomas as they discuss common threats like SQL injection, cross-site scripting,...


In this episode, delve into the world of web application security and discover practical insights to safeguard your code. Join Thomas as they discuss common threats like SQL injection, cross-site scripting, and request forgery, emphasizing the importance of using secure libraries and following best practices. Explore topics such as data validation, authentication, and authorization, along with the significance of log security and intrusion detection. Gain valuable tips for writing secure code and understand the risks associated with implementing your own cryptography.

thereactshow.com/support

Join The Reactors! thereactshow.com/the-reactors-community

Join our Discord! https://discord.gg/zXYggKUBC2

My book: Foundations of High-Performance React https://www.thereactshow.com/book

Consulting: https://thomashintz.org

Music by DRKST DWN: https://soundcloud.com/drkstdwn

Part 1: Introduction to Web Application Security In this segment, the host discusses the importance of web application security and the potential risks associated with vulnerabilities. The focus is on common threats such as SQL injection, cross-site scripting, and request forgery. The host emphasizes the need for understanding and addressing these threats, even when using frameworks like React that offer built-in security measures.

Part 2: Log Security and Authentication/Authorization The host highlights the significance of log security and cautions against logging sensitive user information that could be exploited. They stress the importance of implementing secure authentication and authorization systems and share insights on common mistakes made in login system implementation. Keeping the login process simple and separate from other code is strongly recommended to minimize vulnerabilities.

Part 3: Data Validation and Libraries/External Services Data validation is discussed, with an emphasis on distinguishing between data sanitization and data validation. The host advises against relying on client-side validation and stresses the importance of validating and sanitizing data on the server-side. They also provide insights on assessing the security of libraries and external services, recommending thorough documentation on secure implementation, policies for handling vulnerabilities, and a high-level security approach.

Part 4: Writing Secure Code and Final Tips The host shares their approach to writing secure code, emphasizing the need for systemic solutions, explicit labeling of untrusted data, and assuming worst-case scenarios to design robust security mechanisms. They caution against overcomplicating security measures and advocate for using well-tested libraries for cryptographic functions. The importance of backups, intrusion detection, and minimizing stored data is also highlighted.

Support the show


Transcript

Welcome to the React Show, brought to you from occupied Miwok territory by me, your host Thomas,

and Broken Assumptions. Is your new web app secure? How easily can someone get into it,

take over accounts, or even steal user data? Can someone- take over the site or even use

it to distribute malware? How do you even know? Don't worry, today we're going to cover the

basics of web application security so you'll know where to start, what to focus on, and

how to progressively harden your web application. Thank you so much for joining us. I'm fresh

off a bicycle tour in the San Gabriel and Santa Monica mountains down near Los Angeles. And

I'm really excited to jump into the basics of web application security, maybe more. Maybe

I'm too excited. I just, you know, it was a great time. I had a great time and I'm just

feeling refreshed, you know, so we'll see what happens. But I did want to begin with a couple

quick

super excited to present the general availability of the Reactors. It's the silly name I'm giving

to my new initiative to expand the community around the podcast and programming and React

in general and just try to help all of us get better at programming and React as well as

provide a place to just hang out. First, you can sign up for a premium version of the podcast

that includes all of the regular episodes ad free, as well as bonus episodes. And not only

do you get more, but it also really helps to support this show. And you can actually sign

up for as low as $1 US dollar per year, trying to make it as accessible as possible as well.

But whatever you're able to do, if you're interested, it makes a huge difference in my ability to

produce high quality educational podcasts. I just super appreciate any support anyone is

able to give. Second, you can join for free on our new Discord server or channel. I'm still

learning Discord, whatever it's called. But yeah, you can come hang out with us. ask questions

about programming or react or even tell me how I was completely wrong about something. I'd

love to hear that too. Yeah, so if you want a little break from programming too, I also

post sea slug pictures or other fun adventure things. I want it to be a fun space to hang

out so we can learn but we can also just be friends and hang out with each other, right?

But yeah, no matter what the reason, we'd love to have you come join us on Discord. Links

for Discord and the premium podcast feed will be in the description or summary or whatever,

wherever you find this podcast, as well as on our website, of course, thereactshow.com.

So speaking of Discord, that's actually where the idea for this episode started. So I just

want to say thanks to this MC Kraken on Discord for the initial questions about web application

security and feedback on my early outlines of this episode. Right before we jump into the

main show though, I do want to give a real quick disclaimer. You are responsible for security

on the things you work on, not me. This episode is just meant to be a- primer on web application

security and is absolutely not an exhaustive resource and is not a replacement for doing

your own security analysis on your own projects. My goal is to provide a quick overview so you

can know where to start and so you can dive in deeper on your own projects and also just

to outline methods and approaches I take to in general keep web applications more secure.

And Of course, just like my coverage of this topic is not entirely exhaustive, security

will also never be exhaustive either. Security will never be 100%. Every system that we build

or work on will have holes. The goal of security is not to make a perfectly secure system that

is unreasonable and essentially impossible. The goal is to make the cost of attacking a

system vastly outweigh the rewards. If someone, like for example, if someone breaks into your

system to steal user data but finds out you don't store any user data, Well, you win there.

You've made the reward essentially nothing, in that context at least. There might be other

reasons they might break in. But yeah, the whole point of security, and I think this is something

that if you're not super familiar with when it comes to security, might be a little bit

surprising. But the entire point is not to build a perfectly secure system. It's not to come

up with perfect security solutions. The point is just to make it so it's too costly for people

to break in relative to what they'll get if they succeed. So that's where my thinking when

it comes to security is sort of comes from, which is that I call it sort of scaled security.

So trust in a system should be proportional to the hardening effort. So for example, when

you're first launching your web application, let's say you're just going to share it with

a couple friends and it's not carrying out financial transactions on people's behalf. Maybe you're

using a service for that, but whatever. The point being, you're launching a new application.

It doesn't have a ton of users. The users it does have are your friends, and they understand

this is the first version, and it's gonna have bugs, and it's not gonna work well. In that

case, it might be perfectly fine to spend very little time on security, because the trust

that people are going to have in this system are gonna be very low. So if people are approaching

your system and being like, oh, this thing is probably gonna leak all my data and it's not

secure at all, I'm not gonna put anything that I care about into it. And it's not maybe inherently

creating data that you don't want to share or something. There's a lot of cases where I think

when you're first starting, I wouldn't say all cases, there are cases where you need to care

right from the beginning. But I think for a lot of people, like, Maybe you're creating

a site to track some recipes or something and you want your friends to try it out a little

bit before you make it a larger launch or something. It's still good to be aware of security things,

but it's not as important to have a super hardened system at that point. That's where I think

of scaled security.

you know, how much trust people have in the system. And, you know, a lot of cases people

don't know how much to trust a system, but as the software engineer, we can better evaluate

how much trust they should have in a system as well, and also evaluate how much trust people

think they have in a system. And so we can scale our security based on that. So if we understand

that our software is creating valuable data, We need to scale our security to match how

valuable that data is. So that's kind of my preface to all of this is that you're never

going to build a completely secure system, but the level of security you provide should proportionally

match the amount of trust that people have in your system or should have in your system if

they understood everything it did. and proportional to the rewards somebody's going to get for

breaking into your system. I mean, if you don't have anything valuable, security doesn't matter

as much. There's still other aspects to security. Maybe somebody can take over your server and

use it to infect your users with malware. But that's still a reward somebody gets for the

security vulnerability. But the entire point of this is just that it's going to sound like

a lot probably if you're not familiar with this topic. A lot of the stuff I'm going to talk

about, it might sound kind of overwhelming. But my point is just that think of it in terms

of a scale. We're not trying to have perfect security. Not every application needs the same

level of security. We need to develop an ability to tell how much security a system should have

and engineer solutions for that. That's part of being a software engineer is understanding

these tradeoffs. I'll try to help guide us along that journey throughout the podcast, but I

wanted to start with that so that people are able to frame all of this information in a

more useful manner. One other thing I wanted to... talk about before we get into the main

meat of this episode is that I'm primarily going to be talking about technical security. I'm

going to presume you have a React-based web application, but I think a lot of this will

apply to any web application. I'm specifically going to speak to React. What I'm going to

talk about applies to everything from a technical perspective. But the more important thing in

any web application or any system is going to be your operational security, not your technical

security. Technical security is important. Operational security, though, is where you should start.

Most hacks into systems are not via breaking in, like hacking into the system. using some

vulnerability. Most systems are broken via social engineering. So our focus in this podcast is

going to be more about technical security, like how do we secure applications from a technical

perspective and vulnerabilities. But I just wanted to make it very clear that the place

you should always start is operational security. And what I mean by that is like phishing attacks

or giving people access to an admin account that shouldn't have access or that you don't

trust or those types of things. The people in your systems are always the weak point. Even

very insecure technical systems, usually operational security is the bigger deal. You need to take

care of that first. I just want to mention that and I'll make some other references to it because

it's so important, but the main point of this will be on technical security. All right, so

let's get into it. The best way that I think to start is that we need to look at where people

are coming from when they're trying to crack your system, when they're trying to hack your

system because We need to understand that before we can understand how to make secure systems.

And so I call this thinking like a cracker. Hackers, they're different than the way they

look at your systems is different than the way you will look at your system as an engineer.

I found this from, I think it was mouser.com, like a blog post. And I thought it was really

great. So they say follow paths. They will continue to follow a path until it fails to progress

them forward on their mission. We need to start getting our head into thinking in that term,

those terms. When you're looking at building a system and being that engineer, you're like,

okay, I've structured my API this way, my client this way, and you're thinking of it in those

terms. The way that a hacker thinks of things is like, oh, is there a vulnerability in the

login system? I'm going to try a whole bunch of different things to try to get into this

login system. Is there something I can learn about the way the sessions are organized or

the session tokens, or is there a weakness in the SSL certificates? Can I intercept communications?

they're going to, you know, the way they think of it is, okay, how do I break into the login

system? And they might try a bunch of things they can't break into the login system. Then

they might move on to something else. Oh, can I, you know, break into this other part of

the system? Can I directly break into the server, you know, using some other program that the,

you know, is running on the server, not the main web application? Is it not firewalled

off? I'm going to port scan. And so that's the way that hackers... are really looking at your

system. And so it's important for us to put on our hacker hat, so to speak, and think about

systems that way as well. And just a note throughout this episode, I'm going to sort of talk like

the hacker is a real person sitting at a keyboard, typing this stuff in, trying to break into

your system. And that could be a thing. Generally though, all of this stuff is encoded in bots.

that try to do it automatically. It's not, it's kind of not relevant because the people that

create the bots, you know, create them to do the same thing that they would do if they were

sitting there in front of, you know, at their keyboard, right? I just want to note that.

It can matter in terms of like how quickly somebody is able to do something. You can make a bot

that like tries to break into your system by guessing random passwords, right? And if it

can submit 10,000 requests per minute or whatever, that's going to be, open up vulnerabilities

that wouldn't be there if somebody had to manually type in a password every time. But that's not

so important. Like once you get into this and start thinking about it, it doesn't matter

as much. So I'm just going to talk like it's a real person, but you can imagine it's actually

a bot sometimes, right? Anyway, so going back to our like, hackers follow paths. Another

part of this is that it's really important to try to get assumptions out of your head and

just assume that all of your assumptions will be wrong. In fact, this is generally the place

I start. So if somebody says, hey, can you perform a security audit of this system? I'll look

at the code and be like, okay, what are the programmers assuming? One great example of

this will be a lot of times on the server side, they will assume that the client they're talking

to, the web application they're talking to is trusted. When you're programming the server

side, you're not usually being like, okay, what happens if somebody creates a duplicate of

this website that's malicious? and connects to my server and starts sending me requests.

You might, in general, think like, okay, let's make a secure API, right? But usually what

I find happens is people will be like, oh, okay, we'll take these couple security measures to

make our API secure. And then from then on, assume that the web application they're talking

to is the one that they wrote.

Okay, they're assuming requests are going to come in this order. What happens if I don't

send in requests in that order? Can I just jump ahead in the login process, for example, and

send a request that the server thinks is going to come after three other requests? And so,

yeah, I think when we're looking at how to think like a hacker, this is by far the best place

to start. all of your assumptions are wrong. And even if your assumptions happen to be right,

it's a really great practice. For example, one way you could look at a system is be like,

let's assume that our HTTPS layer, our TLS layer, our security certificate system doesn't work.

Let's assume it's broken. Normally you assume that works fine, right? And maybe it will work

fine. Maybe there's nothing wrong with it. But part of this learning process is to be like,

okay, let's assume we broke something. Let's assume we implemented it wrong or there's a

bug in whoever wrote the library that we're using to provide that. What happens then? If

somebody's able to get past this, what do they get? Where can they go next? And so thinking

like a hacker, this is the way that I usually like to... think about it. It's like, oh, let

me look at this system and just start making a bunch of assumptions that things aren't the

way they seem to be. And so that could be like, let's assume we have a bug here. Let's assume

somebody can view people's bank account numbers. Let's assume somehow there's a vulnerability

we didn't know about and people can view this data in our database. What happens then? What

can they do with this data? That's the way I like to frame it. That's the place I like to

start when we're getting into all of this. So it's like some other examples might be, don't

assume that user data will only be used in the original code path. And this is another part

of security and that is, don't assume that future engineers at the company will make the same

assumptions that you do and think in the same way that you do. going back to this user data,

you might be like, oh, I don't need to sanitize this data for cross-site scripting because

it only ever gets used in this specific way, which never gets sent back to the client, well,

maybe one year later, a new engineer implements a feature that sends the data back to the user,

not realizing it wasn't sanitized. They made the assumption it was. And so that's where

I just try to get in this mindset whenever I'm... doing a security audit or writing code like

this where I'm like, okay, let's assume this fails even though I think it won't. What happens?

That will really help you just start learning. We don't necessarily need to do anything with

that yet, that information, but it's important to just spend some time practicing that. One

of the best things you can do when you're doing this is even spend looking at code, looking

at your own sites, and just trying to get in that mindset of how can I think like a hacker

to hack into my own systems? This will absolutely pay off. It will really help start retraining

your brain to think and view your code in a different way that will help you create more

hardened systems. Another aspect to mention when it comes to assumptions is that I find

a lot of engineers assume for some reason that people hacking into a system, they just exploit

one thing. That's almost never the case. Many attacks involve multiple attack vectors. For

example, maybe the hacker's looking at your system and they say something like, oh, look

at this. It doesn't verify phone, like the phone number matches the account. It only verifies

the email address. I can use that to change my account to someone else's phone number.

I don't know what that will let me do yet, but I'm going to find out. And so, you know, maybe

they make that change, they get somebody else's phone number, and then maybe that allows them

to bypass the two-factor authentication or something like that. So when you were initially programming

the, you know, form to update somebody's profile and set the phone number, you were just assuming

that, you know, somebody setting this number an authenticated user for this account, not

realizing that your API just lets anyone send a request in here and update the phone number,

right? And so that's kind of what I'm getting at. And usually, it'll be like usually people

break into a system using something that seems really minor. You're like, I don't need to

secure that because it's not that important. But they get to that point, which allows them

to exploit something else that is more major and more major and more major and they can

take over more and more of your system. So it's important to also when you're thinking about

this path-based hacker approach to keep that in mind. It's not just one vulnerability. It's

multiple. Another example like the session token is stored in the cookie. Is there a way I can

get access to cookies? Oh, look. I put data. I put data into this text field.

into a form and it shows up on other people's feeds, right? And it isn't escaped. They didn't

escape this code in some way. So I could add some JavaScript on maybe my profile and then

it will show up on everybody else's feed, which means it's getting run in everybody else's

browser, and that JavaScript will let me read their session token cookie. That's an example

again of how you can sort of go through this path. You have a vulnerability essentially

in two different places here. So always remember, defense in depth, never rely on one piece being

secure. Try to secure all the pieces. Try to make the assumption that somebody broke through

the earlier layers. Attacks are usually a chain. They might start with something that seems

hardly worth securing, but once you get past that, you get to progressively higher levels

of trust within the system. All right, so I like to think of things in a sort of methods-based

approach, right? If you've listened to this podcast, that's the way I like to do it. So

that's what I want to talk about next is how can you do this in sort of a methodical way?

So we've talked about how to think like a hacker, but how do we actually apply this? So this

is what is called the threat modeling process. If you really want to get into this, you can

look up way better information. This is just an overview. But this is kind of generally

the method I would use if I'm trying to do some sort of security audit. So to do a threat model,

the place that you generally start with, there's other sort of ways to do it, but I like to

focus on what are called the assets. Identifying assets. Assets. So assets are things a cracker.

might be interested in. Maybe this is personal data, session tokens, bank account numbers,

anything that has value to someone else in your system. These are your assets. So you can just

list them out. That's what I have to do. Just write a big list. The next thing you'll want

to do is identify and rank threats. So then you can go through that list and be like, Okay,

what are the actual threats to this data? So let's say it's personal data. Somebody could

steal that data, disseminate it on the internet at large. And part of this is like ranking

and sort of writing how big this threat is. So let's say you have very minimal personal

data, a first and last name for a site that is just for storing recipes. Well, if this

data gets leaked to the internet, I mean, it's not great to leak anything, but what value

does that really have? I mean, maybe not a lot if that's all it is. But maybe you're Ashley

Madison and you run a website for people to cheat on their partners. Leaking their first

and last name could be absolutely devastating. So this data might be worth a ton. You might

be like, okay, this is a really, really valuable asset. We're going to give this a high rating.

So yeah, I usually will go through that list of assets and just sort of it doesn't You know

depends on how thorough the security audit you're doing if you're in a new web application You

know it can just be pretty quick like oh, yeah, this is really important. This is not as important

Whatever so that can be yeah Many different things too. It could be like oh, what if somebody

can run their own code on our server? What if somebody gets admin access? You know definitely

if you're gonna do this you can look up like lists that people have created that will give

you more ideas. But yeah, you can have this asset list, you can identify and rank threats.

Another example might be a session token could be used to impersonate another user on the

system. What does that give them? What does that let somebody do? How much of a risk is

that? Or a stolen bank account number could be used to steal someone else's money. I mean

that seems like you want to do it in a sort of relative way. Maybe there's a bigger risk

in your system and that's number three on your list. The whole point here is just to sort

of give us a way to prioritize our efforts. So the next thing is a threat analysis, which

is basically the probability that a threat occurs times the cost to the organization or the users

of your system. So this is, you know, being like, okay. We've got our personal data and

maybe it's worth a lot. How likely is that to actually be disseminated, broken into, stolen?

Maybe you encrypt the data and you take all sorts of other safeguards against it or something

so the probability you feel like is lower that it might get stolen. Well, that might move

it down on the list of your priorities. Basically at this point, this is where we start also

exploring attack paths. So we'll look at our system and be like, okay, if somebody breaks

into the login system, that gives them access to this. If they're then able to elevate their,

you know, login to an admin account, that gives them access to these things. Um, but to get

there, they need to break in three systems maybe. Um, and so you're like, well, that seems the

last likely. So that's basically just this process. You can look it up if you really want to know

it, but the general idea is just like get an idea of the paths somebody would have to take

through your system to get to these assets and rate how likely that is times the cost of them

actually succeeding at it. Another thing I like to do at this stage is just to sort of note...

how each of these paths is mitigated or not mitigated. Maybe part of your system is you

tell users, hey, we don't protect against this. That might be valid. But yeah, so that's what

I would do at this stage. We have our threat analysis. And so that's sort of a very abbreviated

version of threat modeling. But this is sort of where I start. I look at a system. I identify

the assets. I rank. the threats against those assets, and then I do the threat analysis where

we figure out sort of the cost priority and the paths a hacker might take through your

system. Once we have this data, we can prioritize our security efforts. We can look at the top

of our list and be like, okay, this is the most important thing for us to secure. These are

the paths we can imagine somebody taking to get to this asset. What can we do to further

mitigate this? Maybe we're like, OK, we need to do better. You can look at each of those

paths and be like, OK, what can we do to stop somebody getting through this layer? What can

we do to stop somebody getting through this layer? So this provides a nice method of doing

a security audit and making your system more secure in a methodical way. All right, so next

I want to talk about basic attack vectors. And this is definitely not an exhaustive list,

but when you're writing a web application, there are very common attack vectors that you should

be aware of, at least. And first, I'm going to talk about operational security and social

engineering. Then we'll get into the technical things. So something that I want to note that

a lot of people forget is it's super important to secure your domain registrar, your host,

things like that. If somebody can break into whoever you've registered your domain with

and take over your domain, boy can they really do a lot of harm at that point. And so that's

not code you've written, but keeping that secure is super, super important. So remember to keep

those types of things in mind as well. One thing that I highly recommend you do is use a hardware

security key. I think, I honestly think most engineers should be using them. So a hardware

security key is basically a physical device that's got cryptographic stuff on it. I'm not

going to go into all the details, but it essentially means that if you use it for two-factor authentication,

things like that. It basically means somebody can't get into the system unless they physically

have that hardware key. And that eliminates a massive host of vulnerabilities when it comes

to things like securing your email, your domain registrar, things like that. So I really recommend

all engineers, software engineers that work basically on anything should spend some time

understanding how to use a hardware security key or at least like a two-factor authentication

app on their phone which is also good. The reason why I really recommend a hardware security

key though is because then you can use WebAuthn, Fido, you can look these things up but they

essentially provide phishing protection as well if you use them correctly. Like when I plug

my hardware key into my computer and I log into my domain registrar, I do my username and password,

then it says, okay, verify with your security key. And you can't get into the system unless

I enter a code that does cryptographic stuff on this hardware security key, and I physically

touch it, you know, hit a button on it. And using public key cryptography, that process

verifies the site the request is going to is actually the site I think it is. It's the site

I initially set up this hardware security key on. And so this is super valuable because it

eliminates a lot of the phishing attacks that normally take over people's accounts where

they think they're on their domain registrar's website, they enter their username and password,

and then maybe even... They enter in the two-factor authentication code from the authenticator

app on their phone. But turns out it's a completely fake site. And this fake site in the background

is entering all these details into the real site and giving that hacker access to these

things. If you use a security key correctly, you eliminate a lot of these things. So I definitely

recommend that. It's kind of a pain. It's extra work, but in my opinion, very worth it. Anyways,

you can do what you want, model your own risk and all this, right? I'm not going to tell

you what to do, just a recommendation. One other thing I want to mention is secure your email

and anyone else at the company that has an important email account. Don't use SMS for multi-factor

authentication, two-factor authentication. It sucks. A lot of people though don't remember

to secure their email. And I think... even more important, secure that this one is, this one

is hard. But if you can make sure that people with important emails in your company also

have them secured like the CEO because a great way that people social engineer their way into

systems is The CEO is like, I'm not super technical. I can't handle all this extra security measures.

And so they don't really secure their email account. Somebody hacks into their email because

it's easy to hack into. And then they send out emails to other people at the company telling

them to do things, impersonating the CEO or CTO or somebody high up in the company. And

A lot of people, like engineers, they're probably not going to question that. They get this email

from the CEO being like, oh, this is really important. Can you take care of this by XYZ

time and basically let a hacker into the system? So just a word of warning, anyone with like

authority in a company, they need to secure email and chat programs, anything like that.

Anyways, all right, done with operational security. Let's get into basic technical attack vectors.

So these are pretty classic, I'm not going to go into anything wild at this point. There's

a million ways you can hack into a system, but we're going to talk about just a few major

ones. So database injection. If you have a database of any kind in your system, you run the risk

of injection. So what is injection? Basically think of it this way. Let's say you have an

SQL-based system. And you... put user data into the SQL queries. Let's say you just made the

queries up with a string, you interpolate or append user data into these queries. Well,

what if a user of your system puts SQL into their data? Then you will be running the attacker's

SQL code against your database. That's horrible. It can let them... getting access to basically

everything. This is super classic. Not gonna go into all the details again, but database

injection is one of them. How do you avoid that? Don't create your SQL just using plain strings.

Basically, most libraries today will provide a API and it'll be the main API where you pass

in user data separate from the query itself. It's parameterized is what it's called. Like

if you use an ORM, Object Relational Management System, that type of thing, generally it provides

us for it. But take like five seconds and look into your system and look at how to do this

right. Don't make the mistakes that people have made in the past and do it wrong. This one

should be pretty good these days. Just take five seconds to understand how your system

works. The next one is cross-site scripting. And when it comes to React, This is one definitely

to be aware of. So cross-site scripting is basically an attack vector where an attacker is able

to run their code on your website, within your web application. This is something I mentioned

earlier. So somehow an attacker, maybe they put JavaScript into a form field on your site,

and this JavaScript gets served up to other users in some way. and runs on their system

in their browsers. This is very bad. Again, this can basically give somebody access to

everything in your system eventually or do lots of other nefarious things. Very bad. Cross-site

scripting. It's a very classic attack vector. But specifically, when you're using React,

there are a couple things to be aware of. Never ever put... data that users have entered into

your system inside dangerously set inner HTML, I think that's the property name. Unless you

really know what you're doing and you really actually understand cross site scripting and

you know how to sanitize that data, just don't do that. And the other thing is don't put user

data into attributes of components in React. Things that could... be passed through as like

a style property or something like that. This one's a little bit more nuanced in understanding

it, but from a blanket perspective, if you're using React, you can put user data in like

the body of a HTML tag. Like let's say something eventually gets rendered out as a div and in

the body of this div, you put some data the user has entered, their name. whatever it happens

to be, that React will always automatically escape for you. So you don't need to worry

about cross-site scripting if you put... In fact, not only do you not need to worry about

it, you just need to be aware that React will escape this for you. So you don't need to escape

this data when it goes into your system necessarily. In fact, I'm going to talk about that a little

bit more in a second, but... The thing to be aware of is if you just generally use React

in a normal way where you just render components and include user data in that output, you'll

be fine. Just don't put it in attributes. Don't be like, style equals dollar sign user data

or whatever. Don't put it inside attributes. Don't put it inside dangerously set inner HTML

and you'll generally be fine. React is great. It takes care of this for us. Originally using

things before React, this was not always the case and boy, it was much easier to have cross-site

scripting. But yeah, if you're using React, it's pretty straightforward. I have though,

definitely run into cases where people have put user data into attributes and even one

time I had somebody putting it into dangerously set innerHTML and they thought somehow that

was more secure. No, don't do that. But yeah, so that's cross-site scripting. Another one

to be aware of is request forgery. So this is like,

one example would be server side. So don't use user data to access local resources. So let's

say you had this brilliant idea where you were going to take someone's name and use that as

the file name on your file system to store some data about that user. I mean, I don't know

why some of you do this, but just to give you an example,

what you're going to do then at some point in your system is open up that file. Well, if

somebody can put any data they want for their name into that field, you're basically going

to be running a hacker's code locally on your system. Again, you can. look into how this

works and maybe you can escape it. So, or create a whitelist or do this in some way securely,

but by default, you need to be careful whenever you're opening a network address, a file on

your system, a database, credentials, anything local to your system or to your infrastructure.

Don't put user data into it because then somebody can use this to forge, you know, to local I.O.

within your system. So that's another one to be aware of. This can also be clients forging

requests to the server, clients, your client forging requests to somebody else's server.

Just another vulnerability to be aware of. Alright, so those are the main web app based threats

that I'm going to cover. There's a million more but that's always basically where I start with

for historical reasons, those things have been exploited more than basically anything else.

So definitely make sure you get those things right. Luckily, libraries often do a much better

job today than they used to in terms of protecting us against those things, but at least spend

a little bit of time to understand what your library does to protect against it and how

to use it effectively. Next, I'm gonna mention a couple other areas that I... find people

often make mistakes on or don't know about when they're getting into this. So another one would

be log security. What are you putting in your logs? This is kind of the same as like don't

put user data into logs because,

or at least you got to be careful because a lot of times logs aren't treated very securely.

And so this could be an easy way to leak user information or even let hackers run code on

your system. A great example of this, which it wouldn't be running on your system, but

something people don't realize is that in JavaScript, console.log and console.error essentially are

the same as eval. So anything that, you know, if you put user data into a console.log or

a console.error, that essentially allows somebody to run arbitrary JavaScript on your client.

Maybe this doesn't matter, depends on your system, but it's just something to be aware of. And

same on the server side. Be really careful what you put into logs and be careful what you do

with logs. I think people forget about this a lot. They're just like, Hey, let me log this

data. I want all the data. Log it all out. Um, that could be a threat. Be careful what you

do with logs. Um, And the next thing is a big one, I think, for people getting started, which

is authentication and authorization. You got to make a login for your system, right? Most

systems have a login. This is where so many mistakes have gotten made. I have found so

many vulnerabilities in login systems. A lot of times, people get sort of the basics right,

like username and password or. They're using some library to do this for them. But oftentimes

where they go wrong is identity. And identifying who a user is or updating data in the login

process, there's just a million ways you can do this wrong. And so my advice is always keep

this as simple as you possibly can. Even if you're using some library to handle this stuff

for you, just keep the implementation of that library, that code, just keep it super simple.

Just make it only about one thing, logging in. Only one section is authorizing the user to

get into the system. The next section might be identifying the user and setting up their

session token, but just keep it really simple. What I have found is these login systems just

balloon. It's really bad. I think what happens is people build the initial one and then somebody's

like, hey, can we add this feature to automatically do x, y, z after a person logs in? And so people

will start putting other code into the login routines. And this is extraordinarily dangerous.

Just don't do it. Make that a separate thing, completely separate. Don't update data on login

automatically unless you're super, super careful. I see this all the time too. People will be

like, oh, our first set of users didn't have this data set. We're going to set it for all

users when they log in or update a phone. Maybe somebody puts in their email and their phone

when they log in and somebody like as a second factor or something. And or I've seen like

they log in with both, I don't know, multiple pieces of data. And people are like, oh, we're

gonna save the user a step. We're gonna update this data for them when they log in. Don't

do that, never do that. It's like the worst thing ever. Cause without realizing it, you

often open up vulnerabilities where it allows a hacker to. inject their own information in

those paths and essentially log in as somebody else. So just something to keep in mind, make

your login systems, your authorizing users and identifying users as simple as you can. This

one is, I don't think I can stress this enough. People, this is by far the place that I've

seen the most issues. Like generally at this point, those other things like database injection,

cross site scripting, that kind of stuff is I don't usually see glaring issues here. People

are generally aware of it, and libraries do an OK job of handling it. But when it comes

to actually implementing this stuff, especially for authentication or authorization, giving

somebody admin access, people overcomplicate this. They add features to it. Just don't do

it. It is a recipe for disaster. All right, so enough of that soapbox. Let's talk about

data validation. So I think this is the user on Discord, this is initially what they were

asking about is how do I validate data or filter data or escape data so it's safe to be in my

system. And this is where it seems like, I think I started here too where I was like, okay,

I get user data, I need to escape it right away and make sure it can never do anything dangerous.

And this can actually be dangerous in and of itself. Let me give you an example. Let's say

you have a system that stores data using SQL or something, right? Then later on, you send

this data back to the user, you render it using React or something, right? The way that you

escape data for putting it in an SQL query is different than the way

in React on the web. And in this case, maybe there's no conflicts, but maybe you have a

markdown parser, whatever. There's many different systems, right? And the thing is they all need

data to be escaped differently. So the approach that I think is safest is only escape and like

you should escape and then unescape data. when it goes in and out of systems. So when you're

putting data into your database, at the database library level or whatever, that should be automatically

escaped for you in the specific way the database needs it to be escaped for. And then when you

take that data out of the database, you generally want to un-escape it back to its original form.

So that at every layer, you're working with the data in its original form. And the reason

why this is important, like initially when I got into this, I was like, oh, okay, I just

want to escape it once right away when the user enters it, right? And then I'll be good forever

and I can just rest easy being like, my data is validated and it's good. I don't need to

worry about it. But what can happen is the way it gets escaped for one system could create

vulnerabilities in the next system's escaping thing, right? So let's say one system escapes,

you escape data by adding a double slash in front of it or something, or adding a slash

in front of slashes. Well maybe the next system sees that and thinks, oh, that's how you indicate

safe code to run, you know? So you just need to be super careful to not end up in those

situations. And that's where I tell people escaping and invalidation. should occur at the layer

that it's relevant for. Don't try to anticipate everything at the top layer. Don't be like,

okay, I'm going to escape it for SQL here, I'm going to also escape it for JavaScript here,

and whatever, right? Don't try to do that all up front. Do it at each layer and do it automatically.

And another reason for this is... You don't know how the data is going to be used in the

future. Somebody comes in later and might add a layer that does something that needs escaping

or on escaping, and they might not realize what you've already done to the data. Generally

things are done right. You shouldn't really need to worry about this. But I think we're

still at a state where you absolutely do. I have absolutely seen this many times over.

People are like, okay. the user enter data into the form, I'm going to escape it for rendering

out in React at this point. That doesn't make any sense, don't do it that way. So yeah, that's

my spiel on data validation. Now that's in my mind separate from, I guess I would call that

data sanitization. There's also what I would call data validation, like. Maybe when somebody

puts in their first name, we don't want it to be a bunch of random symbols, or we don't want

it to include certain things. In general, just because maybe it makes it confusing. Maybe

you're like, oh, people should only be able to enter their username as ASCII characters,

that way they can't use a Unicode character that looks like another character to try to

spoof names or something. That would be the way I would think of data validation. And that's

something you can do immediately when the data goes into the, you know, when you get it from

the form, from the client, you know, whatever. The other part is, and I forgot to mention

this, should have mentioned this, data validation should always happen on code that you control.

So validate and sanitize data only like on the server if you have a web application infrastructure.

Never, ever, ever rely on client-side validation or security. You can have client-side validation

where on the client you reject things and you tell the user, hey, this isn't valid. You need

a password that's longer. You need a password that includes this or whatever. But you never

trust that. You can't trust that because somebody could create their own clients, send their

own requests, You always have to do those things on the server or code that you control. Alright,

the next thing is libraries and external services. So this is a big one that people often don't

treat the same as the rest of their code, but if it's involved in your program, I consider

it from the security perspective to be the same. So keep your libraries up to date from security

vulnerabilities, which is a- pain in the JavaScript world, but that's how it is. That's an obvious

one. Keep things up to date. The next one is check security before adding things as dependencies

to your project. This one is kind of a pain. A lot of engineers I find, especially frontend

engineers, don't do this and don't want to do it. If you care about security, you should.

So you're like, hey, I want this library to do this thing for me. Take a few minutes at

a minimum and do a quick threat analysis. Look at the documentation, et cetera. I'll tell

you what I look for. So if I'm going to add a library or a service to my project, when

it comes to security, I look for a number of things. The first is, does this library have

documentation on how to implement the library securely. Most security vulnerabilities actually

come not necessarily from a vulnerability in the library itself, but people implementing

it wrong. Having really good documentation there that says, okay, this is how you do it securely

and correctly, don't do these things. I look for that in the docs. If it doesn't have that,

that makes me a lot more cautious Did the programmers think about security at all? How do I do this

securely? Are there things I should be aware of? If it doesn't say, I mean, that's a big

red flag to me. So good documentation will also include the types of attacks that the authors

are purposefully not addressing. And this is always gonna be the case. They might be like,

hey, this is something we don't feel it's our responsibility. You need to handle this on

your end or something. But basically at this stage, I'm just looking, does the documentation

include this information? If it doesn't, again, sort of a red flag where I'm like, do these

people know anything about security? Are they handling it, right? It's just sort of one of

those things that makes me spend longer researching it, you know? Let's see, the next one would

be, do they have a public policy in place for how they handle vulnerabilities? This is another

good indicator that they're paying attention to security. Kind of the last general thing

I look for is do they have good documentation on a high level approach they take towards

security and does it make sense? So basically everything should have this in some form or

another, even if it's just, hey, we don't really need to do anything for X, Y, Z reasons. It

just needs, there needs to be something. And like for say a library that has to do with

authentication, it should be like, okay, this is how we store data. This is how we manipulate

data. This is how we defend against these common attacks. That type of documentation needs to

and should exist in a high quality library or service that you might be integrating. As a

quick example on Discord, it was asked about the auth library and identity service called

Clert. like C-L-E-R-K. So I did this analysis real quick and my results were there were not

good documentation on how to securely implement it. It was pretty, almost nothing. And so that's

a huge red flag to me. There should be extremely explicit data on an authentication library

on how to securely implement it. That is like the first thing it should have is. To do this

securely, do things in this way. Follow these things, don't do these things. It did not have

good documentation on it, or if it did, I couldn't find it, which is just as bad. That needs to

be front and center. So I didn't like that. I also looked into sort of the high level approach

they took towards security, and that gave me some sort of, maybe not red flags, but like

orange flags, like sort of warnings too, because. This is something that you might not know if

you're not as familiar with security, but that's fine. They use some relaxed security policies

around session token storage that require extra work from the people implementing the library.

That in and of itself might be fine, but I don't feel like they highlighted this very well.

service and the company themselves. Since they're handling everything including session tokens,

identification, that type of stuff, but they really didn't provide hardly any details on

how they internally secure this information and manage it. They might do a fantastic job,

but I couldn't figure out if they do or don't or if they care or don't care. So this was

a pretty big red flag to me as well. And My overall conclusion was I would be pretty hesitant

to use a service like Clark for these reasons. I think there are better libraries and systems

available within the JavaScript ecosystem. Maybe it's fine. Maybe for your system you're like,

okay, all those things are fine. I don't really care. It's not a big deal. But personally I

was like, okay, there's a lot of red flags here. Anyway, so that's my approach for. how I look

at integrating libraries into my project. And I'll briefly touch on what I call external

services too. So this might be like Google Analytics or something where like they just give you

some code to put in your project or a library or whatever, but they're sort of like clerk

where they are handling everything for you. Your app might be the most secure thing in

the world, but if you're... giving other services access to run code on your system or whatever

that might be, they need to be just as secure as your thing. So you need to perform a threat

analysis with them or in some way keep that in mind. Let's say a few other things I'm going

to go over real quick are keep backups, but also do it securely. If. something goes wrong,

it's really nice to be like, oh, okay, maybe we don't understand everything yet, but we

can restore from a backup. Or you can use the backup to see what, maybe some data got changed

by a hacker, you can use the backup to look at that. So in general, backups are always

good to keep, it's also important for security. Another thing is keeping logs and intrusion

detection. Can you... find out if somebody did hack into your system. How do you know? What

did they do when they were in your system? So this is another aspect of security that often

gets overlooked. It's important to have mechanisms in place to detect when somebody has done something

unusual. Not gonna go into all that, you know, right now what that means, you can research

it yourself, but something to be aware of. Another great tip. piece of advice is don't store data

that you can't secure or that you don't want to put the effort into securing. This is an

easy one that I think a lot of people forget. When you get a feature request to capture some

new data, be like, hey, is it worth it from a security perspective? Maybe this data is

super valuable to a hacker. Are we going to invest in actually keeping it secure? And then

the last thing that I want to talk about is my approach to writing secure and safe code.

It's hard to keep all of this in mind all the time when you're writing code, right? But I

think there are a lot of things that we can do as engineers to just in general, write better,

more secure code. So what I always advocate for are systemic solutions. The first thing

is don't rely on programmers remembering to do things. If there's some part in your application

where you're getting data from the user and a programmer needs to remember to call some

method to sanitize that data, that's horrible. Don't do that. Figure out a way to architect

your system so it gets handled automatically at that layer or whatever it happens to be.

A lot of people, again... don't do this and it really bugs me because it's just too easy

to get it wrong. And, you know, whether it's in refactoring or some other engineer that

doesn't know about it, or you just forget. Don't rely on manual methods. Create systemic solutions.

Or create a library that just guarantees it always gets sanitized correctly at that level

without the programmer having to do anything special. That's the... absolutely critical

to just in general writing robust secure code. Another approach I use when writing code is

that things that seem like you can trust them but shouldn't be trusted should be explicitly

called out in that way. So an example would be a user supplied crypto address that money

can be sent to. where the expectation is that whenever that crypto transaction is executed,

the address is verified at that point. It's not necessarily, like you might verify it when

the user enters it into the system, but the security of your system relies on it being

verified each time a transaction actually occurs.

label that field in the database, like untrusted underscore crypto address or something. Just

so that, you know, anybody that doesn't really know how it works sees that and they're like,

oh, untrusted. What does that mean? You know, and maybe that you have a code comments and

other people on the team that knows what that means. But I just take this really defensive

approach where anything that seems like you can just grab it and use it, but you really

can't is explicit. everywhere in the code base. This helps a ton. It just makes it so it's

a lot harder to make silly mistakes where somebody's like, oh yeah, I just plopped the address in

here and created the transaction and sent the money over. And then somebody else is like,

what? You can't do that. You were supposed to do this other thing first and whatever. And

maybe you created this library to handle it for you, but somebody comes in to refactor

it and they don't know about that, you know? They should, but hey, the CEO wants this done

yesterday, right? We all know how it goes. So I try to like always do this in cases where

it's surprising, where you're like, oh, this is sort of unusual or surprising. I try to

call that out in any way I can. Another thing I do is assume the worst case scenario. So

like, I'll When I'm working on some level of the code, I'll just assume that all the security

before it failed and somebody is able to access the data. I look at it and go, what are the

consequences? Is there anything we can do to store less data or separate some of the data

into a different system or encrypt it per user account or something like that? So I just try

to have this general approach of, oh yeah, are other security mechanisms failed? What can

we do to make this specific layer more secure? And of course, like I mentioned before, complexity

is the enemy. Do not make things vastly more complex to try to make it more secure. Instead,

try to design better code. Complexity just creates more paths to secure and more code to understand.

And I call this out because the tendency when you find a potential vulnerability is to be

like, oh, we can plug this by adding this additional mechanism. But now you have to secure that

additional mechanism, which increases the surface area. And it's not like a linear thing either.

It's kind of like an exponential increase, the more code you add. So in my opinion, I always

push for like, you know, taking a deeper look at how you can re-architect the code to eliminate

the vulnerability altogether or secure against the vulnerability in a more systemic fashion.

This is really important. A lot of times, you'll find a vulnerability, and there'll be pressure

to just solve it right away. And the initial instinct will be, oh, let's add this extra

layer. Let's add this extra stuff. And maybe. That's what you do temporarily to just get

things moving and sort of more secure. But it's a really bad idea long term. Just try to resist

that urge. Try to be like, OK, is there some way we can do this where we don't need to make

it more complex? Complexity around security code is always a big red flag to me. If I get

into some code and I'm like, wow, they made this so complicated trying to make it secure,

it's like, I'm really unsure this is going to be very secure at all. There's just too much

to keep track of. And another just sort of final reminder is don't write or implement your own

cryptography. Unless you're crypto, I was going to say a crypto expert. That means something

different these days. Yeah, don't write this stuff on your own unless you know what you're

doing. Ideally, always use well-tested, well-documented libraries that handle security and authentication,

login, things like that for you. This is just, yeah. I don't find a lot of people end up trying

to do this because it seems overwhelming anyways, but I have. So yeah, do your best to not write,

just don't write your own crypto. Let, let. People that are experts at it do it. If you're

an expert, you'll know it, I guess, and you're fine, but for the rest of us, like just don't

do it. Don't be like, oh, this is too slow. I need to reimplement it in my language. That's

faster, whatever. Just don't do it. It's a bad idea. You're only gonna create headaches for

yourself. Use stuff that is well-documented, well-tested, has a good track record. Don't

do it yourself. All right, well that was a massive dump of information. Hopefully it's useful

to you and it gives you at least a starting point. Yeah, if you wanna know more about a

specific part of this, feel free to send me a message from the reactshow.com or come join

the Discord server. I'd love to hear more or if something wasn't clear, definitely let me

know. Yeah. I just want to thank you all once again for joining us. And if you've made it

this far and you want, definitely check out the premium feed, like I mentioned at the beginning,

or joining us on Discord. We'd love to have you there. Anything that we can do to support

each other, something I'm all for. Anyways, thank you so much for making it this far, joining

us. And and I hope you have a fantastic rest of your day. Bye.