Encrypting username and password using openssl_encrypt on client side? - php

I make API for PHP website and I need to send a login and user password in encrypted form. I chose the following method to decrypt:
$decrypted = openssl_decrypt($user_login, 'bf-ecb', $client_id);
Where $user_login is a string like a 'login:password'. The $client_id know my site and client application. Client is likely to be an application on iPhone. Are normal encryption algorithm I chose, and will not be any problems on the client side with the encoding of user name and password?

Are normal encryption algorithm I chose, and will not be any problems on the client side with the encoding of user name and password?
You will probably need to use something like WebCrypto to ensure accepted and implemented encryption algorithms are available at the client. You may need to polyfill it.
In the bigger picture, you have two problems to contend with. First is the web security model. In the web security model, interception is a valid use case. Second is a breach of server security and the password list.
Interception
The first problem is due to the W3C's philosophy, and there's nothing you can do about the broken vision. The web security model's fundamental defects became acutely clear with Public Key Pinning with Overrides. The overrides accommodate the interception, and the web folks tried hard to downplay and coverup the behavior.
Your immediate defense is to place additional security controls like you are doing. That is, use encryption so the username and plain text password is not available to the interlopers. WebCrypto should help you so you don't need to polyfill it.
There's a latent problem, though. The interceptor can allow the encrypted username and password to pass, and then capture the cookie or token when its returned to the client. So you will need to guard the cookie too.
And the username, password and cookie will need to be protected from replay attacks. You don't want an attacker to grab the encrypted username and password, and then replay it at a later time to obtain an authenticated session. So it sounds like its going to need a salt or nonce, too.
Data Breach
The second problem can be remediated by following best practices of server side storage of passwords. For that, see OWASP's Password Storage Cheat Sheet and Secure Password Storage Threat Model

Related

How to securely store multiple passwords on behalf of a user for external applications?

I'm building a web service and one of the included features involves storing passwords and credentials for users external applications.
My app is built using PHP/Laravel, the current security measures I've implemented are:
Email and password login accompanied by compulsory two-factor authentication using Google Authenticator
Once users are in they need to type in again a master password to access their database of credentials for their external applications.
CSRF Protection and SSL
The passwords are stored in a MySQL database and encrypted using Laravel's encrypt() method and only decrypted (using the decrypt() method) and given to the user if the authenticated users session ID matches the ID in the row with the password credentials.
When a user requests a password credential is it pulled from the database using AJAX, decrypted and copied to the clipboard then deleted from the client side using javascript so the password is only available for a few seconds on the client side before it's back only in the database encrypted as it was before.
Edit: The key for encryption and decryption is Laravel's app key which is a single key stored in the environment file outside of the visible server files in the public folder.
My application is B2B SaaS and is used by mid-large sized clients meaning it needs to be secure. Please point out any flaws you see in my method or any other advice you think is relevant thanks.
The best way to do this is to not do it.
Put another way: If you can get away with not storing passwords (i.e. using OAuth2 instead), don't store passwords. You don't want the extra liability.
That being said, sometimes you literally cannot avoid storing passwords (e.g. IMAP integrations). In this case, always start with a threat model before you delve too far into the weeds.
If someone hacks your database (e.g. SQL injection), what can they access?
Can they access the filesystem and read the encryption keys?
Can they rewrite ciphertexts from a targeted user's account into the field for an account they already hace access to, and thereby gain access to the plaintext without first obtaining the encryption key?
When a user requests a password credential is it pulled from the database using AJAX, decrypted and copied to the clipboard then deleted from the client side using javascript so the password is only available for a few seconds on the client side before it's back only in the database encrypted as it was before.
It sounds like you're reimplementing a password manager. You might want to shepherd your customers towards something like KeePassXC or 1Password instead.
Since this decryption doesn't include any user-provided secrets, the webserver must therefore be capable of decrypting all of your users' passwords. So if an attacker can hack the webserver, they get all of the users' passwords for free.
If you're dead set on partially reinventing password managers, you're going to want to embrace the principle of least authority and make your server unable to decrypt your users' passwords.
This means using client-side encryption, where your server is a black box that only stores ciphertext.

Encrypt a text into the database

