drogonframework / drogonframework/drogon
`drogon::app().forward(...)` persists previous response cookies to future cookies on fail
- Dominant language
- C++
- Stars
- 14.3k
- Forks
- 1.4k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 14
Description
**Describe the bug**
So I was testing some code locally and don't have the 2nd backend up for it to be forwarded to, and all forward requests end up failing which is what I'm expecting to happen.
However, I noticed weird behaviors of cookies sometimes setting and not setting, or having multiple points of the code just start behaving randomly.
I started debugging it and found no fault on my application code, so I started investigating different parts of Drogon calls and found that the forward function of Drogon when it fails it keeps the response cookies of the first failed request and just keeps it in memory for all future calls within the further end of the AOPs.
For context, the application code is made to set the cookies on the pre-sending AOP advice, and only when these cookies don't exist in the request or the response. Meaning if either one has the cookies, it won't do anything.
Here is the log for code containing the forward function to a host that isn't up:
```sh
Sync: /
Request cookies:
Pre-routing: /
Request cookies:
Post-routing: /
Request cookies:
Pre-handling: /
Request cookies:
Post-handling: /
Request cookies:
Response cookies:
Pre-sending: /
Request cookies:
Response cookies:
a = 2
A = 44
Sync: /favicon.ico
Request cookies:
a = 2
Pre-routing: /favicon.ico
Request cookies:
a = 2
Post-routing: /favicon.ico
Request cookies:
a = 2
Pre-handling: /favicon.ico
Request cookies:
a = 2
Post-handling: /favicon.ico
Request cookies:
a = 2
Response cookies:
a = 2
A = 44
Pre-sending: /favicon.ico
Request cookies:
a = 2
Response cookies:
a = 2
A = 44
```
Notice how the favicon request's response cookies appeared out of nowhere in Post-handling advice and persisted to Pre-sending advice.
Now I went to replace the line responsible for the forwarding like this:
```c++
// drogon::app().forward(std::move(req), std::move(callback), "http://127.0.0.1:8080");
callback(HttpResponse::newHttpResponse()); // Return something, don't fail
```
And the log changed to this:
```sh
Sync: /
Request cookies:
Pre-routing: /
Request cookies:
Post-routing: /
Request cookies:
Pre-handling: /
Request cookies:
Post-handling: /
Request cookies:
Response cookies:
Pre-sending: /
Request cookies:
Response cookies:
a = 2
A = 44
Sync: /favicon.ico
Request cookies:
a = 2
Pre-routing: /favicon.ico
Request cookies:
a = 2
Post-routing: /favicon.ico
Request cookies:
a = 2
Pre-handling: /favicon.ico
Request cookies:
a = 2
Post-handling: /favicon.ico
Request cookies:
a = 2
Response cookies:
Pre-sending: /favicon.ico
Request cookies:
a = 2
Response cookies:
```
As observed, no response cookies are present anywhere except for the first request on /.
**To Reproduce**
Steps to reproduce the behavior:
1. Return a cookie in post-sending advice if that cookie doesn't exist in the request or the response.
2. Forward all requests to a non-existing host.
3. Notice how after the first failed request all subsequent responses will contain the first set cookie.
**Expected behavior**
Nothing should be set when it fails, or it shouldn't reuse the last response.
I deem this a security vulnerability ¯\\_(ツ)_/¯
Contributor guide
Assessment
This issue has not been assessed yet.