Is there a way that I can initiate a persistent session in PHP without the placement of a session cookie? Are there other ways of maintaining a session across pages, such as an IP address-based solution?
My reason for asking is, is that although most users have cookies on, I want to see if there's a way for a login system to work for those with it disabled (even though I think disabling cookies is just unnecessary paranoia, personally).
I don't think it's too much to ask your users to enable cookies. I find it silly when people turn them off entirely.
Otherwise, you can set your session.use_only_cookies to "0" to force the appendage of a session ID to URLs within your php. This approach, however, has several draw backs. Mainly that of keeping the state within the URL, as opposed to the Cookie header. If a user were to copy and paste the URL of the page they were on, and someone else were to click on it, they would both be using the same session.
<?php
ini_set("session.use_cookies", 0);
ini_set("session.use_only_cookies", 0);
ini_set("session.use_trans_sid", 1);
ini_set("session.cache_limiter", "");
session_start();
You can set the ini-Value of session.use_trans_sid to true in order to activate appending the session id to every URL. Have a look at this.
For security purposes you should then limit the session to the IP that created the session. This is not perfectly secure though, as someone with the same IP (behind a proxy e.g.) could reuse that very same session.
You can work with session IDs in URLs, and disabling cookies with:
ini_set('session.use_cookies', 0);
ini_set('session.use_only_cookies', 0);
ini_set('session.use_trans_sid', 1);
session_start();
// IP check
if($_SESSION['ip_check'] != $_SERVER['REMOTE_ADDR']){
session_regenerate_id();
session_destroy();
session_start();
}
$_SESSION['ip_check'] = $_SERVER['REMOTE_ADDR'];
// session stuff
Note: it's highly discougared to use session IDs in URLs. IP addresses can change when travelling around with a wireless card and proxy servers have the same IP address. It's easily broken when clicking 'an old URL' (with the old session ID).
You may also be interested in creating your own session handling function (in conjuction with a database). You would ignore the session ID, and bind it to the IP address. (see examples in http://php.net/manual/en/function.session-set-save-handler.php)
References:
http://php.net/manual/en/session.configuration.php
You could create a database record or temporary file and check $_SERVER vars against the request on every page load. It's a security risk, but with enough variables (have a look at the list here) you may feel you've gotten the chance of hijack down to an acceptable level; only you know how secure your app needs to be.
You can save session id per IP in the database:
Create a mysql table with three fields: session_id, ip and unique temp key (for logged users) or any other condition you like. Then turn off session cookies and use_trans_sid.
then make a code to manage session behavior based on this new table!
after session_start() save session_id in the table and later receive it from table (by IP and any other condition) and then call
session_id($in_table_session_id);
for more information and complete guide see: https://gist.github.com/mimrahe/77415f4a9e238c313bbe8c42f8a6b7fe
If I wanted to do that then I would add the session id in the HTML code as a comment tag and use and configure the PHP code to use that session id which is included in the HTML code. I think it will be more relevant to do that instead of doing it with user IP or adding the session id in the URL.
The correct answer on this is NO. Using any combination of variables besides a cookie is insecure.
Think about it: when a user FIRST requests a page, the server is sending the page along with a unique value saying "HTTP is stateless, keep this so I know it's 'you' next time you call". That means, that person, in that browser (regardless of tab), running at that time, has a unique token.
If and only if they've logged in successfully, that token can now be tied to a session on the server side. Tokens are supposed to be so long and random that nobody could guess one in time.
Multiple browsers could be using the same IP address. Multiple people could have the EXACT same user agent. A cookie is the only storage system that works.
There's actually one more way, and that is to add the unique token to every single link back to the server as well as all AJAX calls, like ?PHPSESSID=my-unique-token-189481958 - but that's a pain to code.
You can also login without Cookies only by Session Id and Time, but you have to write them both in your Database direct after Successful Login.
I have in index.php something like this that will always generate a new session id
based on time and the old session id if conditions are not verified.
if ($_SESSION['id'] != $row['session'] || time() > $row['sessiontime']) {
session_destroy();
session_start();
session_regenerate_id();
}
$_SESSION['id'] = session_id();
I use 2 variables in database for id and time.
And in login window I read the Session id from $_SESSION['id'] variable, then I increment the time and send both to database.
Related
I need to be able to load the user's previously set preference (within the same session, doesn't have to persist between sessions) of if they want to view the mobile version or full version of the site.
I would like to achieve this via a cookieless approach, however I am pretty sure that storing stuff in the $_SESSION variable will write to a cookie.
Is there a better way of doing this?
Thank you!
Xavier.
You can disable cookies for the session:
ini_set('session.use_cookies', 0);
ini_set('session.use_only_cookies', 0);
ini_set('session.use_trans_sid', 1);
this will force any client to append his session-id to every request he makes in order to authenticate. (Well actualy your server will append it to any generated link, so the client includes it automatically)
However, this has several drawbacks:
The session could be "copied" to other clients, when the url containing the session id is transfered.
Closing the browser and reopening it does reset the session.
Navigating away from your website may list a valid session id in the "referer" of another server - which might show it somewhere, so any unknown person might get access to the (maybe still valid) session.
First of there is 2 kinds of cookies.
The dreaded client cookies.
The sessions cookies. A session cookie is only a unique hash set by the server to identifiy the users session (not the user!), you could achive the same thing by adding a query parameter to every link on the site with a number for the session.
The $_SESSION variable contains the variables you set on the server linked to the users session.
You can disable the session cookie and only use query parameters in php.ini
Are cookies necessary to create a login page with php (that keeps you logged in across several pages), or could a session variable do the trick without use of cookies?
Answer simply is yes.
Sessions rely on a session id.
Sessions in php use a cookie to store this id, but you can change it to append the id to each url instead of saving it in cookies.
ini_set('session.use_cookies', false);
in the config variable url_rewriter.tags, you see which URLs automatically get rewritten to append this id:
"a=href,area=href,frame=src,form=,fieldset="
As Pekka mentions, jQuery requests and special JS/Ajax/jQuery calls are not getting rewritten by default and you have to append the id manually like:
<script>
$.get('/yourpage/?PHPSESSID=<?php echo session_id(); ?>');
</script>
the session name can be obtained via session_name();, default is in the config variable: session.name.
Use ini_get(); or phpinfo(); to see your configuration.
Actually if you are using sessions you can use a cookie or a special GET/POST fields to identify yourself towards the server. The server then using the user id, passed either by GET/POST or a cookie - knows which data set is connected to the current user/client at server side. This way using sessions you can store data at server side with only sending a special user id to the client.
This way you can save login data for each user, thus login functionality can be implemented using sessions in PHP.
And yes, you can solve login with no other cookie just the Session user ID, or use the POST/GET session id.
Typically sessions are more reliable when working with keeping a user logged in. Sessions are stored on the server, whereas cookies are stored client sided. So that falls down to: do you want your login dependent on something the client can control and manipulate?
I've had first hand issues with logins being hacked with cookies, so I suggest sessions.
No, you do not need cookies in order to set up a login system, sessions suffice. However, if you seek a "Remember me" option, you need cookies in order to keep the user logged in beyond the point when the user closes the browser or the session expires.
http://www.php.net/manual/en/features.sessions.php
For maintaining a session with server, you need to identify yourself (your page) to server. So that server can keep track of your page's subsequent request and maintain a session.
So, if you only have username and password option on your login page, then cookies may not be required. Refer to the following link:
Passing the Session ID from page to Server
You can have a special URL which will have identifier as part of URL, which will inform server about your subsequent request.
However, please note that using this type of special URL is not always the recommended approach. Because this is insecure than cookie based session. For example, someone may paste their own link on a chat or in an email, and other person will be entered to your site without username/password.
You can do authentication without cookies (or sessions which are a special case of cookies) but it won't be on a page. This method is called HTTP Authentication.
When user logs in I use the following strategy to authenticate user:
Username and Password are present in database along with unique Token and Session Identifier
Set session variable $_SESSION['logged_in'] = true if above returns true
On every page (basecontroller) checks if ($_SESSION['logged_in'] > 0) otherwise redirects to login page.
Is it possible that a hacker might somehow set $_SESSION['logged_in'] = true; ? Do I have a security issue with the above strategy?
Please give me an article or anything that can help me make it more secure.
Sessions are stored on the server so it is impossible for a user to modify anything within the session unless he breaks into your server - in that case he could obviously run $_SESSION['logged_in'] = true; or perform anything else circumventing whatever security measures you have in your code.
The only thing stored on the client side is the session ID cookie. This is a random 32-character hash that does not contain any data.
When using sessions in PHP, the visitors browser stores a cookie with nothing but a session ID stored in it. This session ID is passed back to your server on subsequent requests, and when you issue session_start() the server typically opens a file with the name of that unique session ID. This is where the data is stored.
The default session ID is pretty long, so it would take an attacker a long time to brute force and guess someone elses currently authenticated session. The cookie length can be adjusted if necessary.
As long as your sessions expire within a decent time frame, and the server properly removes the expired session data, you won't have any issues.
A "Hacker" would not be able to set the session variable, unless you have some security issue in your code (no code -> no can tell, sorry)
But I see a problem in the provided code. Please use isset instead of >0 in step 3. A strict error setting would give you a warning here. Please only develop with strict error settings (better code, behaviour is predictable) and "normal" settings for live sites.
If you really have security concerns, pay a professional PHP programmer to check your code or post it here.
I have looked everywhere on the web, and the nuances of SESSION variables need some clarification for me.
I have a website that sets a session variable (I assume it also sets a cookie defining what the session id is? Not sure how that works), and all works perfectly. What I've found when roaming(using wifi) by cellphone, that whenever the phone switches wifi networks, the browser seems to be unable to access the session anymore until that window/tab is closed and reopened.
From what I've read the following apply, please clarify for me:
When browser windows are closed, the session cookie is destroyed, thus when I reopen it, a new cookie is created attached to the new session id. Thus allowing the session to work properly again?
If the network is switched, the server creates a new session id, but because the browser window wasn't closed, the old session cookie wasn't destroyed, and the browser tries to manipulate an expired session id (the old one the session cookie contains)? No idea if this is true, I have read a ridiculous number of pages on this and I can't find anything specific. But this is the impression I get. I have seen so many warning about session_regenerate_id() that I am very nervous about using it...
Any help on details about this, or ways to fix it would be extremely helpful. I am at my wit's end...
UPDATE
I am using a mypajamas script to facilitate logins. The sessions are created normally. However, after looking through the code, I found a place where a session variable is set for the $_SERVER['REMOTE_ADDR'] and $_SERVER['HTTP_USER_AGENT'] values. They are then cross referenced to ensure it's the same user on the same browser on the same IP. It was done to prevent multi-source attacks (make a hijack unlikely). The problem is when using mobile browsers, or dynamic IP's the IP can definitely change, and authentication fails.
I can't believe I couldn't figure this out, I spent hours looking for issues regarding session id's changing.
Hopefully it helps someone with a similar issue in the future. And a sincere appreciation to all who read this post, your guidance in the comments definitely helped me troubleshoot this.
EDITED CODE
class.mypajamas.php
From:
function check_ipau() { // user visits again... but is it really him? check values set above (by get_session())
if( $_SESSION['auth'.$this->_unique_id]['ip'] == $_SERVER['REMOTE_ADDR']
&& $_SESSION['auth'.$this->_unique_id]['ua'] == $_SERVER['HTTP_USER_AGENT']) {
// session data is correct -> user did not "change" ip-address or user agent (aka; hijack is unlikely)
return true;
}
else {
return false;
}
}
To:
function check_ipau() { // user visits again... but is it really him? check values set above (by get_session())
/*if( $_SESSION['auth'.$this->_unique_id]['ip'] == $_SERVER['REMOTE_ADDR']
&& $_SESSION['auth'.$this->_unique_id]['ua'] == $_SERVER['HTTP_USER_AGENT']) {
// session data is correct -> user did not "change" ip-address or user agent (aka; hijack is unlikely)
*/
return true;
/*
}
else {
return false;
}*/
}
First of all, session variables are actually cookies.
1) Session cookies have a lifetime. If your code isn't specifying the lifetime, then the value defaults to whatever is in your php configuration. Do a phpinfo(); and look for session.cookie_lifetime, which is a value in seconds. A value of 0 means the cookie expires when the browser window is closed.
2) If your code is using boilerplate PHP Session handling, then it's unlikely that the issue is related to the user's ip address changing. PHP sessions do not store client ips, and as long as the application you're connecting to has the same domain name/public ip across both networks, then you should be fine. (see PHP Session Cookies fail with users changing IP)
It's possible that there may be some added Session handling that stores the client's IP, but that would have to be custom coded and not based on any built-in functionality.
(based on your edit, this was, in fact the case.)
If you're accessing the same url on network A and on network B, then there is no reason why the session will change / be affected by the network switch. If you have to close the browser window down, and find that your session data is gone, then the problem simply lies in setting the lifetime of the session cookie to be a value other than 0. Place the following line before session_start():
session_set_cookie_params(X);
Where X is a value in seconds after which the cookie will expire. Keep in mind that if you call the aforementioned code before every instance of session_start(); then the cookie will effectively never expire since every single page will be resetting that counter ahead by one hour.
Sessions are server-side only. Unfortunately, if you are coming from a different network address the session will not be valid.
A good practice if you want to retain session values is to create your own cookies, so that you know someone was once authenticated/had a valid session. You then first check if the session values are set, if not check for that cookie. If that cookie exists and has a good value, you can re-set the session value to that of the cookie (or just set the session as you would upon authentication). If there is no session and no cookie then the session is presumed to be non-existent.
I am making a login script that I would like to be as secure as possible. Problem is, security seems to be a never ending battle. So essentially, I am looking for suggestions and improvements to my ideas.
What I have is a login based solely on sessions. Anytime the session information changes, session_regenerate_id() is called to avoid obvious hijacking attempts.
When the session is not set, I check a cookie for valid login, and on success, I update the session.
I attempt to secure the cookie by adding a hash value along with a piece of unique user information (like username or id). This hash is comprised of various information, including the username/id, undecipherable password hash, part of the IP address, etc. By extracting the username/id from the cookie, I can make a new hash from the valid user information and compare that with the hash in the cookie. My hopes here are to prevent fake cookies and cookie hijacking (unless they also spoof the IP address).
EDIT Assume that the login itself will be done via HTTPS/SSL, so the transfer is (reasonably) secure.
Am I on the right track? What else can be done to secure my login?
Thanks for the help!
Stop what you are doing. Do not check the user-agent or the ip address. The user-agent is an attacker controlled variable and checking this value does not increase the security of this system. The ip address will change for legitimate reasons, such as if a user is behind a load balancer or TOR.
A session id must always be a cryptographic nonce. In php just call session_start() and then start using the $_SESSION super global. PHP takes care of all of this for you. If you want to improve php's session handler, use the configurations. Enable use_only_cookies, cookie_httponly and cookie_secure. Also setting the entropy_file to /dev/urandom is a good idea if you are on a *nix system but if your under windows then your in trouble.
For instance to authenticate a user:
//In a header file
session_start();
...
if(check_login($_POST['user_name'],$_POST['password'])){
//Primary key of this user
$_SESSION['user_id']=get_user_id($_POST['user_name']);
$_SESSION['logged_id']=True;
}
And to verify if a user is logged in:
//in a header file
session_start()
...
if(!$_SESSION['logged_id']){
header("location: login.php");
die();//The script will keep executing unless you die()
}
To improve this system read OWASP A9 and use HTTPS for the entire life of the session. Also read OWASP A5: CSRF aka "session riding" and OWASP A2: XSS because they can both be used to compromise a session.
There is no such thing as secure cookie UNLESS it's transmitted over SSL only. It can be mitigated some when using a persistent non-session cookie (like remember me), by doing exactly what you're doing, but not in the same way you're thinking of doing it.
You can indeed store server variables such as the user-agent, the ip address and so forth (and even JavaScript variables), but they are only good for validating that the persistent cookie data matches the client's new connection. The ip address isn't a good idea except when you know that the client (like you only) isn't going to change on every page load (a la AOL).
Modern web browsers and 3rd party services like LastPass can store login credentials that only require a key press (and sometimes not even that) to send the data to the login form. Persistent cookies are only good for those people who refuse to use what's available otherwise. In the end, persistent, non-session cookies are not really required anymore.
I use a cookie based method (using setcookie function) but ....
session_start();
...
if(check_login($_POST['user_name'],$_POST['password'])){
//Primary key of this user
$_SESSION['user_id']=get_user_id($_POST['user_name']);
$_SESSION['logged_id']=True;
}
...these methods are wrooooong !!!!
I crack my website with an attack based on the cookie.
I used cookie option of the WebCruiser vulnerability scanner, so I get my cookie after login.
Then I changed a simply value on cookie
Then I clicked save cookie.
At this point I clicked on webbrowser see on the left panel then I clicked right then I clicked on refresh page, so I got my admin page without using the login page with user and password.
So if someone push you a virus to read the cookie history of IE or Firefox, you'll be happy to find out your admin user and pass can be used by others.
So how to fix the problem? Simple: combine the cookie with session server or session's cookie with sessions server, or session with file session, or cookie with file session....
will be secure but slow :((((
I keep all login data in the users session, this way its all stored server side.
The only thing i would store in a client cookie is stuff like 'auto login', 'session id'
SESSION more secure than cookie
and my advise is to create a unique id for the current login attempted
like :
$id = uniqid();
$_SESSION['username'.$id] = "something ...";