Hash id in url php - php

Logged in user on my site can create documents, pretty much like on Google Docs. The document can be made public by the user, or private (defualt). The documents are stored in a database table like this:
| id | title | content | public | owner |
| 1 | asd | asd | 1 | 1 |
| 2 | asd | asd | 0 | 1 |
| 3 | asd | asd | 0 | 2 |
If public equals 1, it is a public document that can be viewed with a link from any user:
site.com/documents/id
The thing is, even though documents can be public, I don't want users to be able to just increment the url ID by 1 all the time to access all public documents:
site.com/documents/1
site.com/documents/2
site.com/documents/3
And so on...
So maybe I should hash the ID or something like that? Like so:
<?php echo 'site.com/documents/'.md5($id); ?>
Problem is, I can't figure out which ID it is on server side since it is hashed...
What can I do about my problem?

Depending on your security requirements, you should ensure that your document IDs are actually random and not guessable. If you simply hash the auto-incrementing ID, the resulting hash may seem random, but once someone notices that you are simply hashing increasing numeric values (and correctly guesses your hashing algorithm), it is easy to guess possible document IDs.
To achieve this, you could simply hash random numbers (make sure that there are no hash collisions in your database), or work with UUIDs (see this question for an example on how to generate them).
In order to map your hashed identifiers to existing documents, simply store the hash alongside the document in your database (best use the hash as primary key).

