# Session security

- Thread: https://externals.io/message/29874
- Original archive: https://news-web.php.net/php.internals/29874
- Started by Stut on 2007-05-29T17:04:29+00:00
- Messages: 24
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #29874 — Stut — 2007-05-29T17:04:29+00:00

URL: https://externals.io/message/29874#29874

Hi all,

Just wanted to get your opinion on a discussion currently going on on 
the general list.

Why does the PHP session extension not use something like the user agent 
to validate that a session ID has not been hijacked? Or is this 
something that just hasn't been implemented yet?

-Stut

---

## #29875 — Antony Dovgal — 2007-05-29T17:14:32+00:00

URL: https://externals.io/message/29874#29875 · In reply to: #29874

> Hi all,
> 
> Just wanted to get your opinion on a discussion currently going on on 
> the general list.
> 
> Why does the PHP session extension not use something like the user agent 
> to validate that a session ID has not been hijacked? Or is this 
> something that just hasn't been implemented yet?

Please elaborate.

-- 
Wbr, 
Antony Dovgal

---

## #29876 — Rasmus Lerdorf — 2007-05-29T17:16:50+00:00

URL: https://externals.io/message/29874#29876 · In reply to: #29874

Stut wrote:
> Hi all,
> 
> Just wanted to get your opinion on a discussion currently going on on
> the general list.
> 
> Why does the PHP session extension not use something like the user agent
> to validate that a session ID has not been hijacked? Or is this
> something that just hasn't been implemented yet?

The user agent is trivial to spoof.  If you are going to hijack
someone's session, it is very easy to also hijack their user agent
string, so I don't see how that solves anything.

-Rasmus

---

## #29877 — Xing Xing — 2007-05-29T17:52:28+00:00

URL: https://externals.io/message/29874#29877 · In reply to: #29874

Stut 写道:
> Hi all,
>
> Just wanted to get your opinion on a discussion currently going on on 
> the general list.
>
> Why does the PHP session extension not use something like the user 
> agent to validate that a session ID has not been hijacked? Or is this 
> something that just hasn't been implemented yet?
>
> -Stut
>
Some http proxy may modify the user agent~
If there are some http proxy in a cluster, and one of them do some 
different on user agent, there must be a trouble.

And, the other way, to aganst the attacker getting the real user agent, 
we could do something like: md5(user agent + secrete key) . then if the 
attacker get the string of md5, it is no use to forge the real user agent.
Any way, this should be done in the script layer, not in the session 
mechanism. you need more security, do it in script, needn't, do nothing~~


Xing

---

## #29878 — Robert Cummings — 2007-05-29T18:07:31+00:00

URL: https://externals.io/message/29874#29878 · In reply to: #29876

> Stut wrote:
> > […]
> 
> The user agent is trivial to spoof.  If you are going to hijack
> someone's session, it is very easy to also hijack their user agent
> string, so I don't see how that solves anything.

I agree mostly, but in the case of idiots that post a URL to a site that
includes a PHPSESSID in the URL it would provide a teency bit more
protection from casual hijacking :)

I agree more with Xing Xing's responde though, in that it belongs in the
script layer.

Cheers,
Rob.
-- 
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting  |
| a powerful, scalable system for accessing system services  |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for       |
| creating re-usable components quickly and easily.          |
`------------------------------------------------------------'

---

## #29879 — Rasmus Lerdorf — 2007-05-29T18:14:27+00:00

URL: https://externals.io/message/29874#29879 · In reply to: #29878

Robert Cummings wrote:
> 
> > […]
> 
> I agree mostly, but in the case of idiots that post a URL to a site that
> includes a PHPSESSID in the URL it would provide a teency bit more
> protection from casual hijacking :)
> 
> I agree more with Xing Xing's responde though, in that it belongs in the
> script layer.

Well, obviously you need an authentication layer separate from the
session layer.  If people are using the session extension as if it was
an authentication layer, then they are amazingly misguided.  The
solution to that is not the session code, but better documentation.

-Rasmus

---

## #29880 — Robert Cummings — 2007-05-29T18:34:47+00:00

URL: https://externals.io/message/29874#29880 · In reply to: #29879

> Robert Cummings wrote:
> > […]
> 
> Well, obviously you need an authentication layer separate from the
> session layer.  If people are using the session extension as if it was
> an authentication layer, then they are amazingly misguided.  The
> solution to that is not the session code, but better documentation.

Well the two are quite related. Not that the session is responsible for
authentication, but once authenticated the session data (stored server
side I hope) usually indicates whether a user has already performed
authentication for the current temporary session -- otherwise you'd need
to log back in on every request. As such, a URL posted in the wild
containing a PHPSESSID is vulnerable to  hijacking for the lifespan of
the temporary session. Better documentation won't help the completely
ignorant masses of end users :)

Cheers,
Rob.
-- 
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting  |
| a powerful, scalable system for accessing system services  |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for       |
| creating re-usable components quickly and easily.          |
`------------------------------------------------------------'

