I am currently managing two servers that have a shared secret key.
I would like to be able to send data between the servers in a manner that even if someone is listening in the middle, the data will be only read if someone has the secret key.
My requirements are:
encryption
authentication
But also:
freshness: so that old encrypted data that has been intercepted in
the past will not be accepted if transmitted now by someone else.
I was wondering if defuse/php-encryption is applicable to this scenario given that it provides encryption and authentication.
I also took a look at libsodium but I want to stay away from PECL if possible.
Thank you.
I would suggest that you use an existing cipher suite that can "blanket secure" the entire connection between the two parties. Then, in any case, use digital certificates (they can be self-signed ...) to secure the connection. (Do not use "shared secrets," a.k.a. "passwords.")
TLS (the successor to SSL) is used by HTTPS secure web-sites. (Be sure to use the current version of this protocol!)
VPN (as "OpenVPN" or "IPSec") provides "a secure router" between two subnets. The advantage of this strategy is that the two parties don't have to do anything to obtain a secure, reliable connection: it’s just there.
SSH is also able to do "tunneling," but it's too-easy (IMHO) for data to wind up actually being passed insecurely, and it really doesn't provide identity-verification.
These cipher suites will provide you with three very important guarantees:
The data is not intelligible to any other party.
There is no "man in the middle." The parties can identify exactly with whom they are communicating.
Messages received are known to be "exactly what the sender sent."
Nothing in-secure is passing "out of band" between the two parties.
... and yet, they operate completely "in the background," just as you routinely see TLS doing when you connect to a secure web-site. "It is secure, and 'it just works.'" It is very important that your scheme be unobtrusive to authorized users.
Related
I am building a website recorder that acts like a proxy, in order to test web scrapers on an ongoing basis. It is split into three Docker containers, all on GNU/Linux: (1) a proxy, (2) an API and request queue, and (3) a simple web app.
It works fine for HTTP sites: I click a button in the web app, this makes a request to the API container, and that adds something to an internal request queue, which then requests the site via the proxy. The proxy records the site as it passes through.
However, I'd forgotten that one cannot record HTTPS site traffic, and now I've come to implement this, I've found that proxies just use the CONNECT verb, and then act as a data exchanger between the client and the target. I believe I cannot replay the same data chunks as part of the encryption uses a randomised, throwaway, symmetric key (however I have a script suitable for testing this, so I will do so just for the educational value!).
So, I was wondering if my fetching client could give up enough secrets for the proxy system to decode the byte-stream? I am using Wget to do the fetch, which I guess would be using OpenSSL. It does not need to be Wget though: if I were using a PHP script with file_get_contents with a stream context, can I ask the openssl module for the decryption keys?
(To be fair, I will probably not solve the problem in this fashion even if it is possible, I just thought it would be really interesting to learn a bit more about TLS. In practice, I will record a "null" entry against all secure websites in the proxy, and require the requesting service to notify the proxy of header/body data via an API call, so it can be later played back. They will of course have plaintext copies of these items).
Yes, I think you have a couple of options here.
HTTPS is specifically designed to thwart "Man in the Middle" attacks and eavesdroppers, which is essentially what you are trying to achieve. You can break some of its assumptions though, and defeat it.
At the start of the SSL connection, 1. the remote server presents its public key and its cert, 2. the client verifies the cert and 3. sends a session key encrypted with the server's public key. For more details, see e.g. An overview of the SSL or TLS handshake
You have two possible ways to circumvent this protection, in the scenario you describe:
1. Rewrite the TLS data, replacing the server's cert and key with your own
Since you control the communications channel, you could substitute the server's public key & cert with one that you control, at step (1). If you then ask the client to skip step (2) using the --no-check-certificate argument to wget, you can then have full access to the encrypted data.
This is how the Fiddler debugging proxy allows access to HTTPS traffic, see https://www.fiddlerbook.com/fiddler/help/httpsdecryption.asp
2. Retrieve the session key from the client application
Since the client app knows the session key, if you could extract it, you could then decrypt the stream. I think this is what you had in mind in the question.
wget itself has no options to allow logging the session key (see "HTTPS (SSL/TLS) Options"), but it does look like its TLS library, "GnuTLS" has a debugging option that will do what you want, see "Debugging and auditing" in the GnuTLS docs:
SSLKEYLOGFILE When set to a filename, GnuTLS will append to it the session keys in the NSS Key Log format. That format can be read by wireshark and will allow decryption of the session for debugging.
Try setting the SSLKEYLOGFILE environment variable to a filename, and see if wget will then log your TLS session keys to that file? You might need to recompile wget with a debug build of GnuTLS. I haven't tried this myself.
First of all, a better question would be is this possible? My gut instinct is that it isn't entirely, but there may be some clever ways. Even if they just act as a deterrent, make it slightly harder for some one to hack, or even make it easier for me to detect suspicious activity.
Basically, I'm building a web service using PHP for my C#.NET program to connect to. Among other things, one of the most important purpose the web service serves is verifying license data. The program sends the licence key entered by the user to be checked, and if it is valid the web service will return the Name of the person who purchased the licence key so that the program knows to activate itself.
I am fully aware that there is no perfect anti-piracy scheme and that is my software will be cracked if people want it bad enough. However, I do not believe that there isn't anything I can do to make it very hard for people to crack my software.
I do have an SSL certificate so the program will be communicating with the web service using HTTPS, however that's the only security I have at the moment. I have thought about
Using long and obscure names so that the functions are hard to guess
Using MD5 to disguise the functions
Adding a username and password
Checking the User-Agent
etc.
However, I have read that there are applications available to simply extract strings from programs, which would render those measures completely ineffective. Still, I don't know how technical users have to be to use those applications. Is it still worth adding some of these measures to stop casual piracy? Which measures are the better ones and what will be the most effective?
Thanks in advance
You can distribute your C# application with a certificate bundled and sign your requests with the certificate. The server can then verify if the request was signed by your application and reject any other request.
Edit: Whoops, I only now understood that you want to secure you application even when in the hands of a malicious user. This, I don't think is possible. A hacker can decompile, scan the memory, read and decode files, etc and your certificate will be available in there if you distribute it with the application. An alternative would be to distribute an external security token (hardware device or flash storage) which will need to be plugged-in to the client computer. The token holds the certificate, keys or cyphers used to sign/encrypt your requests and it therefore doesn't stay with the application.
Your server-side SSL certificate will only guarantee that the communication channel is secure and the server is not lying about his identity. It doesn't guarantee anything about the client connecting. To also be sure that the client is identified, you need to use a form of client certificate that your server recognises.
I intend to have a PHP web service accepting JSON-RPC over TLS (HTTPS). Every client will have an API key that I will use for identification purposes. Is that enough security, is there a JSON-RPC security specific standard?
That's a fine way of doing things. Here's an overview of the requirements and components play in your security scheme:
Checklist
Here's the checklist of what security is needed, and how you would address it:
A third party can't eavesdrop on your communications. HTTPS provides this.
A third party can't tamper with your communications. HTTPS provides this too.
The client can authenticate the server. HTTPS provides this (*).
The server can authenticate the client.
Client authentication
There are lots of way to authenticate the client. Here are a few exaples:
Use the API key to calculate an HMAC of the request and include the HMAC as a header in the request. (**) The most secure, but more complicated to set-up. The key advantage is that should your server be compromised, API keys won't be exposed.
Include the API key itself in the request. Easier to set-up, may be sufficient security depending on your requirements.
...
(*): So long as the client library does. HTTPS requires that you use a certificate that validates your site corresponds to the domain name. Unfortunately, many HTTPS libraries do not validate this by default.
(**): You should also use a nonce to prevent against replay attacks.
You could be signing a request using a secret salt (+hashing algo of choise, MD5 will do fine) because this way an eavesdropper cannot obtain the "API key" and forge his own requests. Use a very long salt.
The salt also acts to protect against intentional altering of a message by a successfull eavesdropper.
How can there be a man in a middle? TLS(SSL) is not much security against man in the middle attacks, unless you issue whitelisted certificates per client. For example, the server in the middle (attacker) obtains valid certificates, or the client application is not checking for various certificate validity settings (expiration dates, etc.). If not under your control, it is likely that clients of your RPC server will connect without doing any sort of security checks. This is a widespread problem. Eavesdropping usually implies access to your (or your client's) network so this could mean poisoned DNS traffic redirects to the rogue server.
Wether your or your client's network connection is secure enough to exclude the possibility of DNS poisoning, or your client is checking the certificates for validity, or you force the client to use whitelisted SSL certificates, are things only you can influence or decide upon.
You might also want to prevent replay attacks by assigning a unique number for each request (possibly overkill if these API calls are just for reading) for denying duplicate requests.
The API keys you mentioned, are generally used when browser side JavaScript clients are involved to track usage. API keys are reissued, when stolen, to identify and disable unauthorized apps (and maybe automatically make a list of the fraudulent domain names for further [lawsuit] action).
I have several independent PHP applications running on few servers. None of the servers have SSL, but I'm able to use PHP wraper for SSL. I would like to ensure all data sent between servers is safe and signed. Do I need to generate an certificate or is it enough to create public/private key everytime I send something? Is this aproach safe?
Do I need to generate an certificate or is it enough to create
public/private key everytime I send something?
Don't generate a public/private key every time. How would you be able to check who has control over the private key? The point of certificates is to be able to bind an identity to a public key: checking you trust the certificate and that you're willing to communicate with the identity it refers to is a necessary component to secure the communication.
From what I understand, the communication between the servers doesn't involve user interaction itself. If you control all the servers, you could give them certificates, either self-signed X.509 certificates (if you can install them all for all parties: only applicable for small numbers in practice) or your own CA (if you have OpenSSL, look into CA.pl, which has a man-page).
You could then sign an encrypt the content you exchange using S/MIME (there are functions available in PHP for this).
(You might also be able to achieve the same goal using PGP, using PGP keys/certificates instead.)
If both machines have mcrypt then you could probably encrypt the text you want to send over the wire in PHP at one end and decrypt it at the other, but of course the big issue you have here is going to be key distribution. You'd either have to pre-configure each machine with the correct key and hope nobody notices you're using the same key every time (which is bad), or you'll have to come up with some kind of way of distributing your key to the receiving machine when you send data without the key being snooped. (which is complicated).
You also mentioned signing, which is also a tricky issue.
Whilst it would in theory be possible to implement all this in PHP using an appropriate extension such as mcrypt, I honestly doubt it would be worth the effort of doing it right, which would be considerable, You'd also just be reinventing the wheel.
SSL implements all the stuff you need already and is the accepted industry standard, if at all possible I'd strongly recommend you install it.
In a little project of mine I use Blowfish encryption for some data transfer, using the mcrypt extension that's available on most servers:
$encrypted = mcrypt_encrypt(MCRYPT_BLOWFISH, 'here goes a key', $data, MCRYPT_MODE_ECB, null);
Decrypting goes the same way, just use mcrypt_decrypt. This is a shared key, not a public/private key system.
I'm developing a small website where I'm going to allow user to create accounts but I'm quite clueless when it comes to safety around authorizations.
I have built my project in PHP with codeigniter and found a library (Tank Auth) that could handle authorization for me. It stores password in a safe way but I'm still worried about the part when the user sends their password to my server.
One easy way to do it would be to send the password in a post-request but I would guess that it's quite easy to sniff such a password. Should I do something with the password on the client side before sending it to my server? And is there any good javascript libraries for this?
As others have said SSL is the prefered way to go.
David Wotever metioned hashing - there's a detailled discussion of the process here
An alternative approach would be to rely exclusively on external providers to handle your authentication for you - openid being the most obvious candidate.
HTH
C.
You can muck around with client-side hashing, but in general POSTing the credentials over a secure (HTTPS) connection is considered sufficient.
This still leaves the possibility of MITM attacks… But performing an MITM attack on an SSL connection isn't entirely trivial, so it's probably not an attack vector you need to be too concerned with.
You say that SSL is too expensive for you, but most hosts offer it for free. The expensive part is getting a private IP address and formal certificate.
However, you could create your own certificate which would mean that all the details are still transmitted securely, it's just your identity that can't be guaranteed. As mentioned by David Wolever, MITM attacks are much harder to do; and anyway are probably not a concern for a hobby site.
Once (if) your site evolves out of being a hobby then you can invest in an assured certificate then.
Authentication via SSL is probably the easiest and most secure way.
If you encrypt it in something like rot13 etc.. it's easily undoable.
As mentioned also, you would want to make sure that your website's security isn't relying on Javascript as that can easily be turned off.
Any other operations performed on the client side can easily be broken.