Course / 09 Web security / Lesson 11 of 28

Server-side request forgery

Estimated time: 16 min reading · 12 min activity

A preview or import feature may fetch a URL supplied by its user. Server-side request forgery, or SSRF, happens when untrusted input causes the server to make an unintended request. The browser supplies the address, but the server uses its own network access and permissions to fetch it.

An internal service may be reachable from that server even when the user's browser cannot reach it. An allowlist states which destinations are permitted. In this model the allowed destination has scheme http, host 127.0.0.1 and port 8000. Treat that as a fictional fetch policy; no URL here should be requested.

Before you begin

Estimated time
16 min reading, 12 min activity. Setup and optional practice may take longer.
Where you work
Read the original fictional requests, source fragments and state tables in a current desktop or mobile browser. The required activity needs no server, database, account or installed security tool. Do not send the printed requests to any service.
Without a lab
Use the complete printed evidence to trace the data or state on paper. Write the decision, the fact supporting it and one limit of the model, then compare with the activity rubric. This does not establish live service behavior. Reading works without JavaScript. Checking requires JavaScript and a secure browser context; saving also requires usable browser storage.

After this lesson you can:

  • Point to the component that would download the worked destination.
  • Classify the two activity destinations against the allowlist.
  • Keep every name unrequested.

01Example

This fictional flow shows who would perform a destination request. Do not contact the example internal name.

Caller supplies: http://desk-metadata.internal/label
Application receives the submitted URL.
Backend fetcher would request that destination.
Policy decision must happen before the backend request.
No request was sent.

02Who fetches

Follow the components rather than the appearance of the form. The caller chooses a URL, the application receives it, and the backend fetcher would contact the destination. That boundary can expose internal responses or trigger unintended actions if the fetcher trusts arbitrary destinations.

Prefer fixed destinations or a narrow allowlist, compare parsed scheme/host/port, and limit outbound network access. Redirects and DNS resolution need checks too because they may change the eventual destination. The card omits those operations. A browser's same-origin reading rule does not constrain requests made by a backend process.

See that the caller supplies an address and the backend would be the component that fetches it.Model. A teaching model drawn by hand. It shows the idea, not real tool output.

Read the full explanation below.

Playback is optional. Step through at your own pace.

CallerSupplies data; does not fetch in this model.
ApplicationReceives the submitted URL.
Backend fetcherWould make the server-side destination request after policy.
Submitted destinationSubmitted destination only; no request was sent.
  1. Caller → ApplicationSubmitted URLhttp://desk-metadata.internal/label
  2. Application → Backend fetcherWould request a fetchThe backend would act as the network requester.
  3. Backend fetcher → Submitted destinationWould request destinationNo request was sent; destination policy must be decided first.
Before-request destination policy
pending

The caller supplies a destination URL.

Follow the explanation

  1. The caller supplies a destination URL.
  2. A backend fetch would use the server-side requester.
Read every state and value

1. The caller supplies a destination URL.

Messages shown
Submitted URL
Current message
Submitted URL
Policy decisions
Status: pending
Participant roles
Actor: caller; Text: Supplies data; does not fetch in this model. · Actor: Application; Text: Receives the submitted URL. · Actor: Backend fetcher; Text: Would make the server-side destination request after policy. · Actor: Submitted destination; Text: Submitted destination only; no request was sent.

2. A backend fetch would use the server-side requester.

Messages shown
Submitted URL · Would request a fetch
Current message
Would request a fetch
Policy decisions
Status: not-established
Participant roles
Actor: caller; Text: Supplies http://desk-metadata.internal/label as data. · Actor: Application; Text: Receives the submitted URL. · Actor: Backend fetcher; Text: Policy must happen before any destination request. · Actor: Submitted destination; Text: No fetch message is released; no destination contacted.
The server would fetch the destination; a browser reading rule does not authorize or constrain this backend action.

03Classify the activity destinations

Read the evidence before comparing your reasoning with the activity rubric. Send nothing.

Original flow. No request was sent.

Browser shows a form.
The form field contains a destination written by the caller.
The backend is the component that would download that destination.
The browser supplied the address. The backend would perform the fetch.

Fictional destination on the worked card: http://desk-metadata.internal/label
That name is not a host to contact. It stands for a service the browser cannot see
and the backend might reach if it fetched caller-supplied addresses.

Activity destinations, also not to be requested:
  http://127.0.0.1:8000/note.txt is on the allowlist card
  http://files.club.internal/note is not on the allowlist card

Download the fetch flow

Outbound policy for the backend fetcher.

Allowlist: http://127.0.0.1:8000/ and paths under it.
Anything else is not fetched.
A prefix of the text is not enough: the card compares the scheme, host, and port
as separate parts. This lesson does not send either URL.

Browser page loads that the browser makes for itself are outside this allowlist.
Those loads are the browser's own requests.

Download the allowlist

  1. Write which component would perform the download.
  2. Mark the activity URL that matches scheme, host, and port 8000 on the loopback name. Mark the other URL.
  3. Check: the note.txt URL is on the allowlist. The files.club.internal URL is not. The worked metadata name is not on the list either.
  4. Stop. Do not send any of these names.

04Optional challenge

Explain why a browser rule against reading another origin does not stop the backend fetch. The rubric is: the browser rule binds the browser, and the fetcher is the backend. About ten minutes.

05Fresh cases for the checks

Use these fictional cases for the checks below. They have different inputs from the worked examples. Read them here or make notes; no installation or external service is needed.

Fetcher case A: new fictional flowOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

1. A browser submits a destination string to a notes application.
2. The application passes an approved destination to its backend downloader.
3. The downloader would request the content and return it to the application.
This is a flow model only; do not request any destination.

Fetcher case B: independent parsed-destination ruleOwned fixture. An original file made for this course. Follow the activity's instructions in your own lab.

Allow only scheme http, host 127.0.0.1, port 8000. Paths under / are allowed.
P: http://127.0.0.1:8000/notice
Q: https://127.0.0.1:8000/notice
R: http://127.0.0.1:9000/notice
No redirects or DNS changes are modeled; a real policy must account for eventual destinations too.

06Explain your evidence

Optional written self-check: explain one decision using the supplied case. No tool run is required.

Check your explanation: separate who supplies the URL from who fetches it; compare parsed scheme/host/port; place enforcement before the backend request; name redirects and resolution as real-policy limits without sending anything.

07Common mistakes

If you treat the form as the fetch, you stopped at the component that supplied the address.

If you allow files.club.internal because it contains the word note, you used a text prefix. The card compares scheme, host, and port.

If you request the metadata name, you left the lesson. It is not a host to contact.

References

  • RFC 6454: The Web Origin Concept

    Sections 3.2 and 5. Reading another origin is generally forbidden in the browser, and sending is a separate allowance. This lesson uses that limit only to say a browser rule does not bind the backend fetcher.

  • PortSwigger: SSRF

    Explains the failure mechanism and prevention. Use it for further reading after reasoning from this page's original model; a topic page is not evidence that a lab was launched.