0

Okay,

So I'm brainstorming about a security architecture where on a website you have a 'secret' page, where a visitor (not user, just visitor) can enter 'secret' info. The visitor doesn't need to give in a password or anything, it's all automated and secured by cookies and session-variables. Normally the only credential needed to get access to this secret page, is a cookie or session_id. So, when a hacker does cookie-stealing and edits his own cookies with the one of the actual user. He can access the secret page anyway. I hoped I figured out a way to prevent this.

First of all, the secret page only remains as long as the user stays on the website (really like a session).

So, I came up with this:

Server-side:

Databases:
Table 'General':

+----+---------+-------------+------------+------------------+
| Id | Page_Id |  Page_pass  | Session_Id | Encrypted_String |
+----+---------+-------------+------------+------------------+
|  1 |   60536 | hash("vbn") | 7XA8B      | R79B6ZF          |
|  2 |   78421 | hash("wxc") | 544X2      | B08Z7FX          |
+----+---------+-------------+------------+------------------+

Table 'Keys':

+----+-------------+
| Id |     Key     |
+----+-------------+
|  1 | hash("abc") |
|  2 | hash("xyz") |
+----+-------------+

Table 'General' Columns:

  • Id: Just the primary_key (nothing special).
  • Page_Id: Unique (random generated?) Id of the secret page.
  • Page_pass: Hashed version of the randomly generated password of the secret page.
  • Session_Id: Unique session_id of user, stored in this DB and cookie.
  • Encrypted_String: Result of: encrypt(PagePassword, sessionKey). So only the user with the right sessionKey (this can only be the right user?!!) can get the page-password needed to enter the secret-page.
    PagePassword: Non-hashed version of the randomly generated password of the page.
    sessionKey: When user visits, unique session-variable gets made with a randomly generated key.

So, a bit of explanation. It actually goes all like this:

  1. User visits website and gets assigned a session-id, and a chart-id. These are stored in a database, and in his cookies.
  2. When the user visits, there also is a session-variable which holds a random generated value. This is the key. To make sure the key is unique, we first check if it doesn't already exists in the Key-database.

  3. We also encrypt (not hashing) the 'random generated page password' with the unique session-key and store it in the fifth column. The hashed version of the password is stored in the third column.

Client-side:

Now, that was the info handled and stored at server-side, client-side this info is stored in cookies:

+------------+-------+
| session_id | 7XA8B |
+------------+-------+
| page_id    | 60536 |
+------------+-------+

Note: Server-side, there is also an unique session_variable with an unique key stored for this user. Not in the database, not in the cookies.

If the session_id, and page_id were the only needed credentials for accessing the secret page, an attacker could steal the cookies of this user, edits his own, and then view the secret page like that.

Request secret page:

However, this happens when the user visits/requests his secret page:

  1. We decrypt the encrypted_string with this function: decrypt(encrypted_string, session_key). This way we have the password of the secret page, and only the right user can get it, because only he has the right session_key.
  2. We check if the users' session_id matches the one needed for the secret page, and we check if the hash of the decrypted password matches the hash of the password needed for the secret page. If it does, he's authorized.

Attacker:

Now, what if an attacker HAS stolen the cookies of the other user, and edits his own cookies with the stolen ones?

New stolen cookies of attacker (same as of actual user of course):

+------------+-------+
| session_id | 7XA8B |
+------------+-------+
| page_id    | 60536 |
+------------+-------+

So, the PHP-code would now go checking the session_id and page_id, and those match because they exist in the same row. That row also has the hashed version of the password of the secret page, and the encrypted string which is the password of the secret page encrypted with the session_key.
But mention: Because the attacker also got a randomly unique generated session_key, it differs from the one of the actual user. So he can't decrypt the encrypted_string to get the password of the secret page needed to enter that page. Because, he can steal and alter cookies; but not the session_variable (I hope?!).

Also, some things in this example were pseudo. Encrypt and decrypt of course ain't real working functions, nor it's outputs.


tl;dr: Each user gets a random key stored in session-variable (not cookie, not database). In database we store the encrypted version of the secret-page-password with that key. Because each user gets a unique different session-variable-key that he of course can't alter, only the actual user/person of that secret page can decrypt the password needed for that secret page. Even if his cookies were stolen.

