johnstephens Posted May 30, 2021 Share Posted May 30, 2021 Hi! I'm puzzling over what it would take to make the public side of my ProcessWire-driven website entirely cookieless. This site doesn't use public-side editing or $page->editURLs or anything like that, and I haven't added any features that get or set cookie info directly. I can't think of any interaction where the public site needs to know that I'm logged in to ProcessWire. But I do see that ProcessWire sends a set-cookie header for each page URL request, regardless. I imagine there are several or many possibilities along a gradient of complexity, based on different needs. But I don't know where to start looking into this. What paths are available? And what are the tradeoffs for serving a site entirely without cookies? Don't get me wrong: I am very happy with the way it works by default, making it super easy to implement front-end functionality for logged-in users! For most of my sites, I use that in some form or another. Thanks in advance for any guidance you can offer! Link to comment Share on other sites More sharing options...
Robin S Posted May 30, 2021 Share Posted May 30, 2021 Read about the $config->sessionAllow option here: https://processwire.com/blog/posts/multi-instance-pw3/#more-session-control 5 Link to comment Share on other sites More sharing options...
horst Posted May 30, 2021 Share Posted May 30, 2021 Exactly what Robin pointed to. Following is a slightly modified version in the site/config.php that also works in situations like accessing the site via CLI or bootstrap and is aware of admin page name changes. All session settings above the function can be modified to your needs for accessing your backend only. Spoiler /*** 3. SESSION *********************************************************************************/ $config->sessionName = 'wire'; $config->sessionNameSecure = ''; $config->sessionExpireSeconds = 86400; //$config->sessionAllow = true; $config->sessionChallenge = true; $config->sessionFingerprint = 0; $config->sessionForceIP = ''; $config->sessionCookieSecure = 1; $config->sessionCookieDomain = null; $config->sessionHistory = 0; $config->userAuthHashType = 'sha1'; $config->loginDisabledRoles = array( 'login-disabled' ); // DISABLE COOKIES FOR FE ONLY, AS WE NEED COOKIES ON THE BE (!) $config->sessionAllow = function($session) { // if there is a session cookie, chances are user is logged in if($session->hasCookie()) { return true; } // if requested URL is an admin URL, allow session $adminPagename = wire()->pages->get('id=2')->name; if(isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], "/{$adminPagename}/") === 0) { return true; } // otherwise disallow session return false; }; 3 Link to comment Share on other sites More sharing options...
wbmnfktr Posted May 30, 2021 Share Posted May 30, 2021 Have you tried that setup in a recent 3.0.17x version of ProcessWire? Had almost the exact same setup running but it broke with 3.0.177 for some reason. Didn't dig deeper into it as that project uses other cookies now as well. Link to comment Share on other sites More sharing options...
horst Posted May 30, 2021 Share Posted May 30, 2021 5 hours ago, wbmnfktr said: Have you tried that setup in a recent 3.0.17x version of ProcessWire? Had almost the exact same setup running but it broke with 3.0.177 for some reason. Nope, - sites where I run this are between 3.0.148 and 3.0.165 currently. Link to comment Share on other sites More sharing options...
johnstephens Posted May 31, 2021 Author Share Posted May 31, 2021 Thank you all! I did some initial testing on ProcessWire 3.0.165 with confusing results. When I set $config->sessionAllow using a function, as described here and in the linked article, there was no set-cookie header when I looked at a public-facing URL with curl, but my browser was still getting a cookie—even in Private mode, and even after deleting the cookie and doing a hard refresh of the page. It worked as expected when logging in to ProcessWire. When I set $config->sessionAllow to false (without checking for cookies or an admin URL), I still got a cookie when visiting a public-facing URL in my browser; again, even in Private mode, and even after deleting the cookie and doing a hard refresh of the page. curl still showed me no set-cookie header. Unsurprisingly, I could not log in to ProcessWire with sessionAllow set to false. ? Maybe I did something wrong. I did not add configuration for any of the other session settings mentioned by @horst, and that might be the root of my problem. The blog article @Robin S linked to did not mention those under the heading "More Session Control", so I thought that the sessionAllow setting could operate independently of altering other default configurations. Thanks again! I'll try looking this again later in the week, but I welcome any insight anyone may offer before then! Link to comment Share on other sites More sharing options...
Robin S Posted May 31, 2021 Share Posted May 31, 2021 1 hour ago, johnstephens said: When I set $config->sessionAllow to false (without checking for cookies or an admin URL), I still got a cookie when visiting a public-facing URL in my browser; It's working here for me. $config->sessionAllow = true; $config->sessionAllow = false; 1 Link to comment Share on other sites More sharing options...
horst Posted May 31, 2021 Share Posted May 31, 2021 22 hours ago, wbmnfktr said: Have you tried that setup in a recent 3.0.17x version of ProcessWire? Had almost the exact same setup running but it broke with 3.0.177 for some reason. Didn't dig deeper into it as that project uses other cookies now as well. 17 hours ago, horst said: Nope, - sites where I run this are between 3.0.148 and 3.0.165 currently. I updated and tested a site locally and it is working as expected with PW version 3.0.175 and 3.0.179 ! Only thing what happend once after changing / updating the wire-directory was an error screen about spoofed session. I think it had to do with the already existing cookies in my browser (generated with the previous PW version) that leads to that error. When changing the wire folder AND first delete all browser cookies before entering the login page and run a login, everything works as expected. 1 Link to comment Share on other sites More sharing options...
johnstephens Posted June 1, 2021 Author Share Posted June 1, 2021 Same test: $config->sessionAllow = true; curl -I https://cyclexo.com/ HTTP/2 200 date: Tue, 01 Jun 2021 18:02:34 GMT server: Apache expires: Thu, 19 Nov 1981 08:52:00 GMT cache-control: no-store, no-cache, must-revalidate pragma: no-cache x-powered-by: ProcessWire CMS set-cookie: wires=puiah8o9og8bspm6frk2q2litk; path=/; secure; HttpOnly tt-server: t=1622570554533288 D=64984 x-frame-options: SAMEORIGIN x-xss-protection: 1; mode=block content-security-policy: upgrade-insecure-requests; strict-transport-security: max-age=300 content-type: text/html; charset=utf-8 And $config->sessionAllow = false; curl -I https://cyclexo.com/ HTTP/2 200 date: Tue, 01 Jun 2021 17:59:52 GMT server: Apache x-powered-by: ProcessWire CMS expires: Thu, 19 Nov 1981 08:52:00 GMT cache-control: no-store, no-cache, must-revalidate pragma: no-cache set-cookie: wires=uiid7c27b3gfnh3tkds12283lv; path=/; secure; HttpOnly tt-server: t=1622570392087006 D=433082 x-frame-options: SAMEORIGIN x-xss-protection: 1; mode=block content-security-policy: upgrade-insecure-requests; strict-transport-security: max-age=300 content-type: text/html; charset=utf-8 This is with $config->sessionAllow at the bottom of my config.php file, without any other session config. Is that the right place to set this? Is there anything that might be overriding this elsewhere? Thanks again! Link to comment Share on other sites More sharing options...
netcarver Posted June 1, 2021 Share Posted June 1, 2021 I think config.php is the correct place. I use that technique on my site at pwgeeks.com if you want to check it works there. Here's the code I'm using... $config->sessionAllow = function($session) { if($session->hasCookie()) return true; if(!isset($_SERVER['REQUEST_URI'])) return false; // CLI invocation of script? if(!empty($session->config->urls->admin) && strpos($_SERVER['REQUEST_URI'], $session->config->urls->admin) === 0) return true; return false; }; Have you made any changes to the example function that was linked above? Link to comment Share on other sites More sharing options...
johnstephens Posted June 1, 2021 Author Share Posted June 1, 2021 27 minutes ago, netcarver said: Have you made any changes to the example function that was linked above? Thank you, @netcarver! Yes. The code in the blog post had the admin path as /processwire/, and I changed it to /my-admin-path/ —but that was the only change I made. I replaced it with the code you posted, and I'm seeing the same behavior. I feel stumped. Link to comment Share on other sites More sharing options...
netcarver Posted June 1, 2021 Share Posted June 1, 2021 @johnstephens Ok, so if you dump the values of $config in somewhere like ready.php, are you still seeing that $config->sessionAllow is a function? Just wondering if it's being overwritten somewhere. I'd also grep the codebase (particularly in site/modules) to see if sessionAllow is being set anywhere unexpected. Link to comment Share on other sites More sharing options...
DV-JF Posted June 1, 2021 Share Posted June 1, 2021 What I've found out, that if you have a Form builder form on your site, a cookie will be set even with the config setting mentioned above. To avoid this you have to disable the cross site scripting protection. 3 Link to comment Share on other sites More sharing options...
johnstephens Posted June 2, 2021 Author Share Posted June 2, 2021 1 hour ago, DV-JF said: What I've found out, that if you have a Form builder form on your site, a cookie will be set even with the config setting mentioned above. To avoid this you have to disable the cross site scripting protection. OOOOOOOHH! That makes sense. Yes, I am using a FormBuilder form on the site. Disabling cross-site scripting protection sounds bad, but I don't understand the relative risks or dangers. What are the trade-offs? If you disable XSS protection for the plugin, are there other reasonable countermeasures one can take? Link to comment Share on other sites More sharing options...
johnstephens Posted June 2, 2021 Author Share Posted June 2, 2021 4 hours ago, netcarver said: @johnstephens Ok, so if you dump the values of $config in somewhere like ready.php, are you still seeing that $config->sessionAllow is a function? Just wondering if it's being overwritten somewhere. I'd also grep the codebase (particularly in site/modules) to see if sessionAllow is being set anywhere unexpected. Thank you, netcarver! I grepped my whole site directory for "sessionAllow" earlier and couldn't find anything. I just had a chance to dump $config into ready.php and here was some of the session-relevant output: <!-- ["sessionAllow"]=> object(Closure)#6 (1) { ["parameter"]=> array(1) { ["$session"]=> string(10) "<required>" } } ["sessionChallenge"]=> bool(true) ["sessionFingerprint"]=> int(1) ["sessionForceIP"]=> string(0) "" ["sessionCookieSecure"]=> int(1) ["sessionCookieDomain"]=> NULL ["sessionHistory"]=> int(0) --> 1 Link to comment Share on other sites More sharing options...
netcarver Posted June 2, 2021 Share Posted June 2, 2021 @johnstephens Ok, so it's still your function (closure) so it's probably not being overwritten, and that seems right. DV-JS's point is really good. You need to turn off CSRF (≠ XSS) protection in your form's settings as anything that uses $session->CSRF will turn on the session cookie again. See the documentation for the sessionAllow variable in wire/config.php for more information. 2 Link to comment Share on other sites More sharing options...
johnstephens Posted June 2, 2021 Author Share Posted June 2, 2021 Thank you, @netcarver and @DV-JF! So I go into this with my eyes open, what are the implications of turning off CSRF protection? Based on the description above, matching the submission with the session that saw the form may mitigate spam. Are there other perils I should know about that the default CSRF protection may defend against? Or is it an overzealous countermeasure when it comes to a simple contact form? Link to comment Share on other sites More sharing options...
netcarver Posted June 2, 2021 Share Posted June 2, 2021 As your site is essentially running stateless (without cookies or possibly having state encoded into get values holding IDs etc) and no operations require authentication, I think there's very little risk for you. If it's just a contact form or something of that nature, I am happy to (and do) turn off the CSRF protection and then add a honey-pot field + Turing test field to deal with spam. Zero spam so far. I can PM you a link to a site set up like this if you want to take a look. Check out OWASP on CSRF for more information. 3 Link to comment Share on other sites More sharing options...
johnstephens Posted June 2, 2021 Author Share Posted June 2, 2021 Thank you for the perfectly comprehensible explanation! Not only does this solve the problem, but I see that it's a setting I can adjust form-by-form, in case I need something more complex in other contexts! 2 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now