|
| 1 | +# Other Security Vulnerabilities and Practices |
| 2 | + |
| 3 | +In this lesson, we will go over different attack trajectories and vulnerabilities. Some are from the list of the [OWASP Top 10](https://owasp.org/www-project-top-ten/). |
| 4 | + |
| 5 | +This document is intended to help you know where to go look patterns and visualize the security of your app. It is a non exhaustive list not to mention that it should be revised anually. |
| 6 | + |
| 7 | +In this lesson you will learn about: |
| 8 | + |
| 9 | +- Cross-site request forgery |
| 10 | +- Database Security & Injection attacks |
| 11 | +- End-to-end encryption |
| 12 | +- Rate limiting |
| 13 | + |
| 14 | +## Cross-site request forgery (CSRF) |
| 15 | + |
| 16 | +[CSRF](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application. |
| 17 | + |
| 18 | +### How does it work? |
| 19 | + |
| 20 | +For a [CSRF](https://portswigger.net/web-security/csrf) attack to be possible, three key conditions must be in place: |
| 21 | + |
| 22 | +- **A relevant action**. There is an action within the application that the attacker has a reason to induce. This might be a privileged action (such as modifying permissions for other users) or any action on user-specific data (such as changing the user's own password). |
| 23 | +- **Cookie-based session handling**. Performing the action involves issuing one or more HTTP requests, and the application relies solely on session cookies to identify the user who has made the requests. There is no other mechanism in place for tracking sessions or validating user requests. |
| 24 | +- **No unpredictable request parameters**. The requests that perform the action do not contain any parameters whose values the attacker cannot determine or guess. For example, when causing a user to change their password, the function is not vulnerable if an attacker needs to know the value of the existing password. |
| 25 | + |
| 26 | +For example, suppose an application contains a function that lets the user change the email address on their account. When a user performs this action, they make an HTTP request like the following: |
| 27 | + |
| 28 | +```js |
| 29 | +app.post("/email/change", async (req, res) => { |
| 30 | + const userId = req.session.user.id; |
| 31 | + const user = await User.findOne(userId); |
| 32 | + const { newEmail } = req.body; |
| 33 | + if (!userId || !user) { |
| 34 | + return res.status(403).end(); |
| 35 | + } |
| 36 | + |
| 37 | + user.email = newEmail; |
| 38 | + await user.save(); |
| 39 | + res.status(200).end(); |
| 40 | +}); |
| 41 | +``` |
| 42 | + |
| 43 | +If this app is not protected against CSRF, it meets the conditions required for CSRF: |
| 44 | + |
| 45 | +- The action of changing the email address on a user's account is of interest to an attacker. Following this action, the attacker will typically be able to trigger a password reset and take full control of the user's account. |
| 46 | +- The application uses a session cookie to identify which user issued the request. There are no other tokens or mechanisms in place to track user sessions. |
| 47 | +- The attacker can easily determine the values of the request parameters that are needed to perform the action. |
| 48 | + |
| 49 | +With these conditions in place, the attacker can construct a web page containing the following HTML: |
| 50 | + |
| 51 | +```html |
| 52 | +<html> |
| 53 | + <body> |
| 54 | + <form action="https://vulnerable-website.com/email/change" method="POST"> |
| 55 | + < input type= "hidden" name= "newEmail" value= "[email protected]" /> |
| 56 | + </form> |
| 57 | + <script> |
| 58 | + document.forms[0].submit(); |
| 59 | + </script> |
| 60 | + </body> |
| 61 | +</html> |
| 62 | +``` |
| 63 | + |
| 64 | +If a victim user visits the attacker's web page, the following will happen: |
| 65 | + |
| 66 | +- The attacker's page will trigger an HTTP request to the vulnerable web site. |
| 67 | +- If the user is logged in to the vulnerable web site, their browser will automatically include their session cookie in the request (assuming `SameSite` cookies are not being used). |
| 68 | +- The vulnerable web site will process the request in the normal way, treat it as having been made by the victim user, and change their email address. |
| 69 | + |
| 70 | +### Preventing CSRF attacks |
| 71 | + |
| 72 | +The most robust way to defend against CSRF attacks is to include a [CSRF token](https://portswigger.net/web-security/csrf/tokens) within relevant requests. The token should be: |
| 73 | + |
| 74 | +- Unpredictable with high entropy, as for session tokens in general. |
| 75 | +- Tied to the user's session. |
| 76 | +- Strictly validated in every case before the relevant action is executed. |
| 77 | +- An additional defense that is partially effective against CSRF, and can be used in conjunction with CSRF tokens, is SameSite cookies. |
| 78 | +- Implement CORS policies |
| 79 | + |
| 80 | +> 💡 TIP: In express based web apps, you can use the middleware library [`csurf`](http://expressjs.com/en/resources/middleware/csurf.html) to enforce CSRF Tokens in your apps. You can also use [`cors`](https://expressjs.com/en/resources/middleware/cors.html) to enforce CORS policies. |
| 81 | +
|
| 82 | +## Databse security |
| 83 | + |
| 84 | +Database security can be discussed in two folds: |
| 85 | + |
| 86 | +- How to mitigate attacks against the database server itself |
| 87 | +- How to mitigate attacks through your server backend app |
| 88 | + |
| 89 | +### Attacks against database server |
| 90 | + |
| 91 | +[Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html) |
| 92 | + |
| 93 | +A database server is the system that hosts your database. It offers access points and tools as API for applications to interact with the database. Lack of security configuration, or malconfig can pose a great threat that risks giving access to databases. |
| 94 | + |
| 95 | +Below are the common facets of database server that should be secured: |
| 96 | + |
| 97 | +- [Connection](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#connecting-to-the-database) |
| 98 | + - [Transport Layer Protection](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#transport-layer-protection) |
| 99 | +- [Authentication](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#authentication) |
| 100 | + - [Credentials storage](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#storing-database-credentials) |
| 101 | +- [Permissions](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#permissions) |
| 102 | +- [Configurations and Hardening](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html#database-configuration-and-hardening) |
| 103 | + |
| 104 | +#### Database connection |
| 105 | + |
| 106 | +Before securing our backend app, it is of utmost security to secure the database server itself, since most attackers will try to access the database api directly over network. Thus it is important that the backend database used by the application to be isolated as much as possible, in order to prevent malicious or undesirable users from being able to connect to it. Exactly how this is achieved will depend on the system and network architecture. The following options could be used to protect it: |
| 107 | + |
| 108 | +- Disabling network (TCP) access and requiring all access is over a local socket file or named pipe. |
| 109 | +- Configuring the database to only bind on localhost. |
| 110 | +- Restricting access to the network port to specific hosts with firewall rules. |
| 111 | +- Placing the database server in a separate [demilitarized zone (DMZ)](https://www.fortinet.com/resources/cyberglossary/what-is-dmz) isolated from the application server. |
| 112 | + |
| 113 | +Similar protection should be implemented to protect any web-based management tools used with the database, such as phpMyAdmin. |
| 114 | + |
| 115 | +#### Stroing Database Credentials |
| 116 | + |
| 117 | +Database credentials should never be stored in the application source code, especially if they are unencrypted. Instead, they should be stored in a configuration file that: |
| 118 | + |
| 119 | +- Is outside of the webroot. |
| 120 | +- Has appropriate permissions so that it can only be read by the required user(s). |
| 121 | +- Is not checked into source code repositories. |
| 122 | + |
| 123 | +Where possible, these credentials should also be encrypted or otherwise protected using built-in functionality, such as the web.config encryption available in ASP.NET. |
| 124 | + |
| 125 | +> 💡 TIP: Most database systems come with a security checklist to ensure your database server is secure. Checkout this security checklist for [MongoDB](https://docs.mongodb.com/manual/administration/security-checklist/). |
| 126 | +
|
| 127 | +### Injection attacks |
| 128 | + |
| 129 | +[Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) |
| 130 | + |
| 131 | +Injection attacks target the web app or the backend server through its interaction with the database. The most prominent is [SQL injection](https://portswigger.net/web-security/sql-injection) which is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows an attacker to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access. In many cases, an attacker can modify or delete this data, causing persistent changes to the application's content or behavior. |
| 132 | + |
| 133 | +#### Example: Revealing hidden data |
| 134 | + |
| 135 | +Imaging having an ecommerse application that has an endpoint that display products by categories. Some of these products are _unreleased_ yet, so they shouldn't show up in the results. |
| 136 | + |
| 137 | +```js |
| 138 | +// /products?category=Digital |
| 139 | +app.get("/products", async (req, res) => { |
| 140 | + const { category } = req.query; |
| 141 | + const SQL = `SELECT * FROM products WHERE category = '${category}' AND released = 1`; |
| 142 | + const results = await db.query(SQL); |
| 143 | + |
| 144 | + res.json(results); |
| 145 | +}); |
| 146 | +``` |
| 147 | + |
| 148 | +This SQL query asks the database to return: |
| 149 | + |
| 150 | +- all details `*` |
| 151 | +- from the `products` table |
| 152 | +- where the `category` is Digital |
| 153 | +- and `released` is 1. |
| 154 | + |
| 155 | +The application doesn't implement any defenses against SQL injection attacks, so an attacker can construct an attack like: |
| 156 | + |
| 157 | +``` |
| 158 | +https://insecure.com/products?category=Digital'-- |
| 159 | +``` |
| 160 | + |
| 161 | +This results in the SQL query: |
| 162 | + |
| 163 | +```SQL |
| 164 | +SELECT * FROM products WHERE category = 'Digital'--' AND released = 1 |
| 165 | +``` |
| 166 | + |
| 167 | +If syntax highlighting is working correctly, you will probably notice the difference right away. The addition of `--` in SQL means what ever follows in this line is a comment and should be ignored! This effectively removes the remainder of the query, so it no longer includes `AND released = 1`. This means that all products are displayed, including unreleased products. |
| 168 | + |
| 169 | +Going further, an attacker can cause the application to display all the products in any category, including categories that they don't know about: |
| 170 | + |
| 171 | +``` |
| 172 | +https://insecure.com/products?category=Gifts'+OR+1=1-- |
| 173 | +``` |
| 174 | + |
| 175 | +This results in the SQL query: |
| 176 | + |
| 177 | +```sql |
| 178 | +SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1 |
| 179 | +``` |
| 180 | + |
| 181 | +The modified query will return all items where either the category is Gifts, or 1 is equal to 1. Since 1=1 is always true, the query will return all items. |
| 182 | + |
| 183 | +Checkout more examples in [this article](https://portswigger.net/web-security/sql-injection). |
| 184 | + |
| 185 | +### Preventing SQL Injection |
| 186 | + |
| 187 | +First and foremost, try to use an ORM, it solves most of these problems for you. And never construct a query by string concatenation or interpolation. |
| 188 | +The cheatsheet from OWASP has a good compilation for best practices. We will summarize it here |
| 189 | + |
| 190 | +- Use Prepared Statements (with Parameterized Queries) |
| 191 | +- Use Stored Procedures |
| 192 | +- Use Allow-list Input Validation |
| 193 | +- Escaping (Sanitizing) All User Supplied Input |
| 194 | + |
| 195 | +Most ORMs offer a query preparation methods, that help you write a query with placeholder that get filled (replaced) later. For example in [Sequlize](https://sequelize.org/master/manual/raw-queries.html#replacements): |
| 196 | + |
| 197 | +```js |
| 198 | +// /products?category=Digital |
| 199 | +app.get("/products", async (req, res) => { |
| 200 | + const { category } = req.query; |
| 201 | + |
| 202 | + const SQL = |
| 203 | + "SELECT * FROM products WHERE category = :category AND released = :released"; |
| 204 | + |
| 205 | + const PARAMS = { |
| 206 | + replacements: { category, released: "1" }, |
| 207 | + type: QueryTypes.SELECT, |
| 208 | + }; |
| 209 | + |
| 210 | + const results = await sequelize.query(SQL, PARAMS); |
| 211 | + |
| 212 | + res.json(results); |
| 213 | +}); |
| 214 | +``` |
| 215 | + |
| 216 | +## End-to-end encryption (E2EE) |
| 217 | + |
| 218 | +End-to-end encryption is a secure way to communicate privately and securely online. By encrypting communication at both ends of a conversation, end-to-end encryption prevents anyone in the middle from reading private communications. |
| 219 | + |
| 220 | + |
| 221 | + |
| 222 | +Imagine building a meetings application that have your server in the middle to fascilitate communication, and at least 2 or more clients connected to the server in a meeting session. |
| 223 | + |
| 224 | +The client would record audio, video, and chat messages, and send them to the server. The server then send this data to the other clients connected to this meeting session. This back and forth communication is all fascilitated by your server. |
| 225 | + |
| 226 | +When your server implement E2EE, it needs to fascilitate client's handshake and encryption keys exchange. This is mainly to exchange Public Keys of clients to encrypt the outward communication. Any video, audio, or text sent should be encrypted using a public key. Then when it is received, it can be decrypted using the private key associated with the public key. |
| 227 | + |
| 228 | +### Advantages of E2EE |
| 229 | + |
| 230 | +- Safe against hacks: All stored data are encrypted. In case the server was breached, an attacker will have a pile of gibberish |
| 231 | +- More privacy: No one will be to read your data except you. |
| 232 | + |
| 233 | +### Disadvantages of E2EE |
| 234 | + |
| 235 | +- Services won't be able to offer features to enhance your data, like offering transcript feature to your meetings, or recommendations and suggestions. |
| 236 | +- Measure to store and rotate encryptions keys are required. If by accident a user lost their key, they will effectivley lose all their data |
| 237 | + |
| 238 | +## Rate Limiting |
| 239 | + |
| 240 | +Rate limiting is a strategy for limiting network traffic. It puts a cap on how often someone can repeat an action within a certain timeframe – for instance, trying to log in to an account. |
| 241 | + |
| 242 | +Rate limiting can help stop certain kinds of malicious bot activity. It can also reduce strain on web servers. |
| 243 | + |
| 244 | +In express, you can use a middleware like [`express-rate-limit`](https://www.npmjs.com/package/express-rate-limit) to control this behavior. This is a necessity especially for API to limit computerized bots from breaking your api server. |
| 245 | + |
| 246 | +You can also use [CAPTCHA](https://www.pandasecurity.com/en/mediacenter/panda-security/what-is-captcha/) to for Non-API server apps to make sure some certain actions are only done by humans. |
| 247 | + |
| 248 | +A library like [`express-recaptcha`](https://www.npmjs.com/package/express-recaptcha) can be used to add CAPTCHA to your app. |
| 249 | + |
| 250 | +You can also use cloud services that are built to mitigate such attacks like [CloudFlare](https://www.cloudflare.com/learning/bots/what-is-rate-limiting/). They proxy your app through extensive security tests and practices to ensure your server won't go down due to bot attacks. |
| 251 | + |
| 252 | +## Further reading |
| 253 | + |
| 254 | +- REST Security [cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html) |
| 255 | +- [Serverside request forgery](https://portswigger.net/web-security/ssrf) (SSRF) & [cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html) |
| 256 | +- [Cross-site scripting](https://portswigger.net/web-security/cross-site-scripting) (XSS) & [cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html) |
| 257 | +- [OAuth 2.0 authentication vulnerabilities](https://portswigger.net/web-security/oauth) |
0 commit comments