login form how to give access only to one device - php

For learning reason, trying to give login access only for one device
so I added new row inside user table in database called ip which stored registered user ip then for example I did something like that
if($user->ip == $myip){ echo 'success'; }
the problem here that ip changing so the form can't let me access or logged in,
So my question is there anyway to logged in from only by using one device without using ip ?

Fixing the IP address might not be possible. There are a number of other ways to achieve your goal, ranging from cheap and simple to very complicated and expensive. Here are a couple.
Use a USB key (such as this one) that enters a strong password on the push of a button.
Use two way SSL (see question), safe but complicated
The easiest of these options (and my recommendation) is to set a long living cookie (using a browser developer toolbar or extension) and check in PHP for the existence of the cookie in the $_COOKIE array
Good luck!

You must use a cookie, and if the cookie is set, you must not allow a new login.
The following experts and accepted solutions agree:
how to identify remote machine uniquely in php?'
Accepted solution: uniquely identify the computer via cookie
Uniquely identify one computer
Accepted solution: set a cookie that must be present on future logins
How to uniquely identify a computer?
Accepted solution: the solution discusses Evercookie but the point seems to be you need a cookie
So, in summary, however you identify this user, if the user has a cookie, let them in. If they don't, I don't know what you're going to do, but maybe that's part of what you are mysteriously trying to learn here.

Not the best solution:
Public IP's are dynamic, meaning when a router is restarted - they obtain a new IP address. Yes, you could never restart the router but you cannot protected against physical things like electricity meaning check-ups, power outs, etc..
The best idea here is to make this Software un-accessible from outside the node you want to be able to interact with. Meaning, use Apache and MySQL (like XAMPP) and run it only on that node.
If you're looking for a long-term solutions to be able to add IP's, used a shared network. Or implement security conventions like Authentication (login).
However, if you want to consist in building it from your point of view: use the $_SERVER super variable to access the current IP and you'd need to know it before they visit (so find it out by going to something like what is my ip.
if($_SERVER['SERVER_ADDR'] == $somePreknownIp) {
// authorised
}

I would recommend using a cookie instead. First add the following code:
If ($user -> me) {
setcookie("HeyItsMe", 'SomeReallyHardToGuessValue', time()+3600*24*365); /* this would expire in 1 year */
}
This will set the cookie for just you since you're logged in. Then, you can get rid of the the code and add the following in your login screen:
if (isset($_COOKIE['HeyItsMe']) && $_COOKIE['HeyItsMe']== 'SomeReallyHardToGuessValue') {
/**show them the login screen **/
} else {
exit;
}

If your have dynamic IP then you can not do it using IP address. Therefor I suggest you to use sessions.
To do that you have to create another PHP file in your root folder(project folder). And do not share that file name with others. (I named that file as loginHandler.php)
loginHandler.php file has following content.
<?php
session_start();
// assign value to loginHandler.
$_SESSION['loginHandler'] = "99";
// redirect to login page
header('Location: login.php');
?>
On your login page (login.php), you have to start session top of the page. And if $_SESSION['loginHandler'] set, Then it will display your login form. Otherwise it will display only rest of the content.
<?php session_start(); ?>
<p>Page Content</p>
<?php if(isset($_SESSION['loginHandler'])): ?>
<div id="loginBlock">
<form method="post" action="">
<p>Your Login Form</p>
</form>
</div>
<?php endif ?>
<p>Page Content</p>
If you want to login. Then first you have to access loginHandler.php file. Then you will be redirected to login.php page. And you can access login form.
But others do not know about loginHandler.php, Therefor they try to access login form directly. Then that login form will not display for them.