Questions:

  1. Is my theory right? Can with this architecture only the actual user enter his secret page?
  2. Is it practical? I mean to code, and for the user/visitor?
  3. This only works as long as the user has the website open, right? Or can I persist session_variables even after website-close, or even browser-close?
  4. What if session_key would be the user's IP instead of a random generated password? Then this could persist, but be unsecure with VPNs and proxies.
  5. (Related to 4), what if there'd be a third database, which holds all the 'active' session_ids of the last X amount of time, and the IP used with it. Than the attacker can't change his own session_id because the one of the user is already in a database?
  6. Any other things?
  • Why are you unwilling to trust session cookies for being secure? Do you have a reason to believe that they are especially vulnerable for you? – Neil Smithline Jul 12 '16 at 0:55
  • I don't understand what you mean? Cookies are just plain-text, no way to encrypt them, because if you do, you have just weird plain-text. If B steals that plain-text-cookie from A and pastes it in his own browser. B can enter A's info. My post is all about not letting B access A's info even with stolen cookies. – O'Niel Jul 12 '16 at 0:58
  • 2
    Note that the session id is in a cookie, so you're only covering the lock with a Kleenex. That said, I really don't get your concept of secrets that last for the duration of the session. If they don't persist, why would people waste time writing them? – Julie Pelletier Jul 12 '16 at 0:59
  • 2
    I understand that the cookies are clear-text, but they are the standard for session management. OWASP recommends them and practically everyone uses them. If your browser leaks its cookies, then you are in big trouble. Combining IP address with cookie-based session is reasonable, but I don't think that you need to reinvent session management from the ground up – Neil Smithline Jul 12 '16 at 1:49
  • 2
    Using the PHP session variable would mean that you are trusting the server, not the user (which is good since the user is the untrusted mutable data). The question is, if you are using the session variable, why at all would you use cookies? In addition, why store anything when it can just be put in the session? – sparticvs Jul 12 '16 at 2:05
2

You should set your cookies with "httponly" and "Secure" options. That will prevent that cookies could be hijacked using Javascript and be sure SSL is used. There is a way to check if the cookies are "httponly" using session_get_cookie_params, which can increase the protection. Also enable HSTS in your web server.

While it will add a little of safety, it won't prevent hijacking at 100%. For example, I believe that httponly+secure cookies can be set in any forged browser (not tested or proven).

You can also use some kind of browser fingerprinting, to identify your customers. Using the IP is not bad idea if the session last for few minutes and you expect them to generate the session if changes.

For your project, I will suggest you to look into: mod_auth_pubtkt which uses DSA or RSA schemes to automatically authenticate users.

I will try to address your questions:

Is my theory right? Can with this architecture only the actual user enter his secret page?

It seems to me a little bit complex for such task. Not sure if I have all the information to tell you, but a feel a simple session is enough. Remember that complexity reduces security.

Is it practical? I mean to code, and for the user/visitor?

If your "secret" page is very secret, then I think using user/password scheme its a better idea.

This only works as long as the user has the website open, right? Or can I persist session_variables even after website-close, or even browser-close?

As long as the browser is still open, the session will persist (for example, if you close a tab it won't erase it). Also check PHP setting: session.cookie_lifetime which may allow the session to persist even after closing the browser.

What if session_key would be the user's IP instead of a random generated password? Then this could persist, but be unsecure with VPNs and proxies.

Also be aware that most of the local networks share the same public IP (so you can't identify unique users that way if they are on the same local network).

What if there'd be a third database, which holds all the 'active' session_ids of the last X amount of time, and the IP used with it. Than the attacker can't change his own session_id because the one of the user is already in a database?

If they are connecting from the same local network, how will you protect hijacking? I don't think that will solve it.

Any other things?

In general terms, session cookies are pretty safe (and widely adopted). As they can be hijacked (hard but possible), an alternative is to do not use sessions. If you want to allow X person to Y page, then generate a link with a unique hash. Then, only that person can access Y page as the hash matches the id. For example: <a href="/pages/?id=2888&h=xxxxxxxxxx">... where "xxxx..." is something like: sha256("some padding".$id."extra".$IP). Then, you can test that hash when the page is loaded. An attacker must have that URL in order to access and their IP address must match. The advantage is that there is no sessions and no cookies involved. In your database, you can have flags, expiration date/time, number of times it can be accessed, etc.

5

If I understand this correctly, this is a lot of complexity with absolutely no security gain at all.

The one thing that the whole scheme hinges upon is that an attacker stealing the cookies would not also get session_key. So you are guarding the session ID with a session key. But who guards the session key? According to you:

Each user gets a random key stored in session-variable (not cookie, not database).

Well, how is the session variable connected to a specific user? Through a session ID in another cookie!

That is how PHP sessions work (or any other sessions for that matter). PHP automatically generates a random session ID and sets it in a cookie. If an attacker has the ability to steal cookies, surely she will steal that cookie as well. This means that when she sends a request with that cookie PHP will happily load the session variables associated with that session ID, including the session_key.

Think of it this way: You have something valuable that you put in a locked box, and you put the key in your pocket. But then you start thinking, what if someone steals the key? So to be safe you take the key, put it in another locked box, and put the key to that lock in your pocket. Are you safer now?

No matter how much complexity you add to a scheme like this, in the end it will still just be turtles all the way down. Instead, you should focus on protecting the one and original session ID (e.g. by using HTTPS and setting the secure and HTTP-only flags).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.