I am building a method for users of my website to link their accounts together, so that resources can be shared between them. My process so far is:
1) User enters email addresses of users he wants to link with.
2) If matches are found, these users receive an email.
3) Email contains a confirmation link. If the recipient clicks this, the connection between the two accounts will be formed.
I'm wondering how secure I need to be with this final step. My confirmation link is in the format: domain.com/link-confirm.php?fromid=xxx&toid=yyy
In theory, it would be possible for anyone to spoof this link, if they knew the user id of their target, thus setting up a connection without permission.
I tried hashing both user ids, then scanning through the user database for matches, but the password_verify function takes so long to run that the page times out (and that's with only 1000 users).
What I would like to know is:
Does my plan above make sense?
Is there a neater way of doing it?
Am I right to be concerned about the spoofing (connecting the accounts does not in itself share any data between users, it merely makes it possible for either user to initiate)?
Thanks
You can just encrypt both id values and after obtaining it from get - decrypt them, hashes don't need to be used here. That way it will take thousands of years for somebody to brute force spoof them.
What you could do is generate some unique data per account linking request and require that unique data to be sent with the linking acceptance request.
So for example user A requests to link with user B, you store the request with some unique data like a random hash and a timestamp, and then when user B clicks "accept" in his email, he is sent to a page on your server. The link in the email contained the unique data that is submitted to the page. You check if the unique data is indeed the data that was generated when user A submitted the request, and, if so, boom, users linked.
Related
I'm not familiar with PHP / MySQL and Emails. And I'm pretty sure this question has been asked somewhere already, but I cannot find it. So I apologise if this is troubling and thank you in advance!
Is it possible to do something that user has to click on a link in email first before the user is added into database???
And you know how, for some websites, they have a unique web address for each email validation (Shown in red on the picture)? How do they create a webpage that's unique in for every email ?
Picture credited: https://kayako.atlassian.net/wiki/download/attachments/5734920/subs-validation.png?version=1&modificationDate=1291956283000&api=v2
Thank you a lot for the attention! If it's possible, I prefer not having straight scripts that I can copy and paste because I like to find out myself :P But please do give me some hints because I'm totally lost.
If there's anything that's not clear, please tell me, I'll try my best to clarify it!
The Registration process
User fills out a form online with basic details including an email and password, and submits the form to register.php
register.php adds user info to a temporary location, such as a pending_users table which has all the fields the user submitted along with an expiration and an activation_code fields. This code can be any random, impossible to guess value. eg: hash('sha1', mt_rand(10000,99999).md_rand(10000,99999)). Just don't do anything predictable such as hash the current time, or the username
register.php sends an email to the user with a URL that will link to activate.php and that includes the activation code. eg: example.com/activate.php?code=a2ef24... The email should also inform the user of the expiration (1 to 12hrs validity seems ok to me)
When user clicks the link, she triggers a GET request to activate.php. In doing so, the user proves ownership of the email address
activate.php gets the code from the request parameters, eg: $code=$_GET['code']. With that code, the script queries the pending_users table for the record matching that code.
If the code is found, check that it hasn't expired before proceeding. Expiration prevents someone else much later who gets in the user's account from completing the registration.
If the code is valid, capture the user details from the matching record and delete that record from pending_users table.
Write a matching record in the regular users table. Until this is done, the user could not log in because login script only checks the users table, and ignores the pending_users table.
Registration complete.
Security Note I:
For your users' protection, never store passwords in cleartext. When you receive it from the registration form (eg: $_POST['pwd'], do:
$pwd = $_POST['pwd'];
//first validate; it should meet minimum requirements
$pwd_hash = password_hash($pwd, PASSWORD_DEFAULT); // <- the hash gets stored
Later, to verify the password, do:
password_verify($cleartext_pwd, $pwd_hash);
It will return true if the password is correct; false otherwise.
Security Note II:
For your protection, never insert user supplied values directly in your DB queries. This means any value that arrives from the outside. Not just usernames, emails, passwords... but also values that you're getting back from the user such as activation_code above or cookie values or headers (eg User-Agent). Instead, learn to use prepared statements. This will protect you from SQL injection.
Not sure if it's possible to add datas in database after the validation...
When I want to do something like that, I create a data in the users table (or metas users table) like "validate".
If this data is "true", then the user already did the validation and he can use his account. If it's still set on "false", the user didn't validate his account : he can't use it.
With that, you have to make sure the account is validate when the user tries to log in, but it's not a big deal ^^
Hope it's usefull.
Those are not a unique websites, there is only one script validating the registration finalization. The incoming requests (when the user has clicked the link) are routed all to the same script by means of server side "request rewriting", so that the random token value is available as an argument (parameter) to the script execution.
What the script does: it checks if that random token value does exist in the database where it has been generated and stored before when the user actually registered.
The only thing left to do for that script is to remove the confirmation random token and/or set a flag indicating that the registered use has actually confirmed his identify (email address) by clicking the link.
Easy and straight forward. Hard to bypass, since you cannot guess what random token value has been generated for what registered user without receiving the email. However take into consideration that it is trivial for an attacking script to use anonymous email services (one time email addresses) to receive and evaluate such a confirmation request, if the process is known to the attacker.
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.
I am having a couple of mails in which I need to implement web versions. But I don't want to pass sensitive information like UUID or userID. I have a "View in browser" link and when user clicks on it, it should take the user to the website page, which will take input from GET and display specific content for each of the user. How this can be implemented ?
I am already using UUID here and passing it through the URL, which will turn fetch the user from DB and display the contents. It is a fool proof method ?
I am doing this in PHP
If it's super-sensitive information, put it behind your sites login mechanism.
If it's just something random people should not stumble upon by accident, just generate a random unique ID (like you do) which you associate with the e-mail and display the user data. Again, this should probably not give any third-party a possibility to change or impersonate the user, just read the e-mail of one e-mail.
I'm currently working on my Referral System, but I have a problem with protecting it of frauds.
Okay, here's how it works for now:
user registers and activate it's account
user now have access to the control panel and there is it's uniqe link in following format: domain.tld/ref/12345
when someone other click to user's link, he or she must to click a specific button to confirm that is not some kind of fraud (like "click here, you'll get $100" or something)
system writes visitor's IP in a database and some data to cookies to prevent re-pressing the button. User now have +1 point.
But, the problem is that visitor can change it's IP, clear cookies and hit button again. It takes a few seconds, and that's not OK, that's cheating.
How to prevent it? Is there some trick to get some unique computer ID or something can't be changed that easy?
Really the only options are to tie the process to something which is not so easily manipulated by the user - super cookies, browser fingerprints, OpenID, Email addresses and telephome numbers (the latter 2 using some sort of validaton step before a vote is counted)
The only way you can be certain a referred party does not reuse a referral code is for the original user to send different one-time-use-only referral URLs to each person. Once the code has been used, it is flagged as such in (or removed entirely from) your database so that it can not be used again.
How you prevent the original user from sending multiple links out to the same person is another matter - and not an easy one to resolve.
Who do you perceive to be the threat?
Although it's certainly not 100% accurate, you can still fingerprint visitors using for example a combination of their ip, browser user agent, and with some javascript you can even go for screen size or installed fonts. Using these pieces of information you can set up a system where you save the fingerprints in datatable and in the same record you store the session id (from the cookie). Now when a new visitor arrives you can test their fingerprint against the db of recent fingerprints with different visitor ids. If you find a large number of matching fingerprints (you define the threshold) with different sessions then you can alert for the possibility of fraud.
Cheers
How about storing the link with with the user when they navigate to the link. then in the database you will have the link and if the users has already been to the link then deny them. Seems like it could work then you wouldn't have to worry about the cookies etc...
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.