I was looking at this question and, to try to find the mistake, went to the PHP manual where I seen those 2 options :
CURLOPT_SSH_PRIVATE_KEYFILE The file name for your private key. If
not used, libcurl defaults to $HOME/.ssh/id_dsa if the HOME
environment variable is set, and just "id_dsa" in the current
directory if HOME is not set. If the file is password-protected, set
the password with CURLOPT_KEYPASSWD.
CURLOPT_SSLKEY The name of a file containing a private SSL key.
OP of that question uses a CURLOPT_SSH_PUBLIC_KEYFILE so I guess it should uses a CURLOPT_SSH_PRIVATE_KEYFILE instead of a CURLOPT_SSLKEY, but I don't really know the difference between those options.
So here comes my question :
What is the difference between CURLOPT_SSLKEY and
CURLOPT_SSH_PRIVATE_KEYFILE ?
Well, I found the difference between SSH and SSL in this IT Security question.
Thomas Pornin answered :
SSL and SSH both provide the cryptographic elements to build a tunnel
for confidential data transport with checked integrity. For that part,
they use similar techniques, and may suffer from the same kind of
attacks, so they should provide similar security (i.e. good security)
assuming they are both properly implemented. That both exist is a kind
of NIH syndrome: the SSH developers should have reused SSL for the
tunnel part (the SSL protocol is flexible enough to accommodate many
variations, including not using certificates).
They differ on the things which are around the tunnel. SSL
traditionally uses X.509 certificates for announcing server and client
public keys; SSH has its own format. Also, SSH comes with a set of
protocols for what goes inside the tunnel (multiplexing several
transfers, performing password-based authentication within the tunnel,
terminal management...) while there is no such thing in SSL, or, more
accurately, when such things are used in SSL they are not considered
to be part of SSL (for instance, when doing password-based HTTP
authentication in a SSL tunnel, we say that it is part of "HTTPS", but
it really works in a way similar to what happens with SSH).
Conceptually, you could take SSH and replace the tunnel part with the
one from SSL. You could also take HTTPS and replace the SSL thing with
SSH-with-data-transport and a hook to extract the server public key
from its certificate. There is no scientific impossibility and, if
done properly, security would remain the same. However, there is no
widespread set of conventions or existing tools for that.
So we do not use SSL and SSH for the same things, but that's because
of what tools historically came with the implementations of those
protocols, not due to a security related difference. And whoever
implements SSL or SSH would be well advised to look at what kind of
attacks were tried on both protocols.
I am now able to answer the question without guessing :-)
Related
I have a SSL enabled eCommerce website which uses cURL for payment processing. Everything is running well but recently I learned about "CA Public Certification Bundle for cUrl" that its a good idea to use it for cURL connections.
If this is true than can someone tell me how or how is it better/different than using the standard SSL?
Doesn't the SSL already provide some kind of certification for all connections?
Any HTTPS client connected to an HTTPS server will get its certificate (in fact, it can be a certificate chain). This server certificate must then verified by the client to authenticate the server.
This is normally done by using a number of CA certificates that are configured on the client as trust anchors (i.e. this is what you trust in advance, before encountering the server certificate). The client tries build a chain between the last element of the server chain and one of the CA certificates in its trust anchors. If there is such a valid chain the server certificate is trusted.
A "CA certificate bundle" would be a set of trust anchors. You can build your own by looking for CAs you're willing to trust, or you can use an existing bundle. Most OSes or browser come with an existing bundle. cURL in itself doesn't but it can rely on a pre-defined location (set at compile time) or it also suggests to use the Firefox bundle (via a conversion mechanism). (You can override default setting via extra options, on the command line or via the API.)
Certificate Pinning (which you also mention) has nothing to do with a CA cert bundle. In fact, it's almost the opposite. Instead of relying on 3rd party trust anchors (the certification authorities), you explicitly "pin" a set of server certificates you know as directly trusted. They're not used to verify other certificates, instead, you compare the certificate you get with the exact certificate you're expecting for that host (or at least you compare public keys). This is more like having a reference mapping from server name to certificate (or to public key) and comparing what you get from that host with the reference you have. Of course, this can only work for a reasonably small set of certificates in practice, unlike the CA (PKI) approach which is designed to let you authenticate parties you have never encountered before (via a 3rd party: the CA).
How is it better/different than using the standard SSL?
Doesn't the SSL already provide some kind of certification for all connections?
Using a CA certificate bundle isn't different than using "standard SSL", it is what's commonly used for SSL/TLS connections. You often don't see it because that CA bundle is often supplied with your client (or with the OS).
Note that strictly speaking, this is orthogonal to SSL/TLS itself, which mainly just says you should authenticate the server. Certificate verification (the PKI way, via CA certificates) is defined in a different specification, also complemented by a specification on how to verify the name in the certificate (and the HTTPS specification of course).
Found a great answer here. The comment above really helped. The exact keyword I was looking for was "Certificate Pinning".
I've been looking around for a way to check if a user has connected to my website using the right (my server's) SSL certificate in PHP. I guess my question is similar to this one,
except that I'm not implying the MITM.
I've looked around but didn't find a way to get the info from the cert used in the current connection and compare it to the servers cert. This to prevent users connecting with other certs.
How would one go about doing this?
Short Answer
You don't.
Longer Answer
This is only possible with client certificates.
Your webserver identifies you to the client, not PHP. PHP never sees this and no environment variables are sent/passed to PHP aside from HTTPS=on. You don't verify yourself to yourself as it would always evaluate true. The question you linked to already has the answer, and man in the middle doesn't mean much. You are effectively asking for a solution to any and all SSL Man in the Middle attacks with a definitive PHP script.
There is no such thing as being able to connect to your host with another SSL certificate, unless something Diginotar-esque happens to your Certificate Authority.
If you want assurance that they really meant to connect to your site, simply just check the host the client connected to. If they hit your IP, and requested a certificate from it, and then verified it with your CA, they will continue with the connection, and connect to $_SERVER["SERVER_NAME"] and $_SERVER["HTTPS"] == "on"
But, honestly, why are you worried about an incorrect SSL certificate? It will be flagged by the user's PC. I'd be more worried about session decrypting.
I have no idea what you mean by "to prevent users connecting with other certs" which sounds impossible to begin with, but:
SSL happens at a layer in the protocol stack to which PHP has no access or control.
The security of your clients' connections [in the context of running a website] is beyond your control.
Is it possible to authenticate a web browser using an ssl certificate.
Say i store a private key in my application, is there any way to read a key from a browser and try to authenticate based on that?
You can authenticate a browser/user using SSL/TLS client-certificate authentication.
The client certificate must be requested by the server, so you'd need access to the server configuration (not just installing some PHP code on a shared server). This is done at the SSL/TLS layer (in fact, the mechanism is not specific to HTTPS): the server requests the client-certificate during the SSL/TLS handshake (sometimes via a renegotiated handshake). In Apache Httpd, this is typically done via SSLVerifyClient (although you'll need to specify other options too).
The server will then verify the certificate against the CAs you've configured it with (possibly your own, and possibly independent of the CAs used for the server certificate itself). (Alternatively, you could disable certificate verification at the server level in some cases, and have the PHP application do it, but this is a bit more advanced and you'd need to know what you're doing.)
You can access the client certificate from your application and obtains its Subject DN (or alternative names), to identify the client.
It's not clear whether you're after identifying a browser or a user. In the end, everything goes through the browser anyway, but client certificates tend to be allocated to users. Users would have to install that certificate into their browser.
EDIT: For further details, it would help if you could clarify your question and what you intend to do with this.
Is it possible to authenticate a web browser using an ssl certificate.
Say i store a private key in my application, is there any way to read
a key from a browser and try to authenticate based on that?
Firstly, strictly speaking, there's no such thing as an "SSL certificate", since multiple types of certificates can be used for SSL/TLS, and some of these same certificates can also be used for other purposes than SSL/TLS. Typically, "SSL certificate" means "X.509 certificate in the context of SSL/TLS".
Therefore, authenticating a web browser using an SSL certificate implies doing it at the SSL/TLS layer. (There have been attempts to implement message-level security using X.509 certificates at the HTTP layer, but they're not widely supported by browsers.)
Secondly, the private key is held by the remote party that you authenticate. The local party that authenticates the remote party doesn't see any private key. If you (as a server) want to authenticate a web browser, it's the browser that needs to have the private key, not your (presumably PHP) application. In this context, it's not quite clear why your (PHP?) application would have/need a private key if it's the browser that you want to authenticate.
What your verifying application may need (if it's not done by the server itself) is a CA certificate to be able to verify the client certificate it is presented with (or at least some form of trust anchors with which to verify the client certificate). There's no private key required here, just public keys and certificates, unless you want your application to be a CA too.
Indeed, you could have your application be a mini CA. It could make the browser generate a key-pair and send a certificate request to the server (there are mechanisms to have a web page make the browser do all that). Then the server would generate the certificate and make the browser import it back against its private key. Subsequently, the browser could use this certificate for authentication with that server (or other servers that would recognise these certificates).
No, you cannot do that.
There is some development going on, and a few day ago W3C has made a proposal for a encryption standard.
You can however put a key in a cookie and use that to identify. This is the default PHP session id behavior.
I have written apps that run on both iPhone and Android. They make calls (HTTP POST requests) to a PHP script on my Ubuntu server that retrieves queries from MySQL server there, etc.
Basically I want to encrypt these messages going back and forth. I have the additional constraint that I am on shared hosting and so do not have root (or sudoer) access on my server.
What is the best way to implement this? I don't want something where I have to pay verisign for a cert (I know very little about security). I am thinking it will somehow involve a public/private key scheme, but I am not sure what is the best method for this.
any thoughts? thanks.
If you are on a shared hosting server, it is likely a bit of a challenge (and, depending on the provider's setup, impossible) to secure your keys from other users. Plus, reinventing the encryption wheel is generally a bad idea. So I wouldn't go that route, especially if you aren't knowledgable about security.
The easiest solution is to use SSL. If you really don't want to get a cert from Verisign (or Comodo or whomever), use your provider's default SSL cert. If they have things set up so that your SSL server will use a cert for https://www.YourHostingProvider.com/, then you should be able to make that work, perhaps with a bit of homework. (MediaTemple is set up that way, where you get their cert if you don't have your own. Not sure about other hosting providers.)
Do try to educate yourself about the elevated risks involved in doing this on the cheap. For example, depending on the setup, it's possible that anyone else on the shared hosting service could impersonate your site if they are sufficiently skilled and determined, since they may have access to the same SSL private key you're using.
If you're securing game high scores or something, that will probably be OK. If you're securing credit card numbers or people's personal health information, this is definitely not the way to go. You don't want to store that kind of information on a shared hosting service, and you definitely don't want to be so resource starved that you're reluctant to buy an SSL cert.
I have a program written in PHP, and I'd like to make sure that login pages etc. are all served over SSL. Is there any good start to finish tutorial for doing so?
Also, does this affect my code in any way, or is it just a matter of getting a SSL cert, and setting up a server correctly?
If your html code contains absolute urls ("http://my-domain.com/...") to:
stylesheets
images
javascripts
Browsers will complain "This page contains both secure and non-secure items".
Use relative urls if you can, or link to "https://my-domain.com/..." urls.
Use free certificates
You don't have to spend money to get valid SSL certificate:
Let’s Encrypt
Let’s Encrypt is a free, automated, and open Certificate Authority.
It depends on the hosting how easy this is to setup, it could be just a checkbox.
The process is well documented on https://letsencrypt.org/
StartSSL
For more traditional certificates, you can get a "StartSSL™ Free" from StartCom.
The site also contains information on installing the certificate.
Firstly a word of warning. if you are considering using SSL its because you have something to protect. Therefore take the time to understand what you are doing every step of the way. Security (not just SSL) is a minefield even for the experienced.
I don't know of any tutorials, but there are plenty of gotcha's you have to be aware of.
Rolling your own ssl cert for testing purposes is free, but you will need to install it on your server.
Most of the time your code does not need to be any different for an ssl page or non ssl as the code itself is ssl agnostic, but as Bob says you must be careful of things like images.
Also redirects can cause popups to warn the user of redirections.
To test if the code is being called from a browser using SSL check for the SSL flag $_SERVER['HTTPS'] this should be a non empty value if SSL is being used.
$ssl_is_on = $_SERVER['HTTPS'] ? true:false;
Personally I prefer to keep my SSL code in a separate folder altogether and use apache to direct all SSL connections to that folder. that way I can be confident a script that should be protected by SSL is not called from a non SSL connection.
If you are logging them in under SSL and then redirecting them to non SSL pages you may need to account for domains and cookies
for example I always use a different domain for ssl normally https;//secure.blah.com and then redirect them to the non secure domain http;//www.blah.com so your cookie domain will need to be blah.com the default is the full domain name which means cookies for secure.blah.com won't be sent to www.blah.com and therefore your users will never be logged in.
Don't use this technique if you use a shared domain name otherwise you could have a problem with cookie information being leaked.
DC
It should not affect your code. Add modrewrite rules to your Apache config. Yes, just obtain an SSL cert (you'll need to pay to have it signed by Verisign or another certificate authority).