We recently failed a pen test due to our implementation of Identity Server 4 not preventing a replay attack. I have uploaded a simplified version of our setup to github to demonstrate what is going wrong. https://github.com/adriver-kwiboo/id4-replay-attack-demo
Here are the steps to replicate:
- Clone github repo
- In VS start multiple projects (IdentityServer + API)
- In VS Code navigate to Bebop.WebApp
- npm install
- npm start
- Get a trial version of BurpSuite Pro: https://portswigger.net/burp/pro
- Start a new temp project
- Proxy
- Options
- Make sure Intercept Server response is ticked
- On the Intercept tab
- Click open browser
- Navigate to http://localhost:3000
- Click Login button
- In Burpsuite click the "Intercept is off" to turn it on:
- Input "alice" as username and password
- In Burpsuite, Forward the first response
- You should get a 302 as the second response:
- Copy this response to Notepad
- Turn off Intercept, and it will continue you back into localhost:3000
- Click the Sign out button
- Navigate back to http://localhost:3000
- Click the Sign in button
- Turn on Intercept back in Burpsuite.
- Input an invalid username / password
- Forward the first response
- On the 200 response, where it displays the invalid username / password. Replace the response, with the text you previously copied into Notepad
- Turn off Intercept
- You will get an error page
- Navigate to http://localhost:3000
- Click the Sign in button
- You will see that you are not prompted for the username / password, but instead logged straight in.
Is there something I am missing in my implementation? Or is this a limitation of Identity Server? My expectation would be that if you tried to login with a previous response, it would validate that the response did not match the request and prevent logging in.
The oidc-client.js is checking something, as it throws the error about no matching state. Should the front-end then inform the backend of the failure and remove the successful token from ID server? This feels like it could be intercepted as well, and ignored.