---

## #29883 — Rasmus Lerdorf — 2007-05-29T19:18:49+00:00

URL: https://externals.io/message/29874#29883 · In reply to: #29880

Robert Cummings wrote:
> 
> > […]
> 
> Well the two are quite related. Not that the session is responsible for
> authentication, but once authenticated the session data (stored server
> side I hope) usually indicates whether a user has already performed
> authentication for the current temporary session -- otherwise you'd need
> to log back in on every request. As such, a URL posted in the wild
> containing a PHPSESSID is vulnerable to  hijacking for the lifespan of
> the temporary session. Better documentation won't help the completely
> ignorant masses of end users :)

You really want a separate and distinct signed authentication cookie
that has nothing to do with the session.  The stored session should
indicate which logged in user the session belongs to, but it should
never ever be used as the sole authentication cookie.  That's what I
meant by a separate authentication layer.

-Rasmus

---

## #29884 — Stut — 2007-05-29T19:25:32+00:00

URL: https://externals.io/message/29874#29884 · In reply to: #29883

Rasmus Lerdorf wrote:
> You really want a separate and distinct signed authentication cookie
> that has nothing to do with the session.  The stored session should
> indicate which logged in user the session belongs to, but it should
> never ever be used as the sole authentication cookie.  That's what I
> meant by a separate authentication layer.

Thanks to everyone for their responses.

The issue is not about how a user is initially validated, it's about how 
you prevent the session ID from being used on a different machine while 
it's still active on the server. AFAICT using a signed authentication 
cookie will not do this since it's still coming from the client and can 
therefore be copied.

The basic question is... is there any way to validate that a session ID 
coming from the client is coming from the same client?

I don't believe there is since, as Xing pointed out, anything that comes 
from the client can a) be faked, and b) may change from request to 
request. This includes the user agent and IP address.

However, I'd like clarification on that just in case there's a reliable 
way to make sessions more secure. Oh, and also to validate the argument 
I'm making on PHP-General, but that's really a secondary goal ;)

Cheers.

-Stut

---

## #29885 — Stanislav Malyshev — 2007-05-29T19:29:34+00:00

URL: https://externals.io/message/29874#29885 · In reply to: #29884

> > […]

Could you explain why? If you can steal session cookie, you definitely 
could steal any other cookie too. So stealing-wise, nothing is gained by 
using separate cookie. Signing would help you to know the cookie is from 
you, but I don't see how it's going to help you to know the cookie 
belongs to whoever is attempting to use it. Could you elaborate?
-- 
Stanislav Malyshev, Zend Products Engineer
stas@zend.com  http://www.zend.com/

---

## #29887 — Stanislav Malyshev — 2007-05-29T19:38:13+00:00

URL: https://externals.io/message/29874#29887 · In reply to: #29884

> The basic question is... is there any way to validate that a session ID 
> coming from the client is coming from the same client?

I'm afraid since there's no way (well, except for described below :) to 
uniquely and securely identify the clients I don't see how you could do 
that. You could use client certificates as a secure client 
identification, and then probably you could verify that current client 
presented the same valid certificate as before, but that doesn't really 
belong to sessions - it's external to sessions. Not sure how well PHP 
support for client certificates is, in any case unless you have a lot of 
control over your users they probably won't like to install any 
certificates.

