29

How to solve :

Warning: session_start() [function.session-start]: The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in ..... on line 3

Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at ......:3) in ..... on line 3

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at .....:3) in ..... on line 3

Community
  • 1
  • 1
Nandini Bhaduri
  • 1,835
  • 4
  • 18
  • 31

9 Answers9

47

It is an information vulnerability: a malicious attacker may alter the cookies and assign illegal characters to PHPSESSID to expose this PHP warning, which in fact contains juicy information like the file path and the username!

TRiG
  • 10,148
  • 7
  • 57
  • 107
EvilThinker
  • 740
  • 1
  • 9
  • 13
  • 1
    My sessions appear to be under this sort of "investigation", I appreciate this is a old answer, but would you have any pointers on how to lock down this information? My error log is only open to the server side rather than wider web, do I need/should do more? – Martin Jul 16 '15 at 10:36
  • @Martin to lock down this error or protect your script, you have to check the cookies before session_start(), check the variable $_COOKIE['PHPSESSID']) if it has illegal characters, if it does then your script should reload the page or just remove them, if not, then you can proceed safely. – EvilThinker Jan 06 '17 at 16:48
  • 10
    Is worth to mention from [owasp.org docs](https://www.owasp.org/index.php?title=Full_Path_Disclosure): ***This vulnerability is prevented simply by turning error reporting off so your code does not spit out errors.*** – gmo Jan 16 '17 at 10:31
18

There is a bug report for this problem (https://bugs.php.net/bug.php?id=68063)

You can check the success of your session_start and generate the id if needed:

$ok = @session_start();
if(!$ok){
session_regenerate_id(true); // replace the Session ID
session_start(); 
}
alpere
  • 1,079
  • 17
  • 26
  • it works for me, let me know whether the script is saved or melicious? – Moxet Khan Dec 20 '14 at 19:47
  • I tried this and get: `session_regenerate_id(): Cannot regenerate session id - session is not active in FILE on line X` followed by the same error as the title of the question... – conner_bw Apr 28 '19 at 21:30
  • @conner_bw this seems like another issue but check this question: https://stackoverflow.com/questions/31436949/session-regenerate-id-is-not-creating-a-new-session-id this seems similar and has an accepted answer. – alpere Apr 29 '19 at 07:55
  • With this I get `session_regenerate_id(): Session ID cannot be regenerated when there is no active session` – PiTheNumber May 02 '23 at 14:21
16

have a look at this session_start() discussion for a work-around:

session_start() generate a warning if PHPSESSID contains illegal characters

Warning: session_start() [function.session-start]: The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in /home/para/dev/mon_site/header.php on line 17

To avoid i wrote this :

   <?php
        function my_session_start()
        {
            if (ini_get('session.use_cookies') && isset($_COOKIE['PHPSESSID'])) {
                $sessid = $_COOKIE['PHPSESSID'];
            } elseif (!ini_get('session.use_only_cookies') && isset($_GET['PHPSESSID'])) {
                $sessid = $_GET['PHPSESSID'];
            } else {
                session_start();
                return false;
            }

           if (!preg_match('/^[a-z0-9]{32}$/', $sessid)) {
                return false;
            }
            session_start();

           return true;
        }
    ?>
Greg
  • 316,276
  • 54
  • 369
  • 333
Sergey Eremin
  • 10,994
  • 2
  • 38
  • 44
  • 13
    How do you end up with illegal characters in `PHPSESSID` in the first place? Aren't they generated by PHP automatically? – Lèse majesté Jul 06 '10 at 11:57
  • 20
    They are, but a cookie that links you to a generated session id is client side. If that cookie changes to an invalid format (somebody is trying to exploit something) PHP will notice it. – Aleksey Korzun Sep 06 '11 at 19:56
  • Nice hint, but if someone is relying on session_autostart functionality... how to override the session_start() function with the one you're suggestiong here? – kante Jul 08 '13 at 07:51
  • 3
    Are you missing `-` in the regular expression, since that is a valid character. – Justin Feb 08 '14 at 20:18
  • 3
    The original answer introduced a potential security vulnerability - I've edited to fix it. – Greg Jul 14 '14 at 09:09
  • Is there any benefit with this solution compared to this other option? - https://stackoverflow.com/a/33024310/1376820 – Matt Nov 24 '17 at 15:23
14

I edited Andron's previous solution! (fix returned value) and added the evaluation output of my_session_start(). Previous solution solve problem with error message, but I need have to session started.

/**
 * @return boolean return TRUE if a session was successfully started
 */        
function my_session_start()
{
      $sn = session_name();
      if (isset($_COOKIE[$sn])) {
          $sessid = $_COOKIE[$sn];
      } else if (isset($_GET[$sn])) {
          $sessid = $_GET[$sn];
      } else {
          return session_start();
      }

     if (!preg_match('/^[a-zA-Z0-9,\-]{22,40}$/', $sessid)) {
          return false;
      }
      return session_start();
}

if ( !my_session_start() ) {
    session_id( uniqid() );
    session_start();
    session_regenerate_id();
}
Community
  • 1
  • 1
Cendak
  • 1,022
  • 9
  • 8
6

I suggest to use "more correct" version of the function.

Several notes:

  1. More correct regular expression (allows characters in the range a-z A-Z 0-9 , (comma) and - (minus)) as described here.
    Regular expression depends on the php ini settings, like described here and here.
  2. Use session name method

So updated version looks like this:

<?php
    function my_session_start()
    {
        $sn = session_name();
        if (isset($_COOKIE[$sn])) {
            $sessid = $_COOKIE[$sn];
        } else if (isset($_GET[$sn])) {
            $sessid = $_GET[$sn];
        } else {
            session_start();
            return false;
        }

       if (!preg_match('/^[a-zA-Z0-9,\-]{22,40}$/', $sessid)) {
            return false;
        }
        session_start();

       return true;
    }
?>
Andron
  • 6,413
  • 4
  • 43
  • 56
  • This should check the PHP ini settings. In most sane configurations, sessions are never held in GET parameters, so there's no need to check them. – TRiG Jan 29 '20 at 10:35
2

If you don't care about other users (for example: if it's a private interface), just check you browser, find the cookie PHPSESSID (or the name you gave it), delete it, and refresh.

KyleK
  • 4,643
  • 17
  • 33
StevenWang
  • 3,625
  • 4
  • 30
  • 40
0

I came with up this simple method, just try and catch the session start, and if there is a problem regenerate the session.

try {
   session_start();
} catch(ErrorExpression $e) {
   session_regenerate_id();
   session_start();
} 
danjfoley
  • 778
  • 1
  • 8
  • 20
0

I had the same problem and wrote a new version with PHP 8 syntax for my middleware class:

public function handle(Request $request, Closure $next)
{
    if (!headers_sent())
    {
        if(!$this->session_validate_and_start())
        {
            session_id( uniqid() );
            session_start();
            session_regenerate_id();
        }
    }

    return $next($request);
}

protected function session_validate_and_start()
{
    $sessid = $this->getSessionIdFromInput();

    if (!empty($sessid) && !$this->isSessionIdValid($sessid))
    {
        return false;
    }

    return session_start();
}

protected function getSessionIdFromInput(): string
{
    $sn = session_name();

    return $_COOKIE[$sn] ?? $_GET[$sn] ?? '';
}

protected function isSessionIdValid(mixed $sessid): bool
{
    return preg_match('/^[a-zA-Z0-9,\-]{22,40}$/', $sessid);
}
PiTheNumber
  • 22,828
  • 17
  • 107
  • 180
0

You should check the sessionid for not allowed characters because the session_start() function in php is vulnerable for information disclosure.

So if you change the phpsessid cookie with a not allowed character, then you will get an error message if not surpressed by error_reporting or an "@" character in the front of session_start function.

Ensai Tankado
  • 189
  • 1
  • 4