I am using PHP from one host to connect to the API of another on the same subnet, which requires cookies to remember the login. It gives me a WARNING: failed to save cookies in /var/includes/cookie
.
I set up a short test script for myself as follows:
$handle = curl_init(); $logfile = fopen('php://temp', 'w+'); curl_setopt_array($handle, array( CURLOPT_URL => 'https://10.0.0.10:8443/api/login', CURLOPT_RETURNTRANSFER => true, CURLOPT_COOKIEJAR => '/var/includes/cookie', CURLOPT_COOKIEFILE => '/var/includes/cookie', CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_VERBOSE => true, CURLOPT_STDERR => $logfile, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode(array('username' => 'user', 'password' => 'pass')) )); $output = curl_exec($handle); curl_close($handle); // Cookies should technically be saved here, right? // Get contents from curl verbose log file rewind($logfile); $log = stream_get_contents($logfile); fclose($logfile); error_log($log); error_log(print_r($output, true));
The verbose log file gives me this output:
* Hostname in DNS cache was stale, zapped * Trying 10.0.0.10... * TCP_NODELAY set * Connected to 10.0.0.10 (10.0.0.10) port 8443 (#0) * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=api.example.com * start date: Oct 5 07:07:04 2020 GMT * expire date: Jan 3 07:07:04 2021 GMT * issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3 * SSL certificate verify ok. > POST /api/login HTTP/1.1 Host: 10.0.0.10:8443 Accept: */* Content-Length: 42 Content-Type: application/x-www-form-urlencoded * upload completely sent off: 42 out of 42 bytes < HTTP/1.1 200 < vary: Origin < Access-Control-Allow-Credentials: true < Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials * Added cookie xxx="some_session_id" for domain 10.0.0.10, path /, expire 0 < Set-Cookie: xxx=some_session_id; Path=/; Secure; HttpOnly * Added cookie yyy="some_other_id" for domain 10.0.0.10, path /, expire 0 < Set-Cookie: yyy=some_other_id; Path=/; Secure < X-Frame-Options: DENY < Content-Type: application/json;charset=UTF-8 < Content-Length: 30 < Date: Mon, 16 Nov 2020 12:28:42 GMT < * Connection #0 to host 10.0.0.10 left intact * WARNING: failed to save cookies in /var/includes/cookie
The contents of $output
itself is correct; it gives me the OK signal from the API that the login was successful. However subsequent requests give me signals that I am not logged in, certainly due to the cookie not being saved and thus not read.
I have tried:
- Using a path inside the served web directory for the cookie.
touch /var/includes/cookie
and set owner and group toapache
with read/write permissions.- Set 777 permissions on the file.
sudo -u apache bash
to get a terminal and attempt to modify the file – this works, so surely file permissions are okay?
Any pointers where I should look? Could SELinux affect this? My issue looks similar to this one.
CentOS 8, PHP 7.2.11, libcurl 7.61.1
Advertisement
Answer
So turns out it was SELinux having a go. Feels a bit silly to mention the solution in the problem, but I know I’m not the first one to trip over SELinux.
First off, to test if this is really the issue, you can temporarily toggle it off (if it is safe for you to do so).
setenforce 0
If that works, I would of course suggest to put it back on and instead set a rule for the file(s) that need to be modified.
setenforce 1
Since I have the file at /var/includes/cookie
I would run the following command to add a persistent rule:
semanage fcontext -a -t httpd_sys_rw_content_t /var/includes/cookie
-a
adds a record-t
specifies a new type, in this case as one that is writable by httpd
Once that context rule is written, it still has to be applied:
restorecon -v /var/includes/cookie
-v
to get some output as to what changed
See this guide for more in-depth descriptions.
Also worth noting: I had to install the policycoreutils-python-utils
package to get the semanage
command on my minimal CentOS system.