Edit:
Upon re-reading the question I see that I've misunderstood what the OP was really asking for. Leaving my original reply underneath, in case someone else finds it useful.
The proper answer to this questions is: Why care about who gets to see the login form? Just use a properly strong password, and the correct techniques for preventing brute-force attempts (throttle limiting).
Any secret key, or similar, you add to this script is just another password after all. Any other information derived from your connection, browser or whatever, can be sniffed and spoofed by an attacker (or even changed from underneath you, for any reason).
Limiting to a single (or range of) IP(s) is only really useful if you have a static IP, and want to make it a bit more difficult for any potential hacker to break your password.It is not a replacement for a good password.
Original answer:
This is actually a rather common problem, and solved quite a few times. While it takes a bit of work to implement the solution, it is quite straight forward.
First off you need to create a table to keep track of the sessions for each user. This table needs only two (or three) fields:
user id
session id
(timestamp)
The timestamp can be omitted as it's not essential, but it might be nice to have for debugging/logging purposes.
Once you have that you need to re-write your login script a bit. So that it first checks if the user has any active sessions already, if they don't then simply create a new session and store its ID in the abovementioned table.
However, if the user does have a session active already, then you need to do one of two things:
If you want to disallow any further logins, simply return an error explaining that they are already logged in.
Or, delete the old sessions and then log them in on the new device.
Of these two approaches I'd prefer the latter one, as the first one can lead to a user accidentally locking himself out of the system. Until you, as the administrator, go in and manually delete the old session.
The second approach will require a bit more work, in order to delete/invalidate the old sessions, but is generally more robust. It will also give the users the least amount of surprise, as they expect to be logged in when attempting to do so. Instead of having to go chase down whatever unit they think they logged in with last.
Another thing you could do, if you decide on approach 1, is to log the timestamp and then use this in conjunction with the max session lifetime. If time_now - max_session_lifetime > timestamp then you know the session is old, and can be deleted automatically. Ensuring that the user will, eventually, be able to log in without having to rely upon finding/getting the old unit, or you manually deleting it.
I won't post any code on this, for two reasons:
You haven't posted the code in which you handle the logins, making it impossible for me to suggest any specific changes.
The changes needs to be done in quite a few places, and requires a redesign of your logic.
However, follow my logic and set up a pseudo code/flowchart diagram and it should be quite easy to implement.

one thing goes into my mind.
If you know his phone number, send him SMS with token to log in.
Of course there is technical issue about sending SMS message, that i'm as newbie are unable to solve...

You can use Mobile-Detect php library and get the device information of particular device and can add device details in db then you can put a check for that particular device.
Official documentation for library is here - Mobile-Detect
And for usage go here - Usage example
There is one for Client side also - mobile-detect.js
Hope this will help you some way (y).

You can combine 2 approaches into one. You have a list with 3 IP-addresses. For example:
$whitelist = [
'192.168.1.2',
'192.168.1.3',
'192.168.1.4',
];
Then you should check address or cookie:
$accessCode = 'Xvj482Sfjfi2Ghj23PoqT'; //some random string
$cookieExpireValue = time() + 3600 * 24 * 365 * 3; //3 years
$isIpValid = ($_SERVER['REMOTE_ADDR'] && in_array($_SERVER['REMOTE_ADDR'], $whitelist, true));
$isCookieSet = (isset($_COOKIES['access_code']) && $_COOKIES['access_code'] === $accessCode);
if ($isIpValid || $isCookieSet) {
setcookie("access_code", $accessCode, $cookieExpireValue);
echo 'success';
}
Pros:
It restricts access
If IP-address changes, user has access for 3 years
You can change $accessCode and $whitelsit to block users which already got access
It simple
Cons:
If some user gets whitelisted IP, he will get access
If a user loses the cookie (OS reinstall, browser clean, etc) with new IP-address, he will lost access (just change the $whitelist)
In case, you have different user's records for every device and you restrict access after form's submitting, you can save a new IP-address for that user if the user has a valid cookie:
if ($isIpValid || $isCookieSet) {
setcookie("access_code", $accessCode, $cookieExpireValue);
$user->ip = $_SERVER['REMOTE_ADDR'];
$user->save();
echo 'success';
}
and change the validation:
$isIpValid = ($_SERVER['REMOTE_ADDR'] && (in_array($_SERVER['REMOTE_ADDR'], $whitelist, true) || $user->ip === $_SERVER['REMOTE_ADDR']));
In this case you can get rid of the whitelist of addresses, just set ip for every whitelisted user.

Related

Login sytem with PHP

