L
L
littleguga2015-10-13 18:20:45
PHP
littleguga, 2015-10-13 18:20:45

How to write authorization/authentication correctly?

What can you read in order to understand how to organize everything correctly?
1. From complete scratch. User enters login + password:
1.1 What to write in cookies/session?
1.2 How to check whether the user is authorized or not on each page?
1.3 If you want the user to have only simultaneous access from one device - how to be?
1.4 And if from several?
2. The user logs in via VK
1.1 What to write in cookies / session?
1.2 How to check whether the user is authorized or not on each page?
A big request is to answer all the points, or give a resource / article / where / what to read in order to answer all the points.
Thanks in advance for your informative response!

Answer the question

In order to leave comments, you need to log in

8 answer(s)
D
Dasha Tsiklauri, 2015-10-13
@dasha_programmist

There are two options for storing data about an authorized user:
1) In cookies (as it is used by default in asp.net): the necessary data (claims) are encrypted by machineKey and given to the user in http-only cookies, so they are sent with each request to the server, decrypted and then can be checked in the required places.
pluses: completely stateless, no need to access the database 2) Session key: after successful authentication, we authorize the user and store claims on the server in fast memory or a database (key-value), where the key is the session key, the value is any data. pluses: there is full control over the authorization state (as well as the ability to end the session from the server side, and change the user's role (or other parameters) on the fly)
cons: organization interlayers - cache or storage in the database (slow), when the session service is restarted / crashed, clients will need to re-login.
one
1.1 In cookies, write either the session key or encrypted data about the user, the session is an abstract concept (it is a pair: key and data), the key must be protected, i.e. difficult to copy (at least visually difficult to remember), unique (so that there are no collisions: two different users were given the same key, i.e. it should not be a hash function from a login-password or IP or something non-unique ).
1.2 There are authorization attributes in asp.no (in which you can place checks for such a requirement, a role, a specific user), in a general sense, the logic is as follows: a request has been received to the server, then you need to look at which resource is being accessed (protected or free), if the resource is protected, then check the cookie (session key or encrypted data), decrypt / get session data from the cache and make a decision: let it in or not (give 401/403 or give 200/404/...).
1.3 Create a dictionary on the server (in the cache or database), add a check condition for the presence of an entry in the dictionary when checking the session algorithm.
1.4 With several - no need for a dictionary.
2
2.1 Even if the user logs in through VK, you still need to give your session keys / encrypted data, but inside the data you already store access_token from the VK session, so there is a very small chance that the VK token will leak, and if the session key is leaked, then the actions will be limited only by the functionality of the site.
2.2 After decrypting the cookie or data using the session key, make an additional request to the VK server with the token that was saved during authentication (access_token), the request is simple, for example, get the username, if the VK issued that the token is expired or an error, then close the session or cookies with data reset.

E
enibeniraba, 2015-10-14
@enibeniraba

Very much simplified, without OOP and patterns):
Authorization:

session_start();
if (!empty($_SESSION['user_id']))
  die('Вы уже авторизованы');
  
$user = get_user_by_login($_POST['login']);
if (!$user)
  die('Пользователь не найден');
  
if ($_POST['pass'] !== $user['pass'])
  die('Неверный пароль');

$_SESSION['user_id'] = $user['id'];
die('Привет, '.$user['login']);

In this case, the session_id will be written to the user's cookies, and the user_id to the session.
Examination:
session_start();
if (empty($_SESSION['user_id']))
  die('Нет прав');

$user = get_user_by_id($_SESSION['user_id']);
if (!$user || !$user['active'])
{
  unset($_SESSION['user_id']);
  die('Нет прав');
}

Output:
session_start();
unset($_SESSION['user_id']);

If you need access from only one device (the last one from which the login was), then we store the last user session on the server and for each request:
if ($user['session_id'] !== session_id())
{
  unset($_SESSION['user_id']);
  die('Нет прав');
}

If there are several, then nothing needs to be done.
With oauth authorization through external services, the session and cookies will be the same.
2 fields auth_provider and auth_provider_id will be added to the database.
In auth_provider you will have vk or fb or google... in auth_provider_id - user id in vk, fb...
When a user presses the login via vk button, you redirect him to a contact. There he does something. Then his contact will redirect to you with ?code=request_code.
You use code to make a request to the contact api to receive an access_token.
Having received an access_token, you make a request to the api to get information about the user. This info should contain some unique id (auth_provider_id).
If you don't have a user with such an auth_provider_id for the vk provider, then you either create it without a login or generate something without a password.
If the user was created or it was before, you put user.id in the session and consider the user to be authorized.
PS:
There are nuances for each line of the answer, but I think the general picture is this.
It's naturally better to write a class for the user to use something like:
$user->is_auth();
$user->auth_by_id($user_id);
$user->unauth();

D
Dmitry, 2015-10-22
@deemytch

In short, the essence of authorization is that the user, instead of his password and login, receives some long, unpredictable string, which he keeps all the time of the session on his side and presents to the server for every sneeze. And except for the server, this line is given to no one.
And the server stores this line with itself, with reference to the user's record.
Additional details are the storage of this string with a time limit, tied to the IP address, browser version and other details, so that you can regulate the number of simultaneous sessions, session time, and try to detect the theft of this string. The string is usually called a hash, although not really. You can not store the string, but check it with another hash, obtained from the first one. And so on as the fantasy and perversion of thoughts grow.

S
Stanislav Makarov, 2015-10-14
@Nipheris

From complete zero. User enters login + password:
User logs in via VK

