Insecure Direct Object Reference (IDOR) is one of the more simple vulnerabilities to understand and create automated testing for, which also makes it easier for an attacker to exploit.

IDOR is a common example of a broken access control vulnerability, which is a category of vulnerabilities which currently sits at top spot on the OWASP Top 10. This type of vulnerability occurs when an application accepts user input which is then used as a direct reference to an object without sufficient authorization mechanisms and checks in place.

An IDOR vulnerability in your application could lead to a data breach, by allowing unauthorised access to sensitive data, functionality, or resources, as a result of weaknesses in the access control mechanisms you have in place.

A simple IDOR example

The following code represents an example React website, which accepts an account ID as part of the URL. This account ID is then used to retrieve customer data from a Lambda backed ApiGateway, and subsequently relays that information in the response sent to the user, which is then displayed within their browser. 

However, in this example there is a lack of sufficient user input validation, and a malicious user could change the account ID value to retrieve the data of other customers.

Frontend

<Routes>
    <Route
        path='/profile'
        element=<Profile />
    />
</Routes>

export const Profile = () => {
    const id = window.location.href.substring(
        window.location.href.lastIndexOf('/') + 1,
    )
    const [user, setUser] = useState<User>()

    useEffect(() => {
        const data = get(`/account/${id}`)
        data.then(data => {
            setUser(data)
        })
    })

    return <div>Hi {user.name}!</div>
}

Backend

export const handler = async(
    event: APIGatewayProxyEvent
) : Promise<APIGatewayProxyResult> => {
    const id = event.pathParameters.proxy!

    try {
        const data = await getUserData(id)

        return {
            statusCode: 200,
            body: JSON.stringify(data)
        }
    } catch (err) {
        console.error('error', err)
    }
}

Using the above example application, we can enumerate account IDs to access any user’s account we desire. The user with account ID 1001 can navigate to https://example.com/profile/1002 to retrieve the user data relating to account ID 1002. This is allowed as we do not check the user making the request has the account ID we’re retrieving the data for.

Mitigating IDOR vulnerabilities

We can mitigate against IDOR vulnerabilities by validating user input, implementing adequate access controls, and denying by default to ensure that a user can only access their own data.

To achieve this a common example is to pass a JWT, which can be verified against an identity provider to ensure the user is successfully authenticated. This process is simple when using a Lambda Authorizer in AWS, especially with Amazon Cognito, as it will only allow authenticated users with the required permissions to make a request to the Lambda, without you needing to write any middleware code.

Once we have confirmed the identity of the user making the request, we can check that their identifier matches the identifier for the user data being requested. We can also perform further authorization checks to ensure that the requester has permissions to access the data in question, if not already captured by a Lambda Authorizer. If that is not the case we can return a 403 status code and mitigate the risk of IDOR vulnerabilities.

A real world example

A famous example of an IDOR vulnerability is the First American Financial Corp data leak, which exposed the records of over 800 million customers back in 2019, which resulted in a fine of $487,616. Although substantial, this fine would be significantly larger with modern day regulation.

You can read more about the First American Financial Corp data leak here: https://www.forbes.com/sites/ajdellinger/2019/05/26/understanding-the-first-american-financial-data-leak-how-did-it-happen-and-what-does-it-mean/

Useful Resources