Also, if you use SSL (which you probably do if you care about security), 
as I see it most frequent way to steal the cookie is to control user's 
browser. If the hostile code gained control over the user's browser, 
it's essentially the same client, so you couldn't distinguish it from 
the legitimate code. You could of course tryng to counter replay attacks 
(which are only part of the possible attacks) by matching IPs and other 
auxiliary data but if you don't have secure ID for the client there 
would be cases when it could be still not enough.

-- 
Stanislav Malyshev, Zend Products Engineer
stas@zend.com  http://www.zend.com/

---

## #29888 — Jacques Marneweck — 2007-05-29T19:45:51+00:00

URL: https://externals.io/message/29874#29888 · In reply to: #29876

> Stut wrote:
> > […]
>
> The user agent is trivial to spoof.  If you are going to hijack
> someone's session, it is very easy to also hijack their user agent
> string, so I don't see how that solves anything.
>
I think he's trying to figure out how to do something similar to using a
'browser fingerprint' as part of his session.  One thing I noticed with
doing creating and checking a 'browser fingerprint' a few years back
was depending on what you were doing / using it would change things
between requests.

With web requests, a lot of things are easy to spoof from the client  
side.
Locking a session to an IP address has it uses provided the user does
not make their requests from various IP addresses like the AOL proxy
farms used to do afaik.

If you are really paranoid, use SSL and regenerate the session  
identifier
on the first request from the user.  That way it's not known.  It's  
generally
advised to regenerate the session identifier on privilege change.

There is no real way of detecting if a session has been hijacked  
given for
example for .za users we tend to be transparently proxied for  
requests to
international sites, so forcing locking a session to a IP will lock  
that session
to an ISP's netcache.

Something along the lines of:

if (!isset($_SESSION['initiated'])) {
     `session_regenerate_id()`;
     $_SESSION['initiated'] = true;
}

When you change privilege do something along the lines of

     session_regenerate_id(true);

Which will delete the previous session and keep the current session  
information.

YMMV.

Regards
--jm

> -Rasmus

--
Jacques Marneweck
http://www.powertrip.co.za/
http://www.powertrip.co.za/blog/
http://www.ataris.co.za/

#include <std/disclaimer.h

---

## #29889 — Rasmus Lerdorf — 2007-05-29T19:54:53+00:00

URL: https://externals.io/message/29874#29889 · In reply to: #29885

Stanislav Malyshev wrote:
> > […]
> 
> Could you explain why? If you can steal session cookie, you definitely
> could steal any other cookie too. So stealing-wise, nothing is gained by
> using separate cookie. Signing would help you to know the cookie is from
> you, but I don't see how it's going to help you to know the cookie
> belongs to whoever is attempting to use it. Could you elaborate?

The session store is just a session store.  It is not a
login/authentication mechanism and thus doesn't have any of the
protections you might want to add to that.  Therefore a separate
authentication cookie is needed that can separate the two concepts
completely.  This also allows you to have different timeouts on the two.
 For example, many sites let you stay logged in for weeks, but for any
critical operation they have a much shorter timeout so they ask you to
re-enter your credentials in order to perform that critical action.

Also, any pages that have some sort of user action, typically a form,
will have a crumb in it which is a small signed bit of data which is
usually in a hidden field.  This helps prevent cross site request
forgeries by making each form specific to the logged in user.

But yes, there isn't any standard approach to prevent cookie theft.  It
is up to the application to come up with a set of checks and
restrictions that best meet the specific needs of that app.

-Rasmus

---

## #29890 — Stanislav Malyshev — 2007-05-29T20:00:01+00:00

URL: https://externals.io/message/29874#29890 · In reply to: #29889

> The session store is just a session store.  It is not a
> login/authentication mechanism and thus doesn't have any of the
> protections you might want to add to that.  Therefore a separate
> authentication cookie is needed that can separate the two concepts

I don't see how it's "therefore". Yes, session is just a storage. But 
how you derive from it that authentication information can not be stored 
in this storage and how the separate cookie is helping you in any way 
make it more secure?

