 Alright, hello everybody. So let's talk about a Wasp top 10 security vulnerabilities in Node.js. So let me start by introducing myself, Markuipolito from Italy. I work at Neoform and I'm one of the Node.js collaborators. And generally speaking, I'm open source enthusiast. I like to use this term because I really like talking about open source and security. So what's a Wasp? Because a lot of people ask me why you have a Wasp as the beginning of your title. And a Wasp is one of the most important organizations that try to spread security awareness and improve the web ecosystem. And it's actually the acronym for open web application security project. It's a non-profit foundation and what they do is totally open source. So every year they provide rankings for the top 10 most critical web application security. So what they do is get experts from the field and do surveys to acknowledge which are the most common vulnerabilities that web developers have to try to avoid in their projects. And the ranking is not based on the frequency of the vulnerability, but also on treatment factor, which is frequency severity. So it means how big of an impact a vulnerability has on your web application. So severity and impact. So let's start with the 10th one, which is server-side request forgery. This category was added from the community survey. And it's basically when your application is fetching some resource, some remote resource without validating the user-supplied URL. What does it mean? Like the most common example is when your web application receives an URL, imagine like your profile picture. So the user tries to upload his profile picture to your web application, but he supplies something like sneaky trying to access some resources that otherwise wouldn't be accessible because your web application is fetching. We use Axios in this example to fetch and user provide URL and this user provide URL is malicious. So in this example, we have localhost 3001, but it could be almost everything depending on what the attacker tries to achieve. So it could fetch passwords, try to look into other services that are not exposed or whatever. And how can you what are the remediation for this kind of vulnerabilities? First of all, never trust user-supplied URLs. So you always have to sanitize the user input and validate it. Don't never send raw responses to the client because if you send the raw response, the client can understand which kind of errors you are getting or you can try to tinker the request to make it to try to access more resources and never, ever, ever always disable HTTP redirections because the client could try to sneak something that looks like a normal URL with something malicious and it could redirect to somewhere else that you don't want to. So let's go to number nine and this is like you will see that this security vulnerabilities are very closely related to each other. So if you have one, you might have orders of you might lack something to realize that you are being hacked. So this one is an example of not actually a vulnerability in your code but a lack of something that prevents hacker from accessing to react when you are being attacked. And security logging and monitoring failures was also added by the community and it's about like we all know that logging and monitoring is very hard for especially big application. So often we don't add logs or alarms that allow us to react quickly. So for example, we don't even notice that we are being hacked. And it's important to respond quickly to breaches and hackers attack. So an example of this one is for example, this was actually using Undishi and it was using a vulnerable version which is 5.0. So there was in this CVE that basically it explained that you could smuggle in the HTTP adder content type. You could smuggle another request. So it was basically using a vulnerability of the Node HTTP parser to do an HTTP smuggling attack. So it would perform that call. So your web application when received this kind of adder would perform another call and you would never ever realize this unless you have proper logging. Like you want to log everything that the user has supplied and you also have enough context to identify which user has supplied something. So for example, if you logged the content type and you also had a warn when for example someone tries to inject something that doesn't look right, we have added like validate content type. So if the content type is not valid, it means someone is trying to do something to your web application and then you want an alarm or you want to react quickly to that. Because if you have a vulnerability like in this example, that might be dangerous or you are exposed to all kinds of dangers. So let's go to the number eight, oh wait remediation. So you have to as I said, you have to make sure you always control like validate all the inputs and log everything that's user supplied and especially like important transactions such as faith logins or logins in general and make sure that for logs are in a format that's easy accessible and can be manipulated by log managers. For example, you have I don't know like centralized logging system. So usually you want to log in for example JSON format which is accessible to many log managers and also you want to have an alerting system. So when you find that someone might be potentially attacking your web application, you can react immediately. Let's go to the next one. This is software data and integrity failures. And so this is also like a general concept. For example, you're trying to like your CICD pipeline is insecure. So it's trying to pull malicious code or your whole CICD system is compromised. So for example, you are deserializing malicious code. So this is generally speaking when your data that you trust can be tampered by someone. And a big example was this not serialized package that allow you to basically what the JSON parse and JSON string if I does, but it was a third party dependencies and it contained a vulnerability that allowed an attacker to to inject some malicious code into the payload. So when you deserialized for example cookies and an attacker has inject malicious code, you would execute arbitrarily code. So an attacker could do anything, could execute any code on your machine because you're using insecure deserializing library. So how to prevent this? You want to make sure that data is not serialized or tampered. And you can do this by signing. For example, when you download the package, you want to show that it's signed. You want to calculate the hash of that package to make sure that you check the hash and you make sure that has not been modified. You want to make sure that libraries and dependencies come from trusted repository. Like we tend to download anything from the internet randomly, but that's very dangerous. And also as I said, you need to always check the digital signature to verify that the software has not been altered. And this is something very common and we don't like put a lot of attention into this just as like a few days ago it was like it was been published that tampered version of Fedora has been distributed for years and people took like 10 years to realize that package manager was distributing unofficial versions of Fedora for example. Because people don't check the hash, they don't check the digital signatures, so they just install stuff from the internet. Let's go to the next one. And this is, as I told you, is very similar to the ones that happened before. They are all interconnected. If you are doing something wrong, you open access to all sorts of vulnerabilities. This is about identification and authentication failures. For example, this happens when you cannot identify your user. You are not 100% sure that the user is actually who claims to be. So for example, your authentication system is broken or is not secure enough. Like you are not using multi-factor authentication, for example. Or you allow brute force attack on your logins. Or you'd never ask users to rotate their passwords. So if the password gets leaked, everybody could be impersonating that user because it's on the internet. So like what you want to avoid is that your application looks like this. So we all know among us the game where someone is an attacker and it's very hard to identify who the attacker is because their identity has been compromised. So how do we prevent this? Use multi-factor authentication. So we don't need to reinvent the wheel all the time. And if your application needs authentication, there are like hundreds of providers. It has been already done multiple times. So no need to implement something from scratch. Limit failed logins. Like you don't want attackers to perform a brute force on a user. So with multiple attempts, they could discover the password of someone. And you want to limit the failed logins. And also, as I said before, you want alerting. Like when someone is failing their login multiple times, you want an alert. You want to know, okay, something sketch is going on. I want to check. And you want to implement weak password check. You should never allow weak passwords. Like there was actually a survey a few years ago that and most people use the like password is the most common password on the internet. Like people will use their people are lazy. So they will use the like the simplest password. And you want to prevent that. You need to enforce that passwords are strong. And also you want to align like your past password length and complexity with the standard of NIST. So it's like a national Institute of Standards and Technology. And they have guidelines to make sure that you implement your password check correctly. So you don't have to invent a new kind of password checking system. It's everything standardized. You just have to follow the guidelines and make and the guidelines change not very often, but they change with time because machine get more powerful and passwords get leaked. And so you want to stay up to date with these policies. Next one is vulnerable and updated outdated components. This is also very common one. And like I like to talk about this because I've been working on Node.js to implement the dependency update automation. And the whole point is to avoid to use vulnerable and outdated components. So you want to have some kind of system that checks and has a workflow to update dependencies. For example, like we saw in the example before, we were using an outdated version of Wundishi, which is 5.8 that contained a vulnerability. And actually it contained multiple vulnerabilities. This is another one that the same package contained. And you could sneak into the origin, you could sneak another URL and it would execute another request. So it was very similar to the first one, but it's like updating dependency is very important. So you want to use tools to monitor the status of your dependencies. There are several tools and I will talk about it later about some tools that you can use. You also want to automate the dependency update workflow. And this is what the security team of Node.js has been doing for all the dependencies of Node. We created a workflow so that every time there is a new release, we open a pull request to add that new release. So even if there is a vulnerability, we always are up to date. So every week, we check if there are like CVEs or new releases and we are always up to date. Remove unused dependencies. So that's like the reason why we have unused dependencies because we don't check what our dependencies are. If we automate the checking dependency versions, we can see that some of them are stale for a long time or they are not maintained anymore, or we don't really need them. And unmaintained dependency means that someone could open a pull request and nobody will review it and probably could sneak some kind of malicious code into it. So you don't want to use outdated dependencies and you also make sure you don't use dependencies that you don't need for your project. So the tools that we can use to check that our project dependencies are safe and up to date is MyNotVulnerable by Raphael. This is your, yeah. It's a great one. So basically, if you have a dependency with a CVE, it will tell you that you are in danger. Otherwise, you are all good. You can use a sneak, which is not open-source, but it's free. So it tells you for all your dependencies that our CVE is associated. And there is also Retard.js, which was the most old-school one of the three. Going next, we have Security Misconfiguration. So when we set up our environments, we have databases, CI, CD, we have a lot of passwords and users to manage. But we have to change the default configurations and we have to use username and passwords that are actually strong and not vulnerable. Because if you use admin-admin, this is what your application looks like. This is the security of your application. We are not protecting anything. For example, I work on Fastify and they do a lot of patches on Fastify and most of the time, they are about cookies and sessions. Cookie is one of the most examples of very easy to forget about security configuration. So you always want to sign your cookies and use HTTP-only flag. You don't want to forget to implement these security features to the cookies in your web application. So going next, we have remediation. So as I said, different credentials should be using each environment. You want to automate the creation of your environment. You want to use tools like Terraform, Ansible, for example, because they make the environment repeatable. And this means it's also testable because every environment where you deploy your application is the same as the previous one. And this helps a lot with testability and repeatability of testing. Everything gets more predictable, so it's easier. It's easier to test and to verify configuration. We don't do that often, but we want to add tests to make sure that the security configuration are actually working. For example, with cookies, you want to have a test in your application that checks if cookies cannot be tampered and your application actually rejects them. Going to the fourth place, we have insecure design. Insecure design is also a general concept. It's not a vulnerability per se. It's basically the lack of security control in your architecture. Your software architecture is missing some security features that allow potential attackers. This is a meme that I found funny because we always have to make pillars on our web application, and these pillars, one of them is security. Security is something that you have to keep in consideration when building your architecture, and it's not something that you assert after you're being attacked. This is something you want to think about before because then it's too late and your data has been leaked or your database has been cancelled, and then it means that you lose money. So how to prevent this? You want to have model threat. We do this in Node.js. We know how to handle possible security vulnerabilities or how to handle situations and what we do to prevent being attacked. You want to use unit tests and integration tests to verify the threat model. So first you say, okay, this is what the potential threats to my application are, and then you add tests and verify that your application is not vulnerable to those threats that you identified. This is not something that you do once, and you say, okay, I'm done. No, you have to do this quite often because the software development cycle is something that continues. So you always add new libraries, new dependencies, you change your architecture. So you always want to reevaluate things and change things and improve them with time. Now we start to get to the top three, and they start to get the most juicy ones and probably you are more familiar with them. And at third place, we have injection. I think injection is my favorite one because it allows you to do almost anything, and the attacker has to have some kind of fantasy to write the queries for SQL injection. So it's something that always, like, I found it interesting. And an injection is basically when someone injects a malicious payload into your query or your code, and so your application is executing someone else's code or doing someone something that someone else has added in a payload. Let's have an example. This is the most common example when you have your SQL queries and you just concut user supplied data. And for example, you add the name to that query, the variable name, but you are not actually checking that variable is a name. So an attacker could make almost anything, like, it looks something like this. Like, you're not actually checking what the user supplied, just accepting everything and it's, you could accept something like this. This is the most common SQL injection that is basically on every book, one equals one, or it means give me everything on that table or column. So depending on your query. And this is very common, especially if you are using a query parameter and adding it directly into the query without checking or using SQL templating. So how do you prevent this? Validate user input. Most of the vulnerabilities that we saw here, it's because we don't validate user input. Never, ever trust what the user supplies. Always check and never use black listing. Always use white listing. So you always have like positive checking and not negative escape special characters. So this is also very common with HTTP smuggling too. So sometimes attackers try to add characters that are not recognized by your application and go into weird edge cases. And with that, they can try to access information or perform an issues operation. You always want to escape special characters and check that they are sanitized. And also avoid user supply table names or columns. When you create your queries, you want to define on which table you are querying. You don't want the user to supply or, for example, like you have on your URL products and you go on the table products. Like that's something that you want to avoid at all costs because user table names or columns cannot be escaped. So that's a thing that you have to keep in mind when building your application. On the second place, we have cryptographic failures. And this is also a general one. So basically using a week or not even using a cryptographic algorithm. And the most famous example of this is MD5. Don't use MD5 because it has been compromised a long time ago. So if you, for example, if you hash your table, your passwords on the database with MD5 and for some reason they are leaked, they could be like the original password can be reconstructed because there are some, actually there are, you can just Google it, tools that do the conversion and the decryption. So you want to use up-to-date and strong algorithms. You want to always, for example, the very common one is bcrypt that uses a salt. So that allows that when you actually encrypt your passwords, it's impossible for an attacker to go through the original password. Use proper key secrets management. How many of you pushed some kind of passwords on GitHub? Like some configuration files, some sensitive information. That's something that could happen, but you want to have proper key configuration management. You want to use environment five and not put everything into your source code. And you want to also disable caching for data that contains sensitive information because cache is something that could also be attacked or it could leak. So if you're caching information that are sensible, that's another way an attacker could possibly access this information. And on the first place, we have broken access control. So this one is the most common, by far, vulnerability of web application. So it's when a user can access or perform actions that they're not supposed or should be able to. It means that your API are not protected properly or they do not check who's actually performing that action. So an example could be when you check that you have the user has a token, but you don't check who actually is the user. So you just check the presence of the token, but you don't actually try to identify the user and authenticate him. So in this example, a user could access someone else's data just because they are logged in. This is very common and this has been stable on the OWASP top 10 for a few years. And we get vulnerabilities like this all the time, even from big companies because it's very hard to protect all your resources. So how do you prevent this? Deny by default. You want to deny access to your resources unless the specific condition is met, you don't want to do the opposite. Implement access control just once. You don't want to have multiple access control system, you just want one and you want to use it for all your application. Because if you use multiple access control system, it's easier to have failures of to forget to check something. And also tokens should be short lived. So if you use JWT tokens, you don't want them to last forever. Because if the token somehow is leaked, then everybody can do the same action without being authenticated. So you want tokens to be short lived, you want to them last as little as possible in order to prevent them. Even if an attacker gets a token, you cannot do much because he has a very short time window. And as we said before, you want to log access control failures. As you see, this has been repeated towards the all top 10 because it allows more vulnerabilities to come in. If you don't log, if you don't manage who's accessing your resources, you have broken access control, identity failures, so everything like all these vulnerabilities are connected to each other. And I think that was it for today. Thanks for listening. You can find my socials there. And thank you.