I'm building a simple web site in which the user can upload pieces of text (notes). A note will have a flag "private" and, in case of true, I'd like to encrypt it so that not even me (who can access the database) is able to read the private note.
I know encryptions are made through a key, and the best key I can think of now for this purpose is the user password. Obviously the password is hashed into the database but I could save it during the login in $_SESSION.
Is it a good idea?
For example, in cryptobin.org the user is asked to input a password, but in my site the already signed up user inserts the password at login and I don't want to ask again something new everytime he will upload his note and, I repeat, I need all this because I want to protect his notes from me.
Probably it's not very clear to me how encryption works; in 0bin.net it's claimed that the pastes are encrypted, but no key is asked.
Can you please explain this?
Keyed encryption is based on the premise of having a secret.
plaintext + algorithm + secret → cipher text
cipher text + algorithm + secret → plaintext
You provide the algorithm, the plaintext/cipher text is the subject of interest, and the party which holds the secret has the final piece of the puzzle and thereby the ultimate power.
From this perspective the user's password is a great choice, because only the user should know it and nobody else. In practice this depends on you really not having access to this password. If you store the password server-side, then obviously you have the password and could use it to decrypt the cipher text if you so chose.
Now, what you're proposing is a temporary storage of the password in the session. That's fine, but then it becomes about risk assessment. Who could get the password from the session? Hopefully nobody except you, unless your server is compromised. That still leaves you with a temporary opportunity to decrypt the cipher text yourself if you so chose. Also, keeping the plaintext password around in any form raises the chance of it being exfiltrated to somewhere (server logs, memory dumps, etc.).
If you're being trusted with handling a secret, you need to secure everything that ever comes in contact with that secret.
It's not infeasible, but depending on how serious you are about this, how sensitive the information you're protecting is, and how many possible attack scenarios you want to prevent, this can get rather complex and goes all the way to the physical security of the servers your code is running on.
An alternative is to do all encryption client side (in native app, or Javascript in the browser), which removes a lot of responsibility from the server. It opens new problems (you now need to ensure your Javascript cannot be tampered with), but those are easier to manage.
#Thilo summaries well how 0bin works. The randomly generated secret is part of the generated URL, is not stored on the server at all, and all encryption and decryption is happening in the browser.

Secure Authentication without SSL

I thought of an authentication system without SSL that seems reasonably secure. Am I overlooking something important?
User hits the login page
Server generates a salt for transmission (t-salt) and stores it in the session
Server sends the t-salt to the user as part of the login page that loads
User types in their username and password and clicks submit
Browser MD5 encrypts their password along with the t-salt
Browser sends username and MD5 (password + t-salt) to the server
Server retrieves password from database using username (*) Note below
Server MD5 encrypts password retrieved from step 7 along with the t-salt that was stored in the session in step 2
Server compares both of the MD5s from step 6 and step 8
If they are identical, the login is successfully authenticated
The server removes the t-salt from the session (added in step 2) to prevent potential replay attacks
* Note that the password retrieved in step 7 cannot be 1-way encrypted (as is common practice) in order for step 8 to work. But 2-way encryption systems can still be used to secure passwords at the database level. (Hey, that comes with the side benefit of allowing a more user friendly password recovery process.)
Aside from my note immediately above, what are the strengths and weaknesses of this scheme?
This'd be wide-open to man-in-the-middle attacks. Nothing would stop an attacker from sniffing the link and getting the salt as it goes from server->client or the hashed password as it goes from client->server, and replaying either.
Invalidating and generating a new salt after each attempt would prevent simple replays, but then it comes down to a race condition - can the attack submit their login attempt before the user? Even then, since the attacker's sitting in the middle, they could presumably interrupt the user's link, capture the salted password, and submit it themselves and capture the session.
You send the t-salt and the hashing algorythm. It wouldn't take long to calculate the password inside the hash.
You should reconsider SSL in my opinion.
While I think that your intentions are good, the fact of the matter is that there really is no security offered at all in your approach. As others have pointed out, any reasonably competent hacker will be able to intercept data going over the wire and execute a replay attack. That is not to mention the fact that any data going over the wire will be unencrypted, which exposes your users' potentially sensitive information to anyone.
The problem with this is that you're making the assumption that SSL is purely about encryption. Take a look at SSL is not about encryption. On this basis, your scheme falls apart at step 1 because you have no assurance that when the login page is loaded it has actually come from the site you think it has and that it hasn't been tampered with.
There are many precedents of this happening, the Tunisian government harvesting usernames and passwords is a good one and you'd be wide open to this style of attack as your login page could be altered before it even hits the browser.
Then of course you have the Firesheep problem in that your auth persistence (which I assume you do via cookies), is going backwards and forwards across an unencrypted network. It doesn't matter what you encrypt inside these cookies, if someone is able to grab it and reissue a request (very easily done at a public wifi hotspot), then you've got a session hijacking problem.
Then there's also the known weaknesses in MD5 but even using a more secure hashing algorithm won't save you from the other problems described above. Spend a tiny bit of money, do some minimal configuration and make SSL part of your login process. Refer to the OWASP Top 10 on Insufficient Transport Layer Security for more info.
Finally, SSL is not intended to be a panacea; it won't protect you from key loggers, it won't protect you from having your database breached and it won't protect you from someone whacking your end users over the head with a wrench until they disclose their password. But it's not meant to do any of these things, it's simply intended to be one more layer of defence - albeit an essential one - which is part of a broader security strategy.
One thing to think about is that SSL doesn't just provide confidentiality and integrity protection to the overall data stream (via encryption) it also provides a level of validation of the identity of the server.
In your example there's no way (that I can see) for the client to validate that they are speaking to the real server before providing their password, as such a DNS spoofing attack or some other MITM attack would be effective.
Also as mentioned, it would be possible to brute-force a users password quite easily as the attacker can intercept the salt going from server-->client and then the hashed password coming back. MD5 being a fast hash algorithm it would likely be quite an effective attack against standard user passwords.
The data transmitted while authenticated won't be secure, and implementing your own schemes is usually a pretty bad idea.

How to secure the sign up process if there is no ssl

I am building a sign up page for user to sign up as a member, and am wondering how to keep the user's password secure if I have no ssl-server.
The only way I can imagine is to md5 encrypt the user's password before sending back to server for storing, and next time while in login page, the password input will be md5 with a dynamic secret seed before sending back to the server to autheticate if the user is a member.
Is it a good idea? Any good suggestion? Do I have other option?
Thanks a lot for any good idea.
The problem is that you need some kind of shared secret between client and server that a possible eavesdropper does not know to be able to encrypt it. As the eavesdropper can also listen to all traffic between client and server beforehand, you have some kind of a chicken and egg situation.
Only way out: use public/private key encryption. The client encrypts the password with the public key of the server and then sends it. The only one who might open it is the owner of the private key, presumably your server.
Have a look at http://www.jcryption.org, it might do what you want.
First, it's worth trying to protect passwords even if the assets you're protecting do not require a high security approach - since too many people use the same password for different sites - however for a secure, public facing system there is no substitute for SSL.
It is possible to do this - if you hash the submitted password with a challenge from the server. And you've already got a suitable challenge available in the form of the PHP session id (although you need to ensure that you're not susceptible to session fixation, and there are also some security constraints around allowing the session cookie to be read from Javascript).
This of course depends on having an un-hashed password on the server to create a comparison value from. And this is a definite no-no.
So....you store the password hashed with a known salt (S1) on the server. When someone wants to login you send them a session id (S2) and S1 and they send back:
md5(S2 . md5(S1 .password));
There are javascript implementations of md5.
Md5 is approaching the end of usefulness as a secure cipher - however for the puproses stated here it should be adequate.
I guess you don't really need to decrypt it, as people normally only store the password hash in the database. (unless you want to know/harvest their password).
A common way is to has the password and send only the hash.
I'll suggest you to pass "salt" from the server side to the form, and hash the password and the salt together to make it more random.
To be really secure, you'll have to implement/find a public key encryption algorithm implemented in javascript. Using any symmetric key encryption would still be vulnerable to man in the middle attack as your key has to be transferred to the client side.
The real fix for this problem is to use real SSL/HTTPS connection.
Rationale:
If the content that is available after logging in is worth protecting, the whole session must be protected, not just the user password.
If the content is not worth protecting why require logging in at all?
Note that you do not need to use paid SSL certificate to get the benefits of SSL. You may sign your own (see http://www.debian-administration.org/articles/284 for an example). However, recent versions of Firefox have made use of self signed certificates a pain in the ass unless the user is ready to install you as CA. (By some weird logic Firefox displays much less alarming dialog for adding a new CA than adding an exception for a singler server that uses self signed certificate. This is really bad because accepting a new CA accepts all certificates that will be signed by that CA in the future!)
However, if you insist on not using real SSL, you may implement encryption with JavaScript: http://www.hanewin.net/encrypt/ or http://www.jcryption.org/ - be warned though that this requires a lot of work and the end result may end up nearly as protected as SSL if implemented correctly in every little detail. The end result will never be as safe as SSL because you have to transfer the JS script to the visitor's user agent (browser) without encryption and as a result, the visitor may end up running JavaScript selected by the attacker (the attacker can execute Man-in-the-Middle attack because otherwise you don't need any protection to the user password, either).
Certificate Authorities(CAs)'s Public keys stored in web browser is the only thing that prevents SSL/TSL to be not vulnerable to man in the middle attack. So, there is no way to protection these solutions.
All of these solutions are vulnerable to man in the middle attack.
Note that Mallory (Malicious active attacker) can replace his public key in the page.
You should be using SSL(the rest is NOT that secure) to do authentication and luckily you can by using open-source OpenID just like stackoverflow.com does. You can for example read why Stackoverflow.com has switched to OpenID by reading this article(good read).
There is a very user-friendly OpenID library available from LightOpenID. I have created a little library "Openid for PHP with an user-friendly way to select an OpenID thanks openid-selector and LightOpenID" available at github. I also have put a demo on my webhosting available at http://westerveld.name/php-openid/

Sending passwords over the web

So I'm working on a mobile platform application that I'd like to have users authenticate over the web. I was wondering the best way to do security. The user is sending a password for HTTP to a php server wich authenticates against a mysql database on the same server. Obviously I don't want to send the password in plain text over the internet, but I also don't want to do 2 SHA hashes.
This is what the server looks like (in pseudocode)
$pass = $_POST['pass'];
if ((get PASSWORD where USERNAME = USERNAME) == SHA($pass)) return PASS;
This is pretty standard and I don't think there's any other way to do this. But I was wondering how I should prepare the data before sending it over the internet.
If you want security, YOU. MUST. USE. HTTPS. With a proper, non-self-signed certificate. Whatever you do, identities that are authenticated in unencrypted communication will be trivial to steal. (Never mind the password, the attacker can simply steal the session cookie that is provided with every request.)
Hashing is worthless in itself, you must salt it. (This is not really related to authentication - it is a second layer of defense for the case when someone steals your database. Which will probably happen sooner or later if you become a promising target.) Use bcrypt with long random per-user salt, sha* is insecure because it is too fast.
Use methods that are already in use by large, security-aware projects. Those methods have, to some degree, withstood the test of time. There are challange-response based methods that avoid sending the password in any form, but crypto is hard, and it is very easy to implement secure algorithms in an insecure way. Use a good security framework (e.g. PHPass), don't rely on code that is not widely in use.
You could use SSL if your client app supports it.
For regular non-critical system most websites send the password in plain text over the Internet during a http post request. The password is then server side encoded by SHA1/MD5 and checked against the value in the database.
You can also use https basic authentication, this will encode the password with a simple algorithm. But although it does not send the password in plain text, the encoding is so simple that it’s very (very!) easy to crack. But by using basic authentication, you cannot use a regular login form, you will need to do with the browsers support for basic authentication (not very user friendly!).
If you need more security most websites just install a server side SSL certificate that you buy at an ISP (for example godaddy). This will make it possible to access you’re login script over an SSL encrypted connection. This solution is considered secure (as long as the password is not easy to guess or stolen).
An other interesting, but uncommon approach, is to do the SHA1 encoding in JavaScript before doing a (Ajax) post request to the server (JS sha-1 example). In theory, this could deliver quite reasonable security…
And if this all is still not enough you could consider installing client certificates or a response-challenge system with a calculator or SMS.
As Pekka pointed out, SSL is your best option.
As an alternative, using SHA in JavaScript is pretty easy, fast, and it's already been written. Here's an example and here's a library: crypto.js

Categories