> completely.  This also allows you to have different timeouts on the two.

That's a very specific case which doesn't really concern security but 
site policies. You could also expire values inside session, there are 
numerous wrappers doing it AFAIK, and even if you don't use such wrapper 
there's nothing hard in storing timestamp inside the session and 
expiring auth once the timestamp goes old.

>  For example, many sites let you stay logged in for weeks, but for any
> critical operation they have a much shorter timeout so they ask you to
> re-enter your credentials in order to perform that critical action.

That doesn't mean it should be implemented using separate cookie.

> Also, any pages that have some sort of user action, typically a form,
> will have a crumb in it which is a small signed bit of data which is
> usually in a hidden field.  This helps prevent cross site request
> forgeries by making each form specific to the logged in user.

That's nice but again is not related to cookies or sessions. This can be 
done without having separate auth cookie.
-- 
Stanislav Malyshev, Zend Products Engineer
stas@zend.com  http://www.zend.com/

---

## #29891 — Rasmus Lerdorf — 2007-05-29T20:06:56+00:00

URL: https://externals.io/message/29874#29891 · In reply to: #29890

Stanislav Malyshev wrote:
> > […]
> 
> I don't see how it's "therefore". Yes, session is just a storage. But
> how you derive from it that authentication information can not be stored
> in this storage and how the separate cookie is helping you in any way
> make it more secure?

Because you don't have full control over the session cookie since it is
generated by PHP.  For an authentication cookie you want to layer other
application-specific checks on top of it.

-Rasmus

---

## #29892 — Stut — 2007-05-29T20:11:08+00:00

URL: https://externals.io/message/29874#29892 · In reply to: #29891

Rasmus Lerdorf wrote:
> Stanislav Malyshev wrote:
> > […]
> 
> Because you don't have full control over the session cookie since it is
> generated by PHP.  For an authentication cookie you want to layer other
> application-specific checks on top of it.

I'm still unclear on how you validate that the authentication cookie 
came from the same client machine as the one the application first sent 
it to, which was the core of my question.

The answer seems to be that you can't do it reliably.

-Stut

---

## #29893 — Stanislav Malyshev — 2007-05-29T20:16:41+00:00

URL: https://externals.io/message/29874#29893 · In reply to: #29891

> Because you don't have full control over the session cookie since it is
> generated by PHP.  For an authentication cookie you want to layer other
> application-specific checks on top of it.

Could you give an example of such checks?
-- 
Stanislav Malyshev, Zend Products Engineer
stas@zend.com  http://www.zend.com/

---

## #29894 — Robert Cummings — 2007-05-29T20:16:57+00:00

URL: https://externals.io/message/29874#29894 · In reply to: #29892

> Rasmus Lerdorf wrote:
> > […]
> 
> I'm still unclear on how you validate that the authentication cookie 
> came from the same client machine as the one the application first sent 
> it to, which was the core of my question.
> 
> The answer seems to be that you can't do it reliably.

You don't have any cookie if the user has cookies disabled. So either
you use a policy that enforces the user to enable cookies or you fall
back on trans sid in which case, all bets are off since all you have is
the PHPSESSID stuck in the URL or form POST.

