Page MenuHomePhabricator

Make phame cacheable
Closed, DuplicatePublic

Description

Blog posts on phame cannot currently be cached by our CDN, and hence cannot be shared on link aggreagators for the (unfounded?) fear of being successful and melting phab down.

Phame currently returns the following response headers that make it uncacheable:

[...]
< Cache-Control: no-store
[...]
< Set-Cookie: phsid=REDACTED; expires=Mon, 01-Apr-2024 09:18:05 GMT; Max-Age=157680000; path=/; domain=phabricator.wikimedia.org; secure; httponly

For posts with visibility set to Published, Cache-Control should be set by phame to some value that allows caching, such as Cache-Control: max-age=1440 (or whatever number of seconds is deemed appropriate).

I'm not sure what the purpose of the cookie is, but I can read phame posts just fine without sending it from my client, so I guess it's not critical functionality-wise and can be dealt with at the caching layer?

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
ema triaged this task as Medium priority.Apr 3 2019, 10:53 AM

I'm not sure what the purpose of the cookie is...

This cookie mostly supports CSRF protection for login attempts (phsid is "PHabricator Session ID"), and prevents an attack where a malicious user tricks you into visiting a web page which issues a background POST to Phabricator's login page with credentials the attacker controls, logging you in with an account the attacker can access. They then somehow trick you into entering all your credit card information or something, then they log in to the account using the credentials they know and read all the secrets you stored.

The system sets it on every page because the cookie part of the code doesn't "know" if there's a login form or other CSRF-sensitive form on the page, but no such form is present on these pages, so the cookie doesn't do anything useful in the context of a logged-out, read-only view of Phame.

(Note that setting the cookie to a cached/known value is vaguely bad, in that an attacker who knows the phsid value for a particular client can also discover a legitimate CSRF token value and construct a valid background POST, so be mindful of not caching the Set-Cookie header, but this attack is complicated and not very effective in the first place so this isn't a huge concern.)

for the (unfounded?) fear

I suspect this is somewhat unfounded since Phabricator is running on reasonable hardware (not a VM on someone's modded toaster) and Phame isn't completely awful at building pages, but obviously it still needs more resources than a cached page from a CDN would. Just hitting Phame with ab and seeing if you can reach a comfortable response rate before anything falls over might establish that there's enough margin here that this isn't a major priority, though. For example, here's secure.phabricator.com serving ~120K requests/hour from Phame:

$ ab -c25 -n1000 https://secure.phabricator.com/phame/live/112/post/774/that_s_not_a_csrf_attack/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking secure.phabricator.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache
Server Hostname:        secure.phabricator.com
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128
Server Temp Key:        ECDH P-256 256 bits
TLS Server Name:        secure.phabricator.com

Document Path:          /phame/live/112/post/774/that_s_not_a_csrf_attack/
Document Length:        13021 bytes

Concurrency Level:      25
Time taken for tests:   30.902 seconds
Complete requests:      1000
Failed requests:        1
   (Connect: 0, Receive: 0, Length: 1, Exceptions: 0)
Non-2xx responses:      1
Total transferred:      13878178 bytes
HTML transferred:       13007979 bytes
Requests per second:    32.36 [#/sec] (mean)
Time per request:       772.545 [ms] (mean)
Time per request:       30.902 [ms] (mean, across all concurrent requests)
Transfer rate:          438.58 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       16   20   4.6     19      52
Processing:     7  742 183.5    708    3234
Waiting:        7  674 166.5    644    3141
Total:         54  762 183.3    727    3254

Percentage of the requests served within a certain time (ms)
  50%    727
  66%    797
  75%    846
  80%    893
  90%    999
  95%   1075
  98%   1161
  99%   1236
 100%   3254 (longest request)

This is a fairly modest request rate and may or may not be within the margin of comfort, but at least suggests that the service won't instantly fall over and die if you get 7 upvotes.