You should definitely hash it. Notice that md5 is not secure enough this days, so you may want to take a look at Sha or Blowfish (even if the latter seems an overkill there).
Then you just have to store the hash in the database table that contains the documents properties.
Otherwise you could just create a random hash yourself to identify the document and use that instead of the ID (and obviously check that Murphy doesn't make it so there are two documents with the same hash).

How are you validating that a private document is being viewed by the owner?
While having random ids is certainly helpful in preventing easy guessing of document ids, it seems you're looking at security by obscurity.
In your documents controller you need to check if public == 0 that owner == $logged in user. Within this method you would also verify your unique document id.

MD5 is not ok for hashing numbers, anyone can reverse a numerical md5. I would recommend something a bit stronger, like SHA. (You can also encrypt the entire URL, for more security, as it wont be crackable easily - it wont take up any extra space, as all hashes are the same size regardless of how much data is hashed)
You need to store the hash in the database, and only store it for public files. So any url that has the following URL structure:
"site.com/documents/65hd83jd8h..."
you can lookup in the database, as the hash will be unique.

Related

PHP-MYSQL encryption that is safe

I'm working on a messagging app, and I would like to encrypt the messages the safest way possible.
Currently I'm doing the following:
chatMessages table
userId | message
---------|---------------------
1 | ENCRYPTED%withChatMasterKey%
2 | ENCRYPTED%withChatMasterKey%
...
chatUsers table
userId | chatMasterKey (it is encrypted aswell with users ID's)
---------|---------------------
1 | ENCRYPTED%withUserId(1)%
2 | ENCRYPTED%withUserId(2)%
...
The messages are encrypted with a random masterKey that are stored in the chatUsers table where with another encryption the masterKey is encrypthed but now the key is the user's Id
So to decrypt the messages, you have to do this in php:
$message = $messagesArray[0]["message"];
$chatMasterKey = decrypt($chatUser[0]["chatMasterKey"], withKey: $userId);
$messageDecoded = decrypt($message, withkey: $chatMasterKey);
Tthat works well, if somebody hacks the dataBase then he would not be able to read out the messages.
But is this safe? If someone hacks the .PHP files aswell, then he will be able to figure out the method I'm using and could be able to decrypt the messages.
Is there a better way to encrypt messages?
/ for security reasons I changed some details in the post /

Should I store app settings in one column array? or create a multi-column table?

I'm building my first app right now, but I'm new to mysql databases.
I want to store users personalized settings in database, and here are two scenarios to make that happen:
First one:
COLUMNS: "uid" | "app_settings"
ROWS: 1 | 0,1,0,1,ffff00,#ff0000
Which is storing them as an array, and breaking them up by PHP explode.
Second one:
COLUMNS: "uid" | "show_menu" | "show_toolbar" | "show_email | "menu_color" | "toolbar_color"
ROWS: 1 | 0 | 1 | 1 | #ffff00 | #ff0000
Which is storing each in a separate column.
Both ways work fine, but I want to know if it's a bad practice to use the first method.
Does the extra processes to break apart each value is overwhelming for the server resources in a large scale? (Using the PHP explode) or selecting multiple columns is somehow just like exploding them by php in terms of processing speed?
It all depends on what for do you intent to use this data.
Main purpose of using separate columns in database is to have ability to index such data.
If it is a matter of storage only you can use your storage format in one field, but it is much better to use well known format as json (json_encoding in PHP before storing in db, and json_decode after reading).
Also if you really want to save up space, then assuming, that things such as "show_menu" / "show_toolbar" are simply boolean flags, you can store them in one number as a bit fields. For example field named show_rights may have value of 6 which translates to binary 110, so [1: show_menu][1: show_toolbar][0: show_email].

Storage - Logic/Performance - PHP/MySQL

Okay, here's a standard users table;
Full Name | Birthday | E-Mail | Username | Password | Facebook | MySpace | Twitter | LinkedIn
Nothing unusual about this, it's fairly standard and text book. However, instead of multiple social networking columns for each network it could be stored like so;
Full Name | Birthday | E-Mail | Username | Password | Social
The difference being the information would be stored in the social column as an imploded array rather than in separate columns. It's quite sensible, so if there are into the thousands of users surely it would be quicker to process via script and less hit on the database.
Can anyone think of any DISADVANTAGES of using the suggested method instead of the text book method?
The two disadvantages I can think of:
It will be more difficult to query for social details specific to a certain user. If you knew their Facebook username was fbuser123 then you might have to query for something like SELECT * FROM users WHERE social LIKE '%fbuser123%'.
It will be slightly more difficult to use the information once it's been selected from the database, for example: Requiring that the field be json_decode'ed before it can be used.
Other than that, I can't think of anything else.
I would imagine that if you did this, the most efficient way of storing the data would be in TEXT format and json_encode the data.

Serialize vs Implode

What do you think is the better way to go about storing a few image id's inside a record in a MySQL database? It's just the image id's which will be used to fetch the images from a different library.
Do i implode the id's in the record like 1#4#7#9#10#12 or do I just serialize the array and store that? Are there any performance benefits by using the one instead of the other? Stability preferences?
I have just always used implode and explode, never really gave it much thought.
Thanks.
If you don't want to (over?)normalize your tables, and you really just want to store a list of ids then I suggest using a simple comma-separated list, because already MySQL has some functions which can directly deal with comma-separated string values:
FIND_IN_SET:
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
SELECT FIND_IN_SET('b','a,b,c,d'); --> 2
CONCAT_WS: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat-ws
SELECT CONCAT_WS(',','First name',NULL,'Last Name'); --> 'First name,Last Name'
Of course, you won't be able to do SQL JOINs, but it still can be helpful.
I would pefer serialize or JSON-encode.
It is more flexible and for example will allow you to add image title and other details there in future...
As far as I know there are not significant differences in this case but implode() is a bit faster since it assumes an array and serialize() does not know what you are passing to it.
EDIT based on OP's comment:
Well all the images are stored in a seperate library table with the title and descriptions and things like that. But yeah I see your point.
In that case is not a good idea so serialize several IDs into a single field. What you need is a *-to-Many relation between your 2 tables. This is the correct way of represent multivalued fields:
+----------------------+
| USER |
+---------+------+-----+
| user_id | name | ... |
+---------+------+-----+
+----------------------+
| USER_PICTURE |
+---------+------------+
| user_id | picture_id |
+---------+------------+
+--------------------------+
| PICTURE |
+------------+-------+-----+
| picture_id | title | ... |
+------------+-------+-----+
My friend, serialization is to obtain a string representation of an object's status. Even if it works i don't think is the best way to do what you want. I would prefer to store a json object with the ids. Because a json object is multiplatform, is a string and is easily readable by a human i think is a good approach.

How do I add "friends" function in PHP?

Hello stack overflow I need help with this problem.
Ok, I have a flat file database in php it records users , hobbies, fav movies and all.
Now i want to add a buddy system so they can have friends and send messages to each other in php without SQL.
Consider having another table (er, flat file?) that maintains links. "Mark" and "John" are buddies if there exists a row in this table (ff?) that links "Mark" and "John". I'd recommend using some sort of index (you know, like a primary key).
Suppose you have a users table (or flat file, whatever, it doesn't matter that much) that contains users and some data, it looks like this:
UID | Username | Hobbies
------------------------
1 | Mark | Swimming, Sailing, Skiing
2 | John | Biking, Paragliding
3 | Suzie | Flying, Skiing
And you have this other friends table (again, flat file, whatever...):
Pair ID | A | B
----------------
1 | 1 | 2
2 | 2 | 3
We've encoded in this friends table that Mark and John are friends, and that John and Suzie are friends, but with the absence of relation 1 and 3, we know that Mark and Suzie are not friends (at least according to our records).
Note that if you want to get all of John's friends, you have to find all rows in your table (or file) that have John's UID (here = 2) in either column A or column B.
Well I am afraid there's no magical answer or a magical PHP function you can call to enable this behavior.
If we are to help you at all we really need some more to work with.
If you really, for mysterious reasons, decide to stick without a SQL database - then I would probably still "tilt" towards a SQL like way of storing it. Assuming you're currently storing each user as a row in a file, with each "field" separated by some character - simply add another "field" in the file and have this containing each "id" of every user that they're friends with (id, being whatever you use for that, could be a name as long as it is unique).
As for the messages, another flat file describing the message itself, sender and recipient would probably be the way to go.
Now the real question is, why so eager to avoid using a SQL database? If it is because of having to install a database, try SQLite

Categories