Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
At this moment users can create an account at my website (username, password, email)
This wil create an entry in the database which stores the username, the hash of the password and the email adress and will set the level of the user to 0. After this it wil send an email with an url that contains the id of the user and a new hash of the hashed password.
$emailhash = password_hash($passwordHash, PASSWORD_BCRYPT, $options);
$url = "domain/validation.php?id=$id&hash=$emailHash";
At the validation page where the url points to, it wil use the hashed password as password and the hash from the email to check if the user is using an existing email adress.
password_verify(hashedPasswordFromDB, hashOfHashFromEmail);
Is this is a safe way to validate a user or should I add an extra table/column for an extra hash? And what are the pro's/cons of my current method and/or another method? (eg. simpler table...)
EDIT:
In case a user want to change his email adress ( something I'm adding at the moment ), I want to implement the same method (sending an url which contains the id, new email adress and a new hash of the hashed password + the new email adress). In my opinion this looks a bit devious but I don't see another way to change it.
Since we've gotten into this, I'm going to throw in my 2 cents on not just doing this but doing it well.
Most people are suggesting that you add a column or 2 to the user table. That is simple and it works.
But if you want to do this well there are things you want to consider:
Will you also support password reset via email
Will you age out the validation or reset
Can you track someone attempting to compromise an account?
Is there some sort of denial of service or other issue going on?
The best way to do this is to have a separate set of tables related to the user table that capture these type of account events.
Here's a list of typical account events:
Account registration
Account verification
Account suspension
Account deletion
Password reset request
Change email
In a robust system, each of these events, which all have a timestamp, will often have an expiration.
Many of them have an associated hash that needs to be stored and sent in an email.
They all have a "completed" flag to indicate if the implied action was completed.
So a better way of handling this is to have a separate related table to user. For the sake of discussion this table would look something like this:
user_event
-----------
user_event_id (pk)
user_id (fk from user table)
created_on (timestamp)
event_type (registration | verification | password reset, etc)
expires_on (datetime) - manually set as is suitable
token (char40) - sha1
is_complete (tinyint) A boolean to indicate if the action was completed
complete_on (timestamp)
user_ip (ip address of end user)
extra (varchar) : store the new email here. Change to old email when you complete the request.
This is a far more robust way of persisting the data needed for these types of activities within a system, and also has some built in logging. You have an audit trail of activities and can handle or prevent repeated requests.
You also can expire reset requests, and use those expired requests to do an aging activity like sending reminder emails to people who never completed their registration.
You now have a system that supports additional account related features without needing a separate additional table, and you can code new events by just creating a new event_type. Those can just be a string, but you might also want to create a lookup table instead and use that as a foreign key to the user_event table.
Better create a separate token (some hash which is sent in the link as a query), which is stored with a timestamp in the DB. This way you have a link and can check with the timestamp, if the link has expired (compare the timestamp of the token with the current time of the request (when the user opens his link).
I would say: extra hash or any random string in your database. There is no need for sending a password or even a hashed password over the line.
Related
I am integrating a user verification feature into a plugin I am developing whereby a user must verify their email address by clicking a link sent to them.
It is based on code provided on Github
At the moment I create a 'temporary' user, then delete the user from the users table. Only after verification is the user added back into the users table.
Is there a way to disable the core user registration in Wordpress so that I don't have to delete the user, therefore it is never stored in the database until it is created by the verification code?
I am finding, quite naturally, the user IDs are skipping every one digit so that for example, a verified user has an id '1' then the next is '3'.
Thanks,
Leon
The standar way to do that is through a field in the table users that is set to true for example whenever the user have validated his email via your link.
And with this field you control that if the field is not validated you dont let them sign in on you website.
So in order to apply this you need to find the sections in your wordpress that control de sign in to put the restriction with this new field
I'm going to be more specific so you can remove the downvote...
Lets think for example that you have a field named email_verify which will just contain a 1 or a 0 if the email is already validated or not.
Then you have another field for example session_token with a sha1 or random token that must be unique for the link that will validate the email when clicking on it.
You need to have a php function that catches when someone enters that link and you do it by extracting the sha1 from the link as an url parameter and searching in your table for whoever have that session_token, when you find a record with this session_token then you turn your email_verify value to 1 meaning the email is already verified and then you turn null the session_token field so the link expires.
I'm adding an option for my users to change their email, and I'm thinking what is the best way of doing it in a safe and fool-proof manner.. so far I have the following options
1) When user changes the email, system stores in a temporary column in the database and sends an email to the new one, requiring the user to click the link to confirm it and only then, change it (I would need 2 extra fields on my DB - temp_email and email_token)
2) When user changes the email, system would gather data from AccountID and New Email, encrypt it and send it to the new email.. when the user clicks the link, system decrypts it and changes accordingly.
I really like the second option, since it does not require saving extra fields on the database.. so my question is.. which one is a better solution? Or perhaps a third one..
I have two fields in my users table: recovery_hash and recovery_time that are updated when a user changes something. I put in a random hash and the current time.
I then send an email to that person (in your case, to their new address), and in the link is the hash (http://foobar.com/verify/randomHashG03sHere). The user clicks the link and it goes to a verify script on the server - which validates the hash and then checks to see if the current time is within an hour of the recovery_time. If both checks validate, I make the change, which, in your case would be updating the users email field with their new email address - which you could store in a separate table, or even in the same users table as a new_email field.
Since you're anticipating the user wanting to change things, you could just store the new email address in a separate table, such as users_temp.email and then update the users table with that new value after it's been validated.
You could just create another table to deal with temporary e-mail addresses (e-mail + AccountID + token + timestamp (possibly)).
I would highly avoid option 2. Keep all your data local on your server! In case someone breaks your encryption he can mess up your entire database or webservice. Especially credentials or email-addresses should never be outsourced. Option 1 is much more recommended, though the data could also be stored in a different manner.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm working on a college project where I have to made a chat that contains invitation options with ACCEPT/REJECT between registered users only. If an invitation is accepted, then open the chat otherwise send a message to the sender.
I've completed the whole project except this invitation option. I know that I can use COOKIE for this (with setInterval), but I need something more secure idea to do this.
In my current PHP invite function, (for example: invitation sender: a#a.com, invitation for: b#b.com) I used to verify the b#b.com user (registered or not) and send back the JSON with verification. If user is registered, then open a chatbox on self-end only (a#a.com) and can send message to b#b.com. The b#b.com user will only gets these message when it opens the chatbox with invitation sender : b#b.com, for: a#a.com.
I have no idea to how to send an invitation directly to b#b.com with option and get back the clicked event (accept/reject) to `a#a.com.
Currently there is a single idea in my mind: cookie with setInterval. But there is a demerit of this idea is, both users page continuously checks the cookie, it means more load on bandwidth and more process on user-end and most of all, it's not secure.
And I'm already user 3 setInterval functions into my project : status check, new msgs check and chat options.
So, can anybody suggest a better approach?
This is rather a broad question, but I'll try to offer some basic design guidance. I expect that a user will enter their email address and the email address of the other person, and click on a "log on" button.
What happens next depends on your design, but this is what I would do. This involves AJAX operations, which is fine for the purpose.
The details are submitted to the server, and a row in a user table is created. The user gets an ordinary session cookie by default, so you just need session_start at the start of each page. A row in a conversations table is also created.
We'll assume that the user is now in a connected but not chatting state.
Using jQuery or similar, a call is made periodically to the server to see if the application status from their side needs updating. To start with, this will determine whether the other user is available. Let's say this call is made every 10 seconds, to avoid excessive load, and every time a call is made, the user table is updated with a last_seen_at timestamp.
You run a script on your server that examines live conversation rows and sees if both parties are online. If they are, and the conversation is not marked as started, then update the row and then notify the users when they next request an update.
When your browser application receives a notification of some kind (in the reply to a periodic AJAX request) it will need to redraw its screen. The life-cycle is: start -> log-on -> waiting -> chat -> log-off. You'll need to work on the JavaScript to do this.
Some of the fields in my suggested table structure below are used to capture the state of the chat, so your PHP application doesn't have to remember things itself. For example if conversation.accepted_by_user_id is null, the conversation is waiting for the second user to accept the chat request. If message.received_at is populated but message.sent_at is null, it means the message needs to be transmitted to the second user when they next send an update request.
Where users or conversations get too old, they can either be marked as stale or deleted entirely.
Side note: we have made no attempt to check that the users own the email addresses they have specified, or whether they even exist. But, for the most part, it doesn't matter - all we need is for the two parties to have a unique string that they can both remember.
Suggested tables:
user (
id (pk) int,
email varchar, // user's email address
email_to varchar, // the email address of who they wish to chat to
session_id varchar,
last_seen_at timestamp
)
conversation (
id (pk) int,
started_by_user_id int, // foreign key
accepted_by_user_id int, // foreign key (null if not yet accepted)
from_notified_at timestamp,
to_notified_at timestamp // timestamp (null if not yet accepted)
)
message (
id (pk),
conversation_id int, // foreign key
is_forward boolean, // true = a->b, false = b->a
message_text varchar, // actual text of message
received_at timestamp, // when it was sent in a server message
sent_at timestamp // when it was picked up in a server message
)
You were worried about the security of cookies. If you use session cookies it means that only the user that initiates a session can use the session ID given to it by PHP (there are a couple of exceptions: the theft of a cookie by a malicious third party via script injection or the capture of data by eavesdropping. You can use SSL and read up on XSS if you are worried about those things, but I would say it is beyond the scope of a college course).
Long story short, you've chosen a non-trivial project! Good luck with it, and if there is something you don't understand, break it down into a smaller pieces, until the pieces are each programming problems.
Now, you can do this project with sockets, but you should learn to walk before you start running. I would suggest you try it this way first (since it is easier but still hard enough) and then if you can do that, move on to sockets.
Ive been asking around for some feedback on my website and one comment I received was the following
"I signed up with email#email.com and managed to active my account with http://www.mysite.co.uk/activateuser.php?email=email#email.com
You need checksums to stop it."
Can anybody elaborate on this and how I can implement them into my activation?
In theory, If I was to create a row named "rand_key" in my DB and when a user registers a random key is stored in the column, could I then use this as the activation as opposed to the email? thus making it un guessable?
You need to create a unique user key, which shouldn't be related to user data. Usually you could do something like hashing the output of a random generator function in order to make it unique and use that. Then you point them to the link:
http://www.mysite.co.uk/activateuser.php?userid=generated-unique-hashed-key
This unique user key should be added as an extra field to the table where you store your user info, or related to the user in some other way. By keeping the key unrelated to user data you make sure nobody can discover a user's key and maliciously activate/do another action instead of your user.
Then you should test the user key on arrival for some conditions:
not authorized yet - authorize
authorized already - some error
wrong key - some error
Also, there should be an expiration date associated with your user, upon which you just deactivate the user along with his key.
The person means you can activate your address by going to that url and simply putting the email address in thr url. You could do this without actually getting the activation email.
By using a checksum, you force thr user to click the link. E.g.
Activate.php?email=aaa#bbb.com&check=A1234b23
At the time of sending the email you would geneate a random code. Store this in your database somewhere. Append it to the url the user is given. When the user clicks the link, you check that the code matches the code stored for that email address. If it matches, validate the email. Else do not.
In theory, If I was to create a row
named "rand_key" in my DB and when a
user registers a random key is stored
in the column, could I then use this
as the activation as opposed to the
email? thus making it un guessable?
Yes. Keep in mind that you don't necessarily want random as much as you want unique (in order to avoid two email addresses accidentally getting the same activation code).
You could do something like:
$key = mt_rand().'-'.uniqid('', true);
echo 'http://mysite.com/activate?key='.urlencode(base64_encode($key));
That would be tough to guess and would be guaranteed unique.
Working on a web based "buying and selling" application with PHP MySQL where users can post adverts for items and services.
Before a new advert is displayed on the system there must be a method of verification to ensure that the user provided email address is correct, and that the advert is legitimate.
I want to send the creator of any new advert an email containing an url which directs to a page whose primary functionality is to receive a posted variable, $advert_id, and to select the advert from the db for updating / editing / deleting.
This variable is embedded in the url with PHP syntax
ie. [http://www.example.com?content=modify_advert&advert_id=2246317].
This part is quite simple to implement, BUT, if a user was to modify this variable called "advert_id=2246317" to any other integer, they can access other posts/adverts in the system.
The system is advert based, and users dont need an account or login to post, so we cannot prompt for a login at the point of verification which would have been convenient.
Any ideas as to how we could protect the adverts/posts in the system from being accessed via the aforementioned url???
Any suggestions?
If visitors will only be viewing that page from the link you send via e-mail, you can include a hash in that address instead of the advert_id — essentially a random, one-time password.
One common and "often good enough" trick for generating such a random password is to take a single, secret, truly random string (I usually use grc.com), concatenate it with the unique advert_id, and hash the whole thing with, say, SHA1(). Like so:
UPDATE advert SET advert_hash = SHA1(CONCAT(advert_id, 'lots-of-randomness-here'))
You could even vary this by adding time(), or (better still) a random number to the end. The outcome is a 40-character string stored in your database that nobody could possibly predict (without knowing the secret data you used to generate it).
For example, I might get this instead of advert_id=1:
f2db832ddfb149522442c156dadab50307f12b62
If I wanted to sneakily edit advert_id=2 (which somebody else created), I'd first have to guess that the hash is this completely different string:
e5c6a3a9473b814b3230ee7923cbe679fcebc922
So, include that in the URL instead of the advert_id (or, if you like, in addition to the advert_id), and suddenly your users are powerless to ruin other people's content.
You could add a salt to the id and then hash it.
sha1($advert_id . $salt);
Send this to the user in the URL instead of the advert_id, and store it in your database, along with the advert_id.
Then when they click the link, you find the matching advert for that hashed value.
Making the salt a secret is how you keep users from 'guessing' a valid URL that will let them modify an ad that they did not post. Perhaps you could use the users email address, the time posted and/or a name or something that the user enters when they make a post.
Generate a GUID as the advert ID so simple ID guessing attacks are unlikely to succeed.