Cheers,
Rob.
-- 
.------------------------------------------------------------.
| InterJinn Application Framework - http://www.interjinn.com |
:------------------------------------------------------------:
| An application and templating framework for PHP. Boasting  |
| a powerful, scalable system for accessing system services  |
| such as forms, properties, sessions, and caches. InterJinn |
| also provides an extremely flexible architecture for       |
| creating re-usable components quickly and easily.          |
`------------------------------------------------------------'

---

## #29895 — Stanislav Malyshev — 2007-05-29T20:17:45+00:00

URL: https://externals.io/message/29874#29895 · In reply to: #29892

> I'm still unclear on how you validate that the authentication cookie 
> came from the same client machine as the one the application first sent 
> it to, which was the core of my question.
> 
> The answer seems to be that you can't do it reliably.

As far as I understand, no, you can't, unless you have secure external 
means to establish client identity (like client certificate).
-- 
Stanislav Malyshev, Zend Products Engineer
stas@zend.com  http://www.zend.com/

---

## #29896 — Rasmus Lerdorf — 2007-05-29T20:18:30+00:00

URL: https://externals.io/message/29874#29896 · In reply to: #29892

Stut wrote:
> Rasmus Lerdorf wrote:
> > […]
> 
> I'm still unclear on how you validate that the authentication cookie
> came from the same client machine as the one the application first sent
> it to, which was the core of my question.
> 
> The answer seems to be that you can't do it reliably.

Correct, which is why it needs to be up to the application.  You may
deem it appropriate to do it based on ip because your user base aren't
likely to be coming from AOL or other dynamic connections, or you may
find it useful to tie it to the user agent, or some other mechanism
entirely.  Like an RSA token plugin thing, for example.  But at the
general level that can't really be hardcoded into PHP since the right
answer will be different for everyone.

-Rasmus

---

## #29897 — Stut — 2007-05-29T20:33:39+00:00

URL: https://externals.io/message/29874#29897 · In reply to: #29894

Robert Cummings wrote:
> 
> > […]
> 
> You don't have any cookie if the user has cookies disabled. So either
> you use a policy that enforces the user to enable cookies or you fall
> back on trans sid in which case, all bets are off since all you have is
> the PHPSESSID stuck in the URL or form POST.

Sorry, I should be using the term cookie when I mean session ID. It 
confuses people ;)

It doesn't matter where the session ID comes from, the basic point is 
that you have to trust it or implement some experience-degrading 
mechanism like client certificates, and even there there are few guarantees.

-Stut

---

## #29898 — Christian Schneider — 2007-05-29T20:49:06+00:00

URL: https://externals.io/message/29874#29898 · In reply to: #29897

Stut wrote:
> It doesn't matter where the session ID comes from, the basic point is 
> that you have to trust it or implement some experience-degrading 
> mechanism like client certificates, and even there there are few 
> guarantees.

You want more info to be checked? Simply add a variable containing 
user-agent, remove ip, etc. to your session and check that in your 
application startup code. If it doesn't match then start a new session.

But as this can lead to various problems (user agent being easy to fake 
and not necessarily constant through proxies, remote ip changing in the 
middle of a session with proxies or some providers) this should be done 
when really needed by the application, not by PHP itself. I'm pretty 
sure there already exists a PEAR package or something helping with this.

My 2 cents,
- Chris

---

## #29913 — Richard Lynch — 2007-05-29T23:58:16+00:00

URL: https://externals.io/message/29874#29913 · In reply to: #29874

> Hi all,
>
> Just wanted to get your opinion on a discussion currently going on on
> the general list.
>
> Why does the PHP session extension not use something like the user
> agent
> to validate that a session ID has not been hijacked? Or is this
> something that just hasn't been implemented yet?

Could be any of these reasons, I suppose:

A) Anybody smart enough to hijack a session, is smart enough to send
the same User Agent.

B) Valid reasons exist for a user to switch User Agents mid-session,
e.g., stupid broken browser bugs that can be worked around by
"hijacking" one's own session.  (I've done it, at least...)

C) It's just too high a level to be done "right" in PHP core, imho.

YMMV

-- 
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some indie artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?

---

## #29930 — Lukas Kahwe Smith — 2007-05-30T05:35:42+00:00

URL: https://externals.io/message/29874#29930 · In reply to: #29898

Christian Schneider wrote:
> Stut wrote:
> > […]
> 
> You want more info to be checked? Simply add a variable containing 
> user-agent, remove ip, etc. to your session and check that in your 
> application startup code. If it doesn't match then start a new session.
> 
> But as this can lead to various problems (user agent being easy to fake 
> and not necessarily constant through proxies, remote ip changing in the 
> middle of a session with proxies or some providers) this should be done 
> when really needed by the application, not by PHP itself. I'm pretty 
> sure there already exists a PEAR package or something helping with this.

PEAR::LiveUser supports this. Not sure about PEAR::Auth.

regards,
Lukas
