Cybersecurity
A10 Server-Side Request Forgery
Server Side Request Forgery

A10:2021 - Server Side Request Forgery (SSRF)

ℹ️

For the information about Server Side Request Forgery (SSRF), visit page (opens in a new tab)

Server Side Request Forgery (SSRF)

πŸ”

CWE-918: Server Side Request Forgery (SSRF)

About

SSRF (Server-Side Request Forgery) vulnerabilities arise when a web application fails to verify the user-provided URL when requesting a remote resource. This flaw enables attackers to manipulate the application into sending a customized request to an unintended destination, even if the system is safeguarded by network access controls such as firewalls or VPNs.

Attack

πŸ’‘

As an attacker, you are going to try different URLs to access the internal resources of the application.

  1. For launching the attack, you are going to use Burp Suite, with which you have already familiarized yourself in the previous chapters.
  2. Open Burp Suite and in the designated browser, navigate to the http://localhost:3001/login.
  3. Log in with a valid user account.
  4. Right in front of you is an input field, which should be used to enter the URL of a patient`s Electronic Health Record (EHR). The application will then fetch the EHR from the URL and display it to the user.
  5. In the input field, enter the following URL: https://www.hack-health.tech/.
  6. In Burp Suite HTTP history, you can see that the web server has sent a request to the URL you entered and received a response.
nth-check package
ℹ️

POST request with a user-provided URL was sent to a /url route on a web server. When you navigate to the definition of /url route in the source code, you can see that the axios library is used to send a GET request to the provided URL and returns the response data to the client.

  1. Right-click on the request and send the request to Repeater.
  2. In the Repeater, change the URL to http://localhost:5000/health and send the request.
nth-check package
πŸ’‘

As you can see, we were able to access the /health route on the web server, which should not be accessible from the outside world.

  1. Now, in the Repeater change the URL to http://ifconfig.pro and send the request.
nth-check package
πŸ’‘

In the rendered response, you can see the IP address of the web server and some additional information. The public IP matches your IP address because the server is running locally. However, if the server was deployed, the information we will receive could serve as a valuable asset for an attacker.

Prevention

Whenever you are working with user-provided URLs, you should always make sure that the URL is valid and that it is not pointing to an internal resource. You can use the following technique to prevent SSRF attacks:

  1. In the externalSource.ts file, define a whitelist of allowed domains.
externalSource.ts
// Define a list of approved external domains
const approvedDomains = [
    "https://www.healthit.gov"
];
  1. Before requesting the URL, check if the URL is in the whitelist.
externalSource.ts
// Check if the requested URL is in the list of approved domains
const isApproved = approvedDomains.some(domain => url.startsWith(domain));
if (!isApproved) {
    throw new Error("Requested URL is not approved");
}
  1. Final implementation should be:
externalSource.ts
const express = require("express");
const router = express.Router();
const axios = require("axios");
 
// Define a list of approved external domains
const approvedDomains = [
    "https://www.healthit.gov"
];
 
router.post("/", async (req, res) => {
    try {
        const {url} = req.body;
 
        // Check if the requested URL is in the list of approved domains
        const isApproved = approvedDomains.some(domain => url.startsWith(domain));
        if (!isApproved) {
            throw new Error("Requested URL is not approved");
        }
 
        // Make a request to the URL provided by the user
        const response = await axios.get(url);
 
        // Return the response from the URL to the client
        res.send(response.data);
    } catch (error) {
        console.error(error);
        res.status(500).send("Something went wrong");
    }
});
 
module.exports = router;

Verification

  1. Into the input field, enter the following URL: http://localhost:5000/health.
  2. Open Developer Tools -> Console
  3. Submit the URL.
  4. In the console, you should see the following error:
nth-check package
  1. In the same way, you can try other requests used for attack, every time you should see the same error and failure to fetch the data.
  2. Try to enter a valid URL, for example, https://www.healthit.gov/faq/what-electronic-health-record-ehr. The application should fetch the data from the URL and display them in the console.
πŸ’‘

We have successfully implemented prevention from SSRF attacks. Now, the application will only allow requests to the domains defined in the whitelist, and any other internal or external URL will be rejected.

ℹ️

In this tutorial, we have only covered register endpoint, but in the next chapter, branch will already contain multiple other endpoints. The logic for creating them is almost the same. In the following chapters, we will also adjust the implementation to use middleware and jwt authentication.

Sources