Good day.
I have questions about the login system , that disturbed me quite a long time. For this i want you to imagine that i have 2 pages login.php and userpage.php. The login page contains fields for input of user name and password. While userpage contains all the information about the logined user. When user inputs his data, some class Connection checks him in the database and if user exists, creates a session.
When I'm creating a redirection from login.php to userpage.php, how should i redirect users data? (Should I use global arrays (like $_SESSION) to transfer the info or I should connect the db again from the user page?)
Should I create some multi-threading (Do not judge strictly, I'm a newbie) for userpage.php, to be created for multiple users, which are trying to login at the same time?
How should I protect the information (code side), for being hard to read? (For example Facebook pages source-code. because i don't want some "bad guys" to view my sources) and other things.
How can I make some users to see what the others can't ? For example userpage.php shows different links and information for different users and all the information for me .
How can i prevent membership.php from being viewed?(Is there some other way than using header?)
How can i prevent my require and require_once from being viewd at the login.php and userpage.php ?
1.) When I'm creating a redirection from login.php to userpage.php, how should i redirect users data? (Should I use global arrays (like $_SESSION) to transfer the info or I should connect the db again from the user page?)
You need to have a connection to the db everytime you want to get the user's data. You can create a session to store a unique attribute for the user, like $_SESSION['id'], when the user is successfully logged in, and you can use that value on any page to query the db and get the necessary user data.
2.) Should I create some multi-threading (Do not judge strictly, I'm a newbie) for userpage.php, to be created for multiple users, which are trying to login at the same time?
No, you don't need to worry about users connecting at the same time. The server can handle this. When you have a million users or so, you can start considering this. (Although, even then I'm not too sure. Unfortunately I've never had that problem ;) )
3.) How should I protect the information (code side), for being hard to read? (For example Facebook pages source-code. because i don't want some "bad guys" to view my sources) and other things.
You cannot prevent anyone from seeing your markup and styles, that is, your html and css, or any client side scripting, like javascript. However, your php is server side and not displayed in the source. The 'bad guys' will not be able to view source to see your db connections, php logic, etc.
4.) How can I make some users to see what the others can't ? For example userpage.php shows different links and information for different users and all the information for me .
There are different approaches to take. The simplest is probably to store the user's 'permission level' in the db, and then check that every time you load content. For example,
if ($user['permission']==1)
// Show something
elseif ($user['permission']==2)
// show something else
5.) How can i prevent membership.php from being viewed?(Is there some other way than using header?)
The easiest way to do this is by checking to see if there is an active session, and if not, redirect:
if (!isset($_SESSION['id']))
header("Location: login.php");
6.) How can i prevent my require and require_once from being viewed at the login.php and userpage.php ?
Not too sure what you mean by this, but consider this: require and require_once are the exact same as including the code directly in the file. If you are referring to them being viewed directly by the client by hitting 'view source', don't worry - see answer to question 3.
Note:
These answers are simplified, and there are plenty of other complications to consider. Some of this stuff may not make sense, but I wouldn't sweat it too much. I would recommend starting small - find a decent tutorial or two on how to create a simple user database, a registration, and login page, and start there. No answers you get here will substitute research, practice, and trial and error. Start small, and things will quickly become clearer as you progress.
Save the users state in a cookie or in a session. Note that you need the session_start() the userpage.php page as well as the rest of the page were the user is connected.
More info on http://www.wikihow.com/Create-a-Secure-Login-Script-in-PHP-and-MySQL
See the above link.
No one can read PHP code because it is server side and not client side. So your code is secure already from its own structure.
Let users have different level from the swl-database. If a user got auth 1 they see some links, if they got user auth 2 they see other things.
See page from answer 1
See page from answer 1
Considering your stated fact that you are newbie,I will also assume that the login system is more of practice thing and not a real world app.
Now to answer your queries point-wise.
Storing data in SESSION variables is alright.However,do not store too many data in SESSIONS.I would suggest just store the userid for the user and use that to gather and display info in the userpage.php. As the app gets bigger,you will definitely need to make connections in each individual page.
Use SESSION and COOKIE combination to create multiple user logins. However,Refrain from trying to implement/allow same browser multiple logging-in.SECURITY ISSUE.
PHP source code is anyways not readable from client-side.Regarding javascript & css-u can maybe minify it.But that would still not make it client-safe.
There are many ways to implement this.Maybe have a $_SESSION['admin'] =true when a admin logs-in and use it to display/hide info on userpage.php.
Same as NEXT
What it is that u want to hide?If its HTML/JS ,u dont't have much choice. One solution may be to use if-else in ur php code and restrict display of code present in header.php and the pages included via require and require_once.
This is a very basic guide.Your strategies may vary depending on the complexity of your application and also if/when you start using framweorks . Happy logging-in !!
ADDITIONS wrt to application structure.
Considering that your end product would be a system that allows a user to register and login/logout,i would suggest a following structure to begin with.
Structure-
index.php
|--action
|---register.php
|---logged_in_user_landing.php
index.php-- This is main page and used to redirect to individual pages based on actions.
check if SESSION is set.
If yes,include action/logged_in_user_landing.php else include action/register.php.
As actions increase,you can add if-else and include more pages accordingly.
In register.php,u have the form for login. On submit, redirect to index.php (via form action).
establish db connection in index page and check username-password combination.If correct,set the SESSION for that user and include the 'action/logged_in_user_landing.php'.
Have a unique identifier sent along when redirecting from each individual page,So that u can identify what to do in index.php.
This is a very simple architecture that should get u started.Its kind of a controller based architecture and will help you in the future when u go into MVC architectures.

