0

I'm experiencing a strange error in my phorum server - seemingly at random, some users will be swapped with each other, and find themselves fully logged in as one another, with complete access to one another's accounts. I've experienced this bug myself once but cannot recreate it.

Phorum is configured to track sessions via cookie, with the session hashes also stored in the user database. I've confirmed the database is intact and there aren't session ID collisions happening.

You can see the source for phorum's authentication and session management here, it's fairly straightforward. Sessions are only created via log-in or from existing cookies so my working theory (after talking to a phorum developer) is that there is some sort of caching issue on the server. There's a known caching issue that affects ASP (see here or here for examples) but my server is a Linux server running Apache 2.4, MySQL (technically MariaDB 10.1 + InnoDB) and PHP 5.6. Is anyone aware of how this might be happening? I've been plugging away at this for over a week and have made little progress other than confirming the lack of bugs in the phorum session code.

The only clue I have to go on is that the session swapping started on the same day my hosting service took down (and restored) their file servers. They said they don't see how that could be responsible, however.

EDIT #1: I am adding some request and response headers.

Here is the response for an initial GET to get a list of forums. General

Request URL: https://www.example.com/forum/list.php?11 Request

Method: GET Status Code: 200 Remote Address: x.x.x.x:443

Referrer Policy: no-referrer-when-downgrade

Response Headers

content-encoding: gzip content-type: text/html;

charset=UTF-8 date: Mon, 07 May 2018 20:23:08 GMT server: Apache

set-cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9; expires=Tue, 08-May-2018 20:23:08 GMT; Max-Age=86400; path=/

status: 200 vary: Accept-Encoding via: e3s

Request Headers

:authority: www.example.com

:method: GET

:path: /forum/list.php?11

:scheme: https

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8

accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9

cache-control: max-age=0

cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9;

referer: https://www.example.com/forum/addon.php?11,module=user_list

upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36

And here is a follow-up Ajax call:

General

Request URL: https://www.example.com/forum/ajax.php?client

Request Method: GET Status Code: 200 (from memory cache)

Remote Address: x.x.x.x:443 Referrer Policy: no-referrer-when-downgrade

Response Headers

age: 734

cache-control: must-revalidate

content-encoding: gzip

content-length: 2862

content-type: text/javascript;charset=UTF-8

date: Mon, 07 May 2018 18:29:37 GMT

expires: Tue, 08 May 2018 02:29:37 GMT

pragma: cache

server: Apache

status: 200

vary: Accept-Encoding

via: e2s

Xiphias
  • 528
  • 1
  • 4
  • 18
  • (I am aware that ASP and PHP are different - I am wondering if PHP can improperly cache responses the way ASP can.) – Xiphias May 07 '18 at 16:29
  • 1
    PHP doesn't cache, but something else in the chain might. Eg: your http server or an edge cache/CDN that you run your app behind. If your app sets caching headers for pages that contain privileged information on URLs that do not differ per-user then an otherwise properly-configured intermediate cache can cause the exact situation you are describing. – Sammitch May 07 '18 at 18:55
  • @Sammitch thank you - I've added some sample request and response headers to my question. Is it possible for "cache-control: max-age=0" to cause concurrent requests to cache? I will keep examining the responses of other parts of the forum for more obvious issues. – Xiphias May 07 '18 at 20:43
  • 1
    The cache-control header in the *request* is irrelevant, as that is entirely in the control of the user/browser. Your *service* needs to be aware of at *least* what *not* to cache, and set the relevant `Cache-Control: private` header for resource responses that are pertinent only for a single user and you don't have your current situation, which is essentially cache bug ready to be exploited. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control – Sammitch May 07 '18 at 22:10
  • @Sammitch Ah okay - I get it. I've set my .htaccess file to set `cache-control: private, no-cache` for my php files. Waiting to confirm this works but I suspect you've nailed it. I suppose `private, must-revalidate` would be sufficient as well? – Xiphias May 07 '18 at 22:38
  • There is indeed something *very* wrong with the caching here. But overriding the settings in .htaccess is just a temporary workaround. PHP will automatically respond with an uncacheable response by default. It will explicitly remove any caching headers when you call session_start() unless you've set session.cache_limiter in the ini or subsequently added a caching header. – symcbean May 07 '18 at 22:48
  • @symcbean looking at the phorum php code - it was setting cache control header values for Ajax calls but literally nothing else. In this circumstance will PHP overwrite the .htaccess cache control settings with nothing? – Xiphias May 08 '18 at 17:54

1 Answers1

0

@Sammitch was correct - phorum was not setting cache-control in the headers for most of my pages. This was causing my hosting service's own caching system to cache responses that included session cookies.

I fixed this by changing my .htaccess file as described here: https://stackoverflow.com/a/7664157/1411376

This seems to work for my server config, since the php code (phorum) had no code that set cache-control (except for ajax requests).

Xiphias
  • 528
  • 1
  • 4
  • 18