Search code examples
javascriptphpcurlsession-variablesisenabled

[PHP cURL]: Session cookies not saved?


I was extending a php script which checks if javascript is enabled to stop reloading after the second time (when js is seeming to be turned off). Here is a link to the original php script by erm3nda. As to be seen in his snippet, the first time the page loads, the script (furthermore 'caller') prints a script tag with a jquery ajax request to the same page, but with a $_GET header, which gets caught by the same page loaded in the background (furthermore 'called script') and sets a $_SESSION variable to 1. After the called script finishes its work in the background, the caller reloads (and echos this ajax query again) until it is able to find a same-named $_SESSION variable to be set to 1. Should it not, it exits during the reload process with "javascript is disabled", if it was set to 1 it exits with "javascript is enabled". I started to modify this code to stop reloading the page after it already reloaded once. Therefore I am currently utilizing this script:

test.php

<html><body><?php
header('Content-Type: text/html; charset=utf-8');
ini_set('display_errors', 1);
ini_set('log_errors',1);
ini_set('display_startup_errors', 1);
ini_set('error_reporting', E_ALL);
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
function start_session() {
  if(version_compare(phpversion(), "5.4.0") != -1){
    if (session_status() == PHP_SESSION_NONE) {
      session_start();
    }
  } else {
    if(session_id() == '') {
      session_start();
    }
  }
}
start_session();
if (!isset($_SESSION['js']) && !isset($_REQUEST['sessionstart']) && !isset($_REQUEST['setjsoff']) && !isset($_SESSION['jsoff'])) {
  echo '<script src="./js/jquery.js"></script><script type="text/javascript">$(document).ready(function(){$.get(document.URL.substring() + "?sessionstart=1");});</script>';
}
if (isset($_REQUEST['sessionstart'])) {
  $_SESSION['js'] = 1;
  exit("in sessionstart mode");
} else {
  if (isset($_REQUEST['setjsoff'])) {
    $_SESSION['jsoff'] = 1;
    if ($_SESSION['jsoff'] == 1) {
      exit("in setjsoff mode (success)");
    } else {
      exit("jsoff unsuccessful");
    }
  } else {
    session_destroy();
  }
}
if (!isset($_SESSION['js'])) {
  if (!isset($_SESSION['jsoff'])) {
    if (!isset($_REQUEST['sessionstart'])) {
      $ch = curl_init();
      $username = "***";
      $password = "***";
      curl_setopt($ch, CURLOPT_URL, "***/test.php?setjsoff=1");
      curl_setopt($ch, CURLOPT_HEADER, true);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
      curl_setopt($ch, CURLOPT_HTTPGET, true);
      curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
      curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
      $chout = curl_exec($ch);
      curl_close($ch);
      echo "curl init - ".$chout." - ";
    }
    header("Refresh: 1");
    exit("301 Redirect");
  }
  echo "Javascript is not enabled";
} else {
  echo "Javascript is enabled";
}
?></body></html>

(sensitive information was replaced with ***)

With javascript enabled, this script currently functions as it should: It loads, reloads once and the caller outputs "javascript is enabled".
Without javascript enabled, the caller loads, reloads and echos this information while reloading (intentionally): "curl init - HTTP/1.1 200 OK Date: *** GMT Server: Apache X-Powered-By: PHP/5.6.36 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Set-Cookie: PHPSESSID=***; path=/ Transfer-Encoding: chunked Content-Type: text/html; charset=utf-8 in setjsoff mode (success) - 301 Redirect".

(sensitive information was replaced with ***)

As you can see, the output is divided into 3 parts:
- curl init signalizing that curl initiated (not outputting an error)
- the header information of the called page via curl + output of that page
- 301 redirect signalizing that the page was completely executed and is about to reload

The header is the most important message received as it mostly unveils what happened in the background. It seems like curl called the page, the page returns in setjsoff mode (success) (which means that it set $_SESSION['js'] to 1) and very much header information which I can´t interpret.
Here (finally) is my problem: the page continues to reload afterwards (so the session variable was somehow lost?). Does the header information reveal any problem or did I forget to set an essential option via curl_setopt?


Solution

  • The basic problem is that you are not actually reloading the page. You may be causing the server to browse to the same page, but that is a completely different session from your original client session which triggered it. Furthermore, you are not specifying the cookie jar for curl so even if you could contrive to recover from that, your session & associated cookies from the server call is lost.

    The first item, however, is the fundamental problem: you are attempting to do something you should not even be considering. Fortunately the HTML spec offers you a <noscript> element you can work with.

    So simply emit something like this:

    <script type="text/javascript">/*<![CDATA[*/ 
    /* JS code goes here  */ 
    /*]]>*/</script>
    <noscript>
      <!--
        - hit a PHP endpoint that returns a static resource you can hide
        - that PHP script can adjust the session as necessary.
       -->
      <img src="/dummy/image/script.php?jsoff=1" 
           style="width:0px!important;height:0px!important;">
    </noscript>
    

    Even better yet: why not simply assume no JavaScript is available, but then reconsider this when a separate PHP script is hit? Then you can simply link a static <script> resource in the <head> of the page... A much simpler & much more robust solution altogether.