How to determine from which url a PHP header was called

I've got a page under http://www.example.com/abc/def/a/ where a user can buy products.
For a marketing activity (printed paper) the customer should type in a shorter url
http://www.example.com/order/
When this url is called, the server executes this script:
<?php
header("Location: http://www.example.de/abc/def/a/");
exit;
?>
The page under http://www.example.com/abc/def/a/ contains some
informations (rebate-code etc.) which should only be visible to users
coming from http://www.example.com/order/
$_SERVER['HTTP_REFERER'] seems to be not reliable from what I've read.
I checked with phpinfo(); if there is any info variable which contains "order" but I haven't found one.
Is it possible or do you recommend an alternative approach?
HTTP is in it's pure form a stateless-protocol, so you won't find anything in the protocol itself that will help you with your current problem.
Using $_SESSION to store data in-between requests is the easiest route to walk, and what I recommend.
As said; since the protocol used to transfer information is stateless you have no choice but to create a method for your web-application to recognize which request is done by which user.. this is a perfect problem solved by php-sessions.
php.net - PHP: Sessions - Manual
As you have discovered, the HTTP Referer, along with all of the other headers, can easily be faked. The only reliable way I see of accomplishing this is logging users as they visit the orders page and when they visit the /abc/def/a/ page, verify that the log entry exists. This kind of log could be stored in $_SESSION, however be sure that when using multiple servers you have the proper setup to ensure all servers share the same session information (you can use a redis server to store session data).
On the order page:
session_start();
$_SESSION['order_visited'] = true;
On the rebate code page:
session_start();
if(!isset($_SESSION['order_visited']) || !$_SESSION['order_visited']) {
header('Location: /order'); // Must visit order first
die();
}

I've been asked to perform authentication without usernames and passwords, what are my options?

