WebApp Sec mailing list archives

Re: How to create (hijacking) secure HTTP sessions?


From: ascii <ascii () katamail com>
Date: Sun, 04 Jun 2006 00:43:04 +0200

Michael Decker wrote:
* HTTP session ID joined with IP and SSL session ID
* Block all session ID usings, that do'nt match IP and SSL session ID

very informative thread, thanks Michael for the initial checklist and
Jason and Ivan for the replies

few things remain to be added

putting remote address into the session is very effective
against session fixation, every type of application (over ssl or not)
should implement this type of check (tcp ip spoofing is more expensive
that user agent spoofing)

if (!isset($_SESSION['remoteip']))
 $_SESSION['remoteip'] = $_SERVER['REMOTE_ADDR'];
if (isset($_SESSION['remoteip']))
 if ($_SERVER['REMOTE_ADDR'] != $_SESSION['remoteip'])
  do_something();

i have seen code that accomplish this task using a db table but it's
easier and better to put the client ip directly into the session

this should play better on https then on http because commonly ssl
connections are direct (while some isp split the http traffic over
different proxy servers and several public ips)

checking the ssl sid is a nice bonus (but as ivan pointed the browser
could reestablish the ssl channel with an other ssl session id)

also making some anti tampering check could be useful (eg: md5 of
user agent, remote ip, accept languages and so on) but this could
harm the session because some browsers modify request header values
runtime/per-page

another issue is that user agent and in general all request headers
are very predictable, so this system mainly relay on the ip address

anyway there are a lot of things you can do to improve the security of
a session but most of them will compromise the usability of the webapp
(and you have to find a trade-off between security and usability, arg!)

auto expiring is useful if the user forgot the browser open and authed

if (isset($_SESSION['lastseen']) &&
    time() > $_SESSION['lastseen'] + 300) // five minutes
 do_something();
else $_SESSION['lastseen'] = time();

limit the session max duration make impossible to maintain a certain
session active forever

if (!isset($_SESSION['firstseen']))
 $_SESSION['firstseen'] = time();
if (isset($_SESSION['firstseen']))
 if (time() > $_SESSION['firstseen'] + 3600) // one hour
  do_something();

session_regenerate_id() or equivalent should be called both randomly
and on privilege changes/login, also the system should destroy the old
session as in php 5.1.0 after an ilia's commit (you have to issue a TRUE
as first argument)

then using strict mode sessions make you sure that the session id has
been chosen by the application, you can archive this result with

if (!isset($_SESSION['fromapp']) || (isset($_SESSION['fromapp'])
    && $_SESSION['fromapp'] !== TRUE))
 session_regenerate_id(TRUE);
$_SESSION['fromapp'] = TRUE;

note that do_something() could be destroy_user_session() as
trigger_error('woop!', E_USER_NOTICE), this is something that needs
specific tuning (on an internet banking you might want session drops
and a super restrictive set of checks, on ebay you cannot force users
to install a browser != than IE to chain the session with their accept-*
request headers)

i have not verified my code, but it has passed the thunderbird
spelling check : )

so the complete checklist could be:
- use ssl
- use a long and really random string as session id
- ssl private certs
- ssl digest (DSA* uses a 160 bit prime and SHA, witch is much better
  than md5 i think)
- total time limited sessions
- set http session timeout
- auto expiring sessions (inactive user)
- auto expiring requiring user iteration (captcha, image recognition,
  otp) (if anal also on an active user)
- chain the session id with the client ip (and block others)
- if applicable chain the session id with the ssl session id (and block
  others)
- regenerate the session id after login/privilege changes (eg:
  session_regenerate_id(TRUE) see ilia's patch for php 5.1.0)***
- logout destroy the session
- allow only one active login (with 'timeouts' or something better)
- strictly set all cookie's options (path, domain, secure)**
  setcookie (string name [, string value [, int expire [, string path [,
  string domain [, bool secure]]]]])
- do not mix ssl and non-ssl
- store sessions on memcached or on the fs but with a different path for
  every vhost
- strict mode sessions (esser wrote this article on the
  topic http://www.hardened-php.net/index.48.html)

correct me if needed (-;

Regards, Francesco 'ascii' Ongaro - http://www.ush.it/

* DSS (Digital Signature Standard)
  http://www.itl.nist.gov/fipspubs/fip186.htm
** es: with mod_rewrite and cookie path we can issue two different
 sessions for bank.tld/site/ and bank.tld/panel/ and an xss on site/
 will never reveal the panel/ cookie
*** ilia session_regenerate_id patch
 http://ilia.ws/archives/47-session_regenerate_id-Improvement.html
 http://it.php.net/session_regenerate_id

-------------------------------------------------------------------------
Sponsored by: Watchfire

Watchfire named worldwide market share leader in web application
security assessment by leading market research firm. Watchfire's AppScan
is the industry's first and leading web application security testing
suite, and the only solution to provide comprehensive and consolidated
remediation task lists at every level of the application. See for
yourself.
Download a Free Trial of AppScan 6.0 today!

https://www.watchfire.com/securearea/appscansix.aspx?id=701300000007t9c
--------------------------------------------------------------------------


Current thread: