Does anyone have any ideas on how you could prevent a user from posting their password on a site using php?
You could entirely forbid (for passwords) using dictionary words, names, dates or anything other sequence of characters that people might use in a conversation. Then, for every message, loop over every word in the message, hash it, then compared it to your store of hashed passwords.
This would be require a lot of CPU, and be easy to bypass though.
If people want to be idiots and tell other people their account details, you can't stop them.
To save them from phishing, you can only educate them.
To save yourself from multiple people sharing a single account, you can only look for patterns which suggest the account is being shared (such as being logged in from many different IP addresses at once — but be careful as people may access a service from a computer and phone at the same time, or use an ISP that slaps a rotating proxy in front of its users).
You can store the password in session or where ever you want and try to match the password when the user post a comment but I wouldn't do that because:
you will end up storing the clear password somewhere which is really bad
you will clutter your code with hundred of useless checks
I think in this case the prevention is the way to go, just make a nice blurb on your registration and login pages that user shouldn't give their password, post it on site.
The other way to go is like BeemerGuy mentionned jsut hire some humans to moderates the comments on your website.
Did you ever see it happen? Probably not!
Why:
Or you need to save the password as plain-text (lucky hackers!).
Or you need to hash each word to compare it to the hashed password, very expensive.
So you just can't do it properly!
Don't even try it, explain the users why it is bad and just hope they don't post it ...
Related
I run a service where users can log in, but I will never have a need to send an email to them. I try to keep user data as anonymous a possible. I'm not interested in user tracking, selling data, etc. I know there will be simpler solutions to this question, such as "don't use email addresses in the first place" but they make a good login identifier because they are GUIDs. My service goes though the process of having the user verify the address, that's the only email I'll ever send.
So I had the idea of storing the addresses anonymously. My first thought was to simply store the SHA512 hash of each address, but in the event of a breach - which I believe my security would prevent - technically somebody could use rainbow tables to recover at least some of the addresses.
To use a salted hash, I need some way to narrow down the potential result list so I don't compute hashes for every user for every login. That won't scale. To achieve that, my idea was to store the first 5 characters of the SHA512 of the email. That wouldn't be a unique value of course, but it gives me a smaller pool of potential matches. Technically, this all works great.
My concern though is this is still vulnerable to rainbow tables. Those 5 characters are enough to look up possible inputs, and the attacker would already know that only inputs that look like email addresses would be valid. They'd still have enough to determine the email address given the first part of an unsalted hash and entire salted hash.
Am I overthinking this though? For the record, I'm using pgsql and php in this case, but that's really an implementation detail.
Update: I'm still not sure if I'm going to go ahead with this, but for anybody curious, the problem with rainbow tables here can be solved rather easily. Rather than hashing the whole email and taking the first few characters of the hash, use the first few characters of the email as the hash input and store the whole hash. It achieves the same effect, but at best the rainbow table will only reveal the first few characters.
To me, I think yes. You are over-looking.
no matter how strong your structure is, there is always a small chance of breach as nobody is perfect and no can be the human made script.
I think you should go for the best option you think it is and then stick to it.
Some things are best left to fate.
Good Luck
I think you're overthinking this. You stated that you don't need to email the users down the road, so my question back to you is why do you need to store the email at all? You mention that it's a good GUID, but if you're that concerned about data security, would it not be easier to let users define a username upon email verification?
Basically, I picture an ephemeral usage of the email, where it's never stored in the database, and only used to send a validation email. This would allow you to send a custom one-time-use link to the email, which would allow your user the chance to create a custom login name, which you could validate against your database to make sure it is unique.
You could then safely store this unique identifier without the concern that it would lead to email insecurity.
All of that said, I don't think any of it is necessary. As you said, email is an excellent GUID. What makes it an excellent GUID is that it is so widely known and available. The risks associated with the release of a plaintext email are far fewer and less damaging than the risks of a plaintext password. I believe our time as developers is better left securing the private data, and not the public data.
(I'm sure I'm not the first person with this issue, but I wasn't able to find much via Google/Stack Overflow. Apologies in advance if it's a duplicate.)
My site can be used as a data source for the program Mp3tag: it accesses a page on my site, scrapes data, and uses it to tag mp3 files. I want "vip" members of my site to have access to higher-resolution artwork.
Unfortunately, Mp3tag acts like a fresh browser each time: there's no cookie/session data, and the program can't display any sort of "sign in" prompt. So my issue is that I need to [semi-]securely authenticate a user without having them sign in.
My plan is to store a simple md5 hash for each vip member, have Mp3tag include the username/hash in the url it uses to access my site, and then have the server authenticate this. (For the record, I'm using PHP/SQL.)
(Note: I don't need this to be super secure. I won't be using the hash for any kind of sign in or access to anything else on the site. The worst case scenario should be that someone manages to guess a vip member's hash, and then has access to high-res artwork―if that's the worst case, I'm ok with that.)
But will this simple hash cause security issues elsewhere? All passwords are hashed/salted, use PHP's password functions, etc., so having a separate md5 hash (that's unrelated to password) shouldn't cause any issues, right?
And secondly, is there a more secure way to do this? I guess I could add some sort of IP address checks, but that's the only other idea I had.
But will this simple hash cause security issues elsewhere?
No.
All
passwords are hashed/salted, use PHP's password functions, etc., so
having a separate md5 hash (that's unrelated to password) shouldn't
cause any issues, right?
Right. This is a simple "something you have" authentication. It's basically a key that's relatively easy to copy. Not the strongest mechanism, but you're only protecting an image, so it doesn't have to be. As long as your actual account authentication uses separate credentials, you're not weakening that.
And secondly, is there a more secure way to do this? I guess I could
add some sort of IP address checks, but that's the only other idea I
had.
IP-based access can be very effective, but tends to be a real pain when your clients move around. It's probably not worth it for this level of protection.
You might use a stronger hash, but that's irrelevant if the page isn't served over HTTPS.
I think your idea is fine, just use random_bytes() as the source, not something predictable like the username. Think of it as just a second password that they don't get to make up.
I am creating a website whereby users are given an account by invitation only, and are sent a unique code by post. Users can then log in (at least the first time) by entering the code only.
The goal of this is for it to be extremely easy to understand and use by non tech-savvy people.
User accounts will contain name, email, maybe address if the user wants to add it. No other sensitive information.
The site itself would not be of interest to anyone other than those invited, and will not be indexed by search engines.
If you imagine the users are receiving a piece of mail in the post which says something along the lines of:
Please visit www.example.com
Log in with your unique code:
A6XH3
As for the code, it must be extremely easy to remember and enter.
I was planning four or five upper case alphanumeric characters - e.g. A6XH3 - because I don't want anyone to have to enter a long hash or complicated string. I think 6 characters is the limit that I would deem acceptable for people to enter in this format.
An alternative idea I had was to use two/three easy to spell words, such as [adjective] [noun] which would be more fun and seem less "techy" to the users - e.g. pretty blue flower - which would be more in keeping with the spirit of the site.
Caveat
Website administrators must be able to see all the users' codes in plain text, so they can mail them out in the first place and/or offer support to anyone unable to log in. They may also need to generate a new code for some reason, and tell the person directly.
Is there any alternative to storing the codes as plain text in the database?
Questions
Is this secure enough for the context? i.e. The only people who know about the site are those invited, and there is no real motive for anyone else to try to force their way in.
Would you use either of my methods of unique code generation, and if not what would you suggest as a better solution?
Is there another way I could allow a simple login without compromising security or simplicity of use without a username?
Reminder
There is NO registration process and users don't choose their own code. Their account is created by the website administrator, and the site randomly generates a unique code for them.
Is this secure enough for the context? i.e. The only people who know about the site are those invited, and there is no real motive for anyone else to try to force their way in.
Not really, as it would allow an attacker (disregard the notion of 'no motive to force their way in') to brute force a login - just like any other login system, apart from in this instance you'd only have to try four or five upper case alphanumeric characters and not an e-mail and a password that adheres to various character sets.
Of course, you could do the following to help prevent a brute-force;
Add a captcha to fill on every login request
Two-factor authentication via SMS or E-Mail.
Would you use either of my methods of unique code generation, and if not what would you suggest as a better solution?
Both methods are fine in my opinion, as it's just like a site not enforcing "strong" password character sets. However, the reason for the code to be in plain text is no different than storing passwords (in the conventional sense) in plain text - you just don't.
Generate the random code
Send it to the user (securely)
Encrypt the code and store in the database
Is there another way I could allow a simple login without compromising security or simplicity of use without a username?
Simplicity is a relative term as it depends on your users. I would strongly recommended adding two-factor authentication via SMS or e-mail as outlined to my answer to your first question.
You could also use social media APIs to login. You'd then be giving the security to the social media platform and the user (without holding all the security concerns on your end, to some degree).
To raise points in your question that weren't explicitly defined as a question.
Website administrators must be able to see all the users' codes in plain text, so they can mail them out in the first place and/or offer support to anyone unable to log in
No. I see no reason why you'd need any human interaction, nor have a site administrator to see the passcodes in plain text - anything your administrators can see, a hacker can see.
When a user is unable to login, they should verify their identity via e-mail or SMS or security questions (or all three?), and have a new code generated for them via the system and sent to the user. The new passcode should be immediately encrypted and saved into your database.
User accounts will contain name, email, maybe address if the user wants to add it. No other sensitive information.
Any data that can be used to identify someone (for example their name, email and address) is considered sensitive.
Ultimately, no. Authenticating with a single piece of information is dangerous. I touched on this subject when I covered securely implementing "remember me" checkboxes. Your database lookups are going to leak timing information and allow attackers to trivially guess a valid code. (And implementing constant-time search algorithms is not a good idea.)
Having an authentication mechanism based solely on one value is a very bad idea. Always have two inputs: one for database lookups, the other for constant-time validation.
In most authentication systems, the username is used for the database lookup:
$userData = $pgsql->dbQuery("SELECT * FROM accounts WHERE username = ?", array(
$_POST['username']
));
...and the password is, ideally, compared outside of the DB query:
if(\password_verify($_POST['password'], $userData[0]['passwordhash'])) {
/* good password */
}
Aside from timing leaks (which may lead to timing attacks), having only one factor means that you can't benefit from a per-user salt without evaluating every single user in your database (which would be an enormous performance drag with a sufficiently large number of users).
With these requirements, you have to do something like:
$result = $pgsql->dbQuery("SELECT * FROM accounts WHERE password = ?", array(
hash($algo, $_POST['password'])
));
...which goes completely against best practices.
My advice: Bite the bullet and either use two pieces of information (an identifier and an authenticator), or eschew authentication completely and work with OAuth, OpenID, SQRL, Mozilla Personas, etc. Feel free to implement this if you really want to, but it will not be secure.
There are many good ways of doing this, if you don't want to change the unique code. You could use API's for IP location and then you could create like a pattern of the places where the user has logged in from and then once you have enough data of the location, IP, maybe user agent? or even ISP you could use an algorithm to determine any alterations in pattern you collected, and then block that user account temporary till he/she confirms it was them using the account?
This is just an idea, its kind of complex and probably to extreme for some people, but that's what I would try to do if I just waned a login system based on a unique key.
You can do it the same way, as you would do a with a password-reset page:
Let the user register with his email.
Send a link with a token to the user, a hash of the token is stored in the database.
If the user clicks the link and if the token is valid, welcome him and let him enter his own password.
If you send the user a link with a token, (s)he can simply click this link and does not have to enter a code anywhere. The token can then be a strong token like:
http://www.example.com/register/8eM2WwsuR59MnmyswYoQ
In the database you should store only a hash of this token, though if the token is strong, the hash can be unsalted and the algorithm can be fast like SHA256. When you implement it this way, you also have the password-reset for free.
Is it a horrible idea to email users their password on sign up - before it's hashed by the server side code and stored into the DB?
If it's user-entered, yes, it's a bad idea. E-mail is unencrypted and can be intercepted in transit between your mail server and theirs, as well as potentially being readable by folks with access to the two servers.
If it's a one-time temporary password, the risk is smaller, as they should change it shortly afterwards.
I'd email them a temp password, then require them to change in upon first login. Granted someone could change it before the user got the chance.
Part of the answer depends on how secure you think your credentials need to be. If you're a bank or any other site that deals with PII, then it's absolutely a terrible idea. But if you don't think there's a real payoff in cracking your site, then you can use your own discretion. It's definitely not a good idea from a security standpoint, but if there are organizational factors such as budget or legacy code that may drive you into such a corner, then you can consider it.
Also, I agree wholeheartedly with the other folks who answered suggesting not to send a user their password if they've picked it. That's an unnecessary potential security hole!
Better not, because if users specify an incorrect email address, other people can login using their information.
Also, you can make it more secure by not allowing to reset your password if you didn't login at least one time with the password that was used for the registration.
My opinion is this.
Option 1 - if user picks his password, don't mail it.
Option 2 - if you generate a password, send to user, have a link to active his account and change password.
Depends for what users get registered, each option can be used.
I'm working on a small webapp that generates exercise program printouts. A user (ie personal trainer) can create an exercise program, then enter the email address of one of their clients. A link to the exercise program then gets sent to the client, like so...
http://www.myurl.com/generate.php?hash=abiglonghash...
The hash is a sha512 string.
I don't want people to be able to easily discover other people's exercise programs. At the same time I would really prefer to avoid prompting people for additonal password info, etc, when they click on that link. I would like a client to click on the link in their email, and immediately get their program, no fuss.
I'm wondering what thoughts are as to the security of the above, without additional authentication? I know it's not Fort Knox, but it seems about as safe to me as a typical "Forgot your password" system. Any thoughts, suggestions as to how this could be improved, without getting into full-blown user authentication?
Thanks in advance,
A "forgot password" system typically does a few things:
Requires you to "know" something once you get to the page (like your mother's maiden name, your high school, etc)
Sends you your new password in an email. Even if you get to the 'forgot password' URL of another user, the new password is sent to that user's email address on file. This means you would need access to their inbox, as well as their "secret question"
For your purposes, a SHA512 string should be secure enough. Using a SHA512 is similar to using a UUID, in theory. It is long enough to be statistically improbable that someone could guess someone else's hash. The odds of it happening are astronomically high.
Of course, there are always easier ways than guessing to get access to someone else's hash. Things like the user's browser history, intercepting their net traffic, looking over their shoulder, etc. Only SSL combined with a protective login system would protect against those things.
Security always brings up questions like these. Obviously the only way to keep all the people you want out is to keep everyone out! But that is not going to work.
If all you are interested in doing is shallowly hiding a user's workout program from another, then what you are doing is not a problem at all and there are no security issues.
If someone guesses (or investigates and finds) a link to another workout program, then there is nothing you can do to stop it with your system. If that is a concern, then you are going to have to come up with another method to know who you are letting in. If you don't care about people actively trying to get at others' workout programs and only trying to stop this from happening incidentally, then you have no problem.
Technically it's exactly as safe as a login/password pair, 32 chars each, i.e. very. Even brute forcing for random records is not an option. With a billion users and billion brute force attempts per second it would take well over 10^100 times the age of the universe before you found a working hash.
In practice there are other consideration, such as caching proxies, browser history and so forth. I would recommend against doing this with important data, but it's really in how you present and explain it to users.
I think this is not a bad idea as long as you don't allow those "magic tokens" to continue to work forever. You should store the tokens in a database and keep track of whether they've been used. Once a client uses the magic token to reach the system, they really should create a "normal" account with a username and password, like every other site on the internet. After that use, the token should be marked as "used" and further uses of it should be disallowed.