I've been asked to leave passwords and user names aside since most of the site visitors are stop-buy-come-back-several-months-later-kind of visitors, and the motivation was somewhat along the lines "they would forget there passwords any way and have to request new ones".
I suspect there is no realistic way for me to do this thinking IP:s probably change and browsers get updated, cookies are cleared and so forth.
Or do I have any options?
(not that I'm looking for code but rather concepts and pseudo but the language in the project is php/js coupled with an apache server)
Use OpenID.
Let Facebook, Google, Wordpress, or even Stack Exchange handle the authentication for you, and people wont have to remember another password.
Alternatively:
Many users understand the "forgot my password; check my email" routine by now, so why not just short-cut it by having them input their email and send them a login url with a randomly generated token to log in with.
Once they're logged in, keep them logged in for as long as you deem secure.
We do the following in our e-commerce solution:
We use email as a unique identifier.
When a customer makes a purchase using the same email, the order will be attached to their existing user. You don't however get any address details or stuff like that, but have to enter it manually.
The customer will receive an email with a generated password if it is a first time buy. If it is a second time buy, they will just be instructed to log in. This can however be combined with a url and a login token. Likewise for logging into the site, you could just have them enter an email to receieve a login url token.
Combine this with a long living cookie and/or the browsers datastorage to remember the customers details (address and stuff like that).
Another option would be to have them entering something about themselves that they would always know, but others wouldn't. However it is hard to have an internationally workable solution for this.
You could use so-called supercookies, which is offline storage on the client side. Either through html5 offline storage, or plugin like flash to restore deleted cookies. Although, these cookies is likely to be banned at some point, since they're mostly hidden for the user, and very hard to get rid of. (Not recommending this approach, just saying it's possible)
Authentication credentials break down to three options;
Something you know - passwords
Something you have - physical keys, cards
Something you are - iris, retinal and other biometrics
The best you can do is use cookies I think. Or...I guess you could have them download a file, and upload that file as their access credential - same idea as a cookie but unlikely to be deleted. You would have to think carefully about what to put into the file however - their user id isn't enough, as it would be easily hacked. A random long string would do, one that is saved into the database on their account. Nothing that can be predicted, and nothing that can be used to guess a different account's credential.
A couple of options come to mind:
Use a persistent cookie, but only do this in conjunction with SSL (so it simply can't be sniffed off the wire)
Another option is OpenID like you use here - therefore vistors can use an account they use often to log into your site.
It seems to me that your only option is giving them a forever cookie and hoping it doesn't get purged between visits.
You can read about them here.

Only allow webpage to be viewed via link click

Is there a way to only let a webpage be viewed if the link pointing to it is pressed. I am sending emails to members of my organization with links that attach values to the URL so I can use phps $_GET to figure out who they are on the webpage and update appropriately. What I am worried about is individuals changing the values of the link and changing other members data. If there is a better method for doing this, I am all ears. Using a log in system is not an option.
Not exactly, no.
What you could do is include some token that you keep associated with a particular user id and is very difficult to guess, and include that in the link as well - then, when you get a GET request, you check to make sure the token matches the one you know is correct for that userid. (You'd store the "correct" tokens locally in a database when sending out the emails.)
For instance, you might have...
/modify_info_script?user_id=123&token=aSDqWEqwejk2123salskq
And then you'd have a database table or some other storage that has...
user_id token
----------------------
... ...
122 klqwkejajwie8u8213nak
123 aSDqWEqwejk2123salskq
... ...
and thus if someone tried to change the user_id in the URL, the token wouldn't match and you could reject their request. For instance, this would get rejected...
/modify_info_script?user_id=122&token=aSDqWEqwejk2123salskq
since the right token for 122 would be klqwkejajwie8u8213nak, not aSDqWEqwejk2123salskq.
This is probably the best option if using a login system isn't an option. However, you should really make sure that using a login system isn't an option at all, because user data really should be protected by a login.
This is really not the proper way to secure your site.
However, the simple fix for you is to check the "referer" header and make sure it's not blank. If it's not blank, then it came from a click (or they spoofed it, which is why this isn't secure).
The real way to protect data is to implement a login system with a set of permissions.
To check, if someone came from a link, see $_SERVER['HTTP_REFERER'].
To protect the application against link manipulation, you can combine it with a secret passphrase (only internally, the passphrase must not be known to anyone) and use md5() on the result. Attach the MD5 to the url. If anyone manipulates the url, you will know because the MD5 of "the url plus your passphrase minus the MD5" will be different.
Quite a lot password reset systems work like this so you could say it's reasonably safe provided you use long enough random token. Something like 32 chars should be fine.
Just providing the token should be enough since you don't need the user ID to check it against issued tokens in database.
/modify_info_script?token=aSDqWEqwejk2123salskqfilltill32chars
The other alternative is to have login system where use has to type in their credentials in order to change information.
Also if you really fear that someone might try to guess it, just timeout/ban users after 3 wrong token attempts. No one should be trying to type them in by hand anyway.

Hide pdf to non registered users

I've hit a dead end with this code I'm working on. I have a website where users can register and will be able to view certain pdfs when they are logged in. My question is though, how do I hide this file to make sure that only those currently logged in can subscribe. I keep track of my users with a MySQL database and have been using PHP for all the server side coding. Ideally, the solution won't involve the user having to sign in again or anything like that. I'm not necessarily looking for code (though its always appreciated :D), but any bump in the right direction would be great.
Thanks for any help you guys can offer.
if(isset($_COOKIE['login']))
{
header('Content-Type', 'application/pdf');
readfile('secret/books.pdf');
exit();
}
else
{
include('login.php');
}
The only way to secure the URL to the user is to require a login, which is something you don't want to do. (Obviously as long as the session is open via a cookie or whatever you are using, the person could access it.)
But keep in mind that once a person as the link to the PDF, they can download it and give it to somebody else. So in my opinion, you should simply focus on making it impossible for the average person to guess the URL.
In other words, simply putting the PDF on a URL that is not guessable is sufficient security given that a person can easily duplicate the PDF.
That said, if you want to lock it down a bit, you could give each user his own unique URL for the PDF. Thus if somebody does copy the URL around, you know who did it. Also, you could have URLs expire after a certain time.
That URL could be stored in the database as a url -> pdf lookup. No authentication would be required to access it.
Two thoughts on that:
1) store your PDF outside of your public readable WWW folder and include it to an authenticated user like ayush proposed
2) protect the file with a username and password using htaccess and access it with curl. cURL can provide the correct credentials without making the user re-authenticate.

Categories