It doesn't really matter, your task is to map the received information to the user ID in YOUR database, taking into account the necessary checks. VC will be considered a trusted party, i.e. you trust him with the procedure for checking the authenticity of the user. If authentication is on your side, then you check it (check the password against a salted hash in the database, or something else). If you have a "quick login" on VK (without registration), then you need to do more auto-registration if the userid is not found according to the data from VK. True, here you need to be prepared that the user will want to link his accounts if he has already registered with a login / password. Well, or at least warn when logging in via VK that he was not found in the database and a new account will be created so that he is not surprised later.
session ID. As already said, should be hard to copy (copied session id is a stolen session), unique. Google the algorithms or use the standard ones. Store sessions either by standard means, or try radishes (there is an auto-expire, which is nice).
check the existence of a session for a given user (by the user ID from the authentication stage). If there is already a session - kill it, create a new one (the new device will log in successfully, the old one will "log out"). True, nothing will prevent the user from copying the session identifier from the cookies to another device, so you can still write to the IP session, or the user agent (changed - recreate the session).
do not check anything additionally, allow the creation of any number of sessions.
we go to the session storage (standard PHP / Redis mechanisms), request / start the session by the identifier that came in the cookie. If there is no such session (it is outdated, or it never existed, the user himself invented the identifier) ​​- we do not perform authorization. If there is a session, then depending on what we store there, we either get the USERID and break through its rights in the main database, or we get the rights from the session itself, if we cached them there. "Issuance" of rights - there is an authorization procedure. Now, depending on the set of rights, we change the logic inside the script. In large systems, the concepts of roles and groups are used - all this can be googled. In short - during authorization, it is determined in which groups the user is a member. Then, across a set of groups, the roles that the user "plays" in the system are compared (data / user administrator, backup administrator, chief accountant, manager, etc. etc.). The roles are fixed and depend on the logic of the application - depending on the roles the user has, the behavior of the application also changes.
Also now you can find a claim-based approach, especially in asp.net - google it too.
At least - USERID, but you can also cache information about his rights so as not to constantly read it from the main database. Plus, immediately store data related to the session ITSELF, for example, the same login IP, login time, etc. This depends on the task.

V
Vitaly Zhuk, 2015-10-22
@ZhukV

Here you still need to very well separate the concepts of authorization and authentication.
Authentication is user definitions, that is, what kind of user it is. Usually this stage takes place immediately after entering the login password. If the login is correct, we can immediately say: "User is authenticated". For example, if you use HTTP Basic authentication, then if the login/password is incorrect, there will be a 401 error.
Authorization is a check of the user's rights to a specific resource. For example, can the user edit some material (article, comment), can he view some resource. Very often, the concept of " Firewall
" can still " emerge"." is a mechanism for determining the behavior of the authentication / authorization system. For example: In a personal account, it is necessary that the user be authorized, but on the site (docs, other pages), no. As a result, we can create two firewalls that determine this behavior for different URLs
These two mechanisms can work any way you want, the main thing is to follow some rules:
1. Do not authenticate by UserID in any case, otherwise anyone can gain access.
save only the UserID for authentication in cookies, then someone will be able to change the cookie from their side and log in as a different user. server.
3. The password in the database must be hashed, and the check must be based on hashes, and not on real passwords. Otherwise, if someone hangs your database, it is very likely that they will be able to access many other accounts, since many people use the same password.
Personally, for my projects, I always use Symfony Security , since everything in this package is already done for you. The main thing is to correctly connect and configure, and voila :)

A
aqwAntonio, 2015-10-22
@aqwAntonio

I don't want to nerd, but the issue of protecting against fixing the session ID has not yet been addressed, in this case, the session_regenerate_id () function generates a new session ID of the current visitor. the very value of the session identifier in the cookie is set by the session_start () function, and in any case you need to call it, otherwise the sessions will not work
i.e. I want to say that trying to come up with some kind of your own solution instead of using system solutions, you risk forgetting something in the future or not taking into account due to ignorance and the need to use such a function as, for example, session_regenerate_id() , will then cause you a headache,
so in order :
1.1 What to write in cookies/session?
you do not need to write anything manually in cookies, call session_start().
you can write the value is_auth = true to the session after you check that the login and password are correct
1.2 How can I check whether the user is authorized or not on each page?
Well, this is more of an application architecture than a question of just authorization. for a couple of pages, you can make a common plug-in file for checking authorization, and for an average project, it’s better to use the framework right away, but then your questions about authorization will probably change, because. frameworks usually already have the basic functionality of authorization. in the simplest case, check that the value of the session is_auth === true
1.3 If you want the user to have only simultaneous access from one device - how to be?
Well, it's quite complicated, but I'll try to explain briefly
- firstly, you need to store the current user session ID in permanent storage, a database, or somewhere else (i.e. on each page after checking authorization, update the session ID in the database)
- secondly, you need to store authorization sessions in a specific folder specified by session_save_path($dir) function. the point is that the $dir folder should be available for you to read (read the security issue separately)
- thirdly, after successful authorization, you retrieve the session ID of this user from the database (see step 1) and delete this session from the directory (see p. 2), and only then write a new user session ID to the database (again, see 1)
1.4 And if from several?
the same as in 1.3, only earlier you had a table structure, let's say user_id, session_id, and in this case it will be user_id, session_id, device_id i.e. the meaning is that this is not a table of users, but a table of user sessions
Also I recommend reading the book "PHP. Programming Recipes" from O'Reilly, second edition or later
On the second question, in essence, nothing changes, except that it is supplemented by the initialization functionality and processing responses from vk.com. you can read about it on the page https://vk.com/dev/auth_sites

A
alexey_abramov, 2015-10-29
@alexey_abramov

If it is still required, then in a simple and understandable form, how to create authorization on cookies is described here - habrahabr.ru/post/13726

N
nozzy, 2015-10-13
@nozzy

1. I recommend starting with the userPie library, looking at the code, it helped me a lot to understand this whole kitchen.
userpie.com

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question