We are currently designing a smartphone application that needs an authentication protocol.
We will use HTTPS for all the messages. The idea is the following :
The client contacts the server and authenticates himself with his user/password combination.
The servers replies with a ramdom-generated token that is stored in the database.
To contact the server the client now uses his/her user/token combination.
In each message he sends, the server has a certain probability to regenerate a new token that it includes in the message it sends.
The question is : will we have security issues using this protocol ?
Note : passwords and tokens are stored hashed in the database.
The security bases on the certificate you use for encryption. In general this is enough, you may also check if it is the expected certificate. In the case that you check yourself the fingerprint of the certificate you can be sure (if you use sha1 or better) that the certificate is from you and not a successful man in the middle attack. E.g. the NSA could simple create valid certificates for your domain, but AFIK it is impossible to generate a second certficate with the same fingerprint.
By the way I hope that the passwords and tokes are also salted. That is important so it is impossible to see that two customers uses the same password and also it increases the complexity of the hash, that means that it will take much more time to crack such a password with a rainbow table.
Related
Usually when a user logs in, the user details are sent to the sever to authenticate the user. How are these credentials protected in the best way during flight?
Main Questions :
I understand the passwords are many times hashed, keeping them secure. Also TLS maintains the in-flight security, But is that the only way the transaction details are kept secure or do websites add any of their own layer of security?
In our case, we want to send a passcode to the backend, where another API will be called (that uses password grant) of a third party application. We cannot hash the password, we'll need it in the backend. Will TLS be sufficient for securing it in flight?
We were also planing to implement and secure the passcode by RSA (public key) on the client side and unlock it on the backend for use. Should we consider RSA?
I understand the passwords are many times hashed, keeping them secure. Also TLS maintains the in-flight security, But is that the only way the transaction details are kept secure or do websites add any of their own layer of security?
There are very few cases where layering more cryptography on top of TLS are beneficial. Your case doesn't seem to fit them. So TLS should be enough. TLS already provides encryption in transit. RSA would do the same. Defense in depth means layering different security mechanisms on top of each other.
You might hash the password on the client side creating an intermediate password, but considering your 2. question, this is not what you can do.
In our case, we want to send a passcode to the backend, where another API will be called (that uses password grant) of a third party application. We cannot hash the password, we'll need it in the backend. Will TLS be sufficient for securing it in flight?
Yes, but let the client (your server) validate the certificate chain and don't accept protocol downgrades.
We were also planing to implement and secure the passcode by RSA (public key) on the client side and unlock it on the backend for use. Should we consider RSA?
No, just use TLS 1.2 or higher with a valid server certificate and let the client validate the certificate chain (browser does that automatically for you).
Keep in mind that TLS needs a trust root. Most client side libraries as well as many browser use the trusted root store of the operating system. A certificate chain presented by the server should end in one certificate that is in the trusted root store.
You could use a self-signed certificate, but then the client would need to pin the public key of that self-signed certificate.
I am looking into ways of securing the channel between my client apps and the server.
I have a rich desktop client (win) and mobile client connecting to a webservice, exchanging data.
Using SSL certificates, server and clients may trust each other. On the secured connection i can exchange username and password and therefore authenticate the user.
However i have certain circumstances where a user must connect to the server via any of the two methods without his credentials but only a literal, like say, a license plate number.
I really want to make sure that in this case i ONLY allow client connects from devices i am sure i know, since there is no further checks on the authentication and a license plate number would be a pretty common literal.
How can i ensure that only "devices" which are known to my server, can interact with my server?
If you want to authenticate the device, you'll need to find a way for the device to prove what it is, without disclosing its secret.
A system similar to a number plate would be quite easy to spoof, for anyone in a position to see that number. Depending on how much control you have on this device, you might not be able to hide it, even if the connection to your server is secured with SSL/TLS.
A potential way to do this would be to use a cryptographic hardware token (or smart card). Some of these tokens can be configured to hold a certificate and private key, with the ability to use the private key without being able to export that private key. The cryptographic operations (signing and decryption) happen on the token itself.
You can use these to perform client-certificate authentication to your server. In this case, you would know that the client has that token. This could work on the condition that you know the CAs were issued its certificates only for key pairs in such tokens: there will be a cost in administering the CA to handle this.
This would at least allow you to tie the authentication to a particular token. Whether you can integrate this with your overall device depends on the kind of device you have.
Please check if TLS Pre-Shared Keys (RFC 4279) can be used for your scenario.
I am curious how to properly send username and password from a website login form to a server.
If I just send the username and password without hashing them to an https server how exposed is the password I send in a POST request to somebody sniffing the package and finding out the password? The server is https enabled.
What would be the proper methodology to do this?
If the server is HTTPS enabled then any data going over the wire will be encrypted. It would be extraordinarily difficult for a network-only attacker to sniff even a plaintext password over HTTPS without one of the parties noticing.
HTTPS uses SSL/TLS on the transport layer, which is designed to provide both encryption and authentication. The SSL/TLS protocol, as part of its handshake, negotiates a symmetric encryption key that is different for each session and is used with a strong algorithm to protect data on the wire.
To mitigate 'man-in-the-middle' attacks, the asymmetric keys used by the client and server to establish a shared encryption key are also cryptographically signed by a certificate authority, both to provide assurance of trust and to prevent modification of the certificate. As long as the certificate authority can be trusted, it is easy to check the signature and and server name on the certificate itself. All modern browsers do this automatically and throw a warning to the user if there is any problem with the certificate.
As long as you and your users are aware of the issues surrounding the proper use of SSL (e.g. keep your private key safe, and make sure your users pay attention to browser warning), it's fine to send plaintext passwords over an SSL connection.
If the demands of your application are such that you cannot do even that, you might consider X.509 authentication (which uses certificates on the client side as well as the server side) or Kerberos authentication (which sends no passwords over the wire). For a basic web application, though, both of these solutions are overkill.
I'm trying to figure out the best way to secure an API. I only allow SSL and I'm using OAuth2 for authentication, but that doesn't seem like enough.
The major concern I have is that anyone could inspect the requests being made by a legitimate client to the API and steal the OAuth client_id. At that point they would be able to construct any request they want to impersonate the legitimate client.
Is there any way to prevent this? I've seen people use a HMAC hash of the parameters using a secret key known only to the client and server but I see 2 problems with that.
It's very difficult (impossible?) to prevent a malicious user from decompiling your client and figuring out the secret key.
Some parameters seem odd to make an HMAC hash of. For example if a parameter was bytes of a file, do you include the whole thing in your HMAC hash?
You can deploy mutually-authenticated SSL between your legitimate clients and your API. Generate a self-signed SSL client certificate and store that within your client. Configure your server to require client-side authentication and only accept the certificate(s) you've deployed to your clients. If someone/something attempting to connect does not have that client certificate, it will be unable to establish an SSL session and the connection will not be made. Assuming you control the legitimate clients and the servers, you don't need a CA-issued certificate here; just use self-signed certificates since you control both the client-side and server-side certificate trust.
Now, you do call out that it's really hard to prevent someone from reverse engineering your client and recovering your credential (the private key belonging to the client certificate, in this case). And you're right. You'll normally store that key (and the certificate) in a keystore of sometype (a KeyStore if you're using Android) and that keystore will be encrypted. That encryption is based on a password, so you'll either need to (1) store that password in your client somewhere, or (2) ask the user for the password when they start your client app. What you need to do depends on your usecase. If (2) is acceptable, then you've protected your credential against reverse engineering since it will be encrypted and the password will not be stored anywhere (but the user will need to type it in everytime). If you do (1), then someone will be able to reverse engineer your client, get the password, get the keystore, decrypt the private key and certificate, and create another client that will be able to connect to the server.
There is nothing you can do to prevent this; you can make reverse engineering your code harder (by obfuscation, etc) but you cannot make it impossible. You need to determine what the risk you are trying to mitigate with these approaches is and how much work is worth doing to mitigate it.
Are you running the OAuth authentication step over SSL itself? That prevents all kinds of snooping though it does mean you'll have to be careful to keep your OAuth server's certificate up to date. (Note, the OAuth server can have a public SSL identity; it's still impossible to forge with even vaguely-reasonable amounts of effort. It's only the private key that needs to be kept secret.)
That said, you need to be more careful about what you are protecting against. Why do people have to use your client code at all? Why does it have to be “secret”? Easier to give that away and put the smarts (including verification of login identity) on your server. If someone wants to write their own client, let them. If someone wants to wave their account in public in a silly way, charge them the costs they incur from their foolishness…
I'm making a server-client to use ssl for sign up and login process.
(and this is for iphone if it matters)
I just started looking at what ssl is and how to use it, and
saw there is a certificate in the process which can be bought or self-signed.
If I use self-signed certificate in web server, web browser would alert that cert is self-signed, that I understand.
But what would happen if I use self-signed certificate in regular application with tcp(not http), specifically iphone.
I just want to make the signup/login
info(their password) to be secure,
and hoping that using self-signed
certificate would be ok for this
purpose. But I also need to make
sure this won't cause "not trusted
certificate - alert" type of
interruption when used in application
other than a web browser.
Edit
I understand that "not trusted certificate alert" is saying client shouldn't trust this server.
But in my situation, client doesn't need to authenticate with the server.
The server just needs to get client's password in a secure way.
To answer your question: You can, but you shouldn't!
First, using SSL only for authentication isn't secure at all. The authentication process probably produces some kind of session (e.g. cookie) which is then transfered without encryption. Therefore, the session can be stolen (see Session hijacking).
Second, using a self-signed certificate allows man-in-the-middle attacks. So, someone can steal the user's password and he probably won't even notice it. The user doesn't know the difference between the alert that pops up when the client receives your self-signed certificat and the pop up that shows when the attackers self-signed certificate is used.
My advice: Don't use self-signed certificates. When an attack happens it's bad for you and your customers.
When you use an SSL connection to encrypt a login dialogue with a password the server sends the client a public key (in the form of a certificate), and the client generates a one-off session key, encrypts it using the server's public key, and sends it to the server. The server can then decrypt the session key because it has the private key.
The user then encrypts his password using the session key and sends that to the server, which can decrypt it because it knows the session key.
Now, without PKI if an attacker wanted to learn your password he could spoof the server. He'd send you his public key and you'd generate a session key, etc., in the usual way and send him your password which he would be able to decrypt because you'd be using his key without knowing whether you can trust it.
PKI protects you against this kind of attack by requiring that public keys are distributed as certificates. If you trust the CA that signed the certificate you can tell that the public key really does belong to the server and that it's safe to use it to encrypt your password. If you don't use a certificate -- or if you use an untrusted certificate -- you generally have no idea who you are sending your password to.
You don't give enough information about your own particular use case to say for certain whether you can use a self-signed certificate ... For example: It may be that you have one fixed certificate that is distributed in advance by some trusted channel and that you can check that the correct certificate is being used when you begin your SSL conversation. If that's the case then your client already knows that it has the correct public key and doesn't need to be able to check a signature. In general, though, you need a proper certificate signed by a trusted CA or else you have no security.
That's the entire point of trusted signing authorities - anything signed by someone else is supposed to give a security alert. So, no, there's no useful way to override this (unless you have control over the client computers - e.g. a self-signed certificate used for company-internal sites, when you can add your own CA into the clients' list), either for web browsers or anything else.
With a self-signed certificate, how can a user know whether the certificate is yours or an attacker's? He can't.
If you completely control both ends of the process (server and client), you can of course instruct the client to always trust "certificate from Eugene with a fingerprint of A01AABB546AC", for example, but then you need to build your own certificate infrastructure (expiration/revocation).
You will add no theoretical security by using a self-signed certificate, because of the possibility of man in the middle. The counterparts (your client and your server) in this communication will have no additional information about who is talking or listening, whereas the point of this kind of encryption is to make sure that there are only two participants in the communication and that the identity of at least one of them is known.
In your case, the password will not be transferred to you securely, because you don't know if it has passed through a third party on the way. Likewise, the user won't know who he sends the password to.
In practice, a man in the middle attack will be a bit of work to set up, and maybe that obstacle is some kind of security, but contrast that to the annoyance of forcing your users to accept a security warning with unclear consequences, and indeed the risk of "false sense of security".
There are companies that offer free certificates with the lowest form of validation (they will only check that you "own" the e-mail address hostmaster#domain). That way you won't have to do with the warning, either.
Unless there is a way for you to package your certificate or its fingerprint with the app, as Piskvor said.
Moved to answer - for this type of thing you should be fine. The only thing the users won't get is a way to confirm the trust level of the cert (like you could do with a signed cert in a browser for example) but as per your comment to #Piskvor that doesn't sound like an issue: you aren't using it for that.