How do I support SSL Client Certificate authentication? - ruby-on-rails

I want to do what myopenid does -- once you've logged, you can click a button that generates you an SSL certificate; the browser then downloads this certificate and stores it. When you later go back to yourid.myopenid.com, your browser can use its stored certificate for authentication so you don't ever need a password.
So my questions is what is required to get this working? How do I generate certificates? How do I validate them once they're presented back to me?
My stack is Rails on Apache using Passenger, but I'm not too particular.

These are usually referred to as client side certificates.
I've not actually used it but a modified version of restful-authentication can be found here here that looks like what your after.
I found this via Dr. Nic's post

Depends on the server, but the simplest solution I know of, using Apache:
FakeBasicAuth
"When this option is enabled, the Subject Distinguished Name (DN) of the Client X509 Certificate is translated into a HTTP Basic Authorization username. This means that the standard Apache authentication methods can be used for access control. The user name is just the Subject of the Client's X509 Certificate (can be determined by running OpenSSL's openssl x509 command: openssl x509 -noout -subject -in certificate.crt). Note that no password is obtained from the user... "
Not sure about rails, but the usual REMOTE_USER environment variable should be accessible in some way.

If you want to generate certificates, you need to cause the client to generate a key pair, and send you at least the public key. You can do this in Firefox via a Javascript call, it's crypto.generateCRMFRequest. I'm guessing there are browser-specific methods available in other browsers too. But first, you need to figure out how to issue a certificate once you get a public key.
You could script something on the server with OpenSSL, but it has built-in support for CSRs, not the CRMF format Firefox will send you. So you'd need to write some code to convert the CRMF to a CSR, which will require some sort of DER processing capability… I'm just scratching the surface here—operating a CA, even for a toy application, is not trivial.
SSO solutions like OpenId and PKI solutions do overlap, and there is an elegance in PKI. But the devil is in the details, and there are good reasons why this approach has been around a long time but has only taken off in government and military applications.
If you are interested in pursuing this, follow up with some questions specific to the platform you would want to develop your CA service on.

You can generate a certificate in the client's browser using browser-specific code. See this question
You could also generate SSL client certs server-side using OpenSSL in Ruby (see this q). (This will work in any browser without browser-specific code, but your server will have generated the client's private key, which is not ideal for crypto purists.)
Whichever method you use to generate them, you will then need to configure your webserver to require the client certificates. See the Apache docs for an example.

I've been working on a solution to this problem. I wanted to do the same thing and I know lots of other website owners want this feature, with or without a third party provider.
I created the necessary server setup and a firefox plugin to handle the certificate-based authentication. Go to mypassfree.com to grab the free firefox plugin. Email me (link on that page) for the server setup as I haven't packaged it yet with a nice installer.
Server setup is Apache2 + OpenSSL + Perl (but you could rewrite the perl scripts in any language)
Jonathan

Related

Is it possible to create the self-signed ssl certificate which will avoid the "challenge" in the application code?

Background
I have a third-party framework that does some network requests to the URL which I provide to it.
The format of requests is:
https://10.0.2.2:8000/api/....
Since the schema is https I constantly receive the error message from the third party lib:
The certificate for this server is invalid. You might be connecting to a server that is pretending to be “10.0.2.2” which could put your confidential information at risk.
The server is a Django application started with
python3 manage.py runserver_plus 10.0.2.2:8000 --cert-file _my_cert.crt
I've tried a lot of ways to generate and install the self-signed certificate to the simulator and run the server, however, none of them have helped to avoid the error in the third party lib.
The Question
So I'm wondering if this makes sense at all.
Is it possible to generate and install self-signed certificate into iOS simulator which will avoid solving the challenging as is described here:
https://developer.apple.com/documentation/foundation/url_loading_system/handling_an_authentication_challenge/performing_manual_server_trust_authentication?language=objc
Please, provide proofs for any kind of answer whether yes or no.
You can get free SSL Certificate from https://letsencrypt.org
Just try it once.
For developing/testing purposes, I think the easiest way to go is to use a tunneling service like serveo. Execute the next command on the application server and this will keep the connection open:
ssh -o ServerAliveInterval=60 -R 80:localhost:8000 serveo.net
You can check for more config options on serveo. For example, you could set up a custom domain name like custom_domain.serveo.net.
You also have alternatives like ngrok.

Is there any way to learn more about SSL/TLS for iOS/MacOS development?

I am currently trying to make my own game app to have a secure transmission to my server. Specifically, I am trying to build a SSL/TLS layer over CF connections. There seems a decent support of this in iOS/MacOS (https://developer.apple.com/documentation/security/secure_transport/using_the_secure_socket_layer_for_network_communication). However, the resource of learning this library is pretty scarce.
By referencing some other posts online and guessing the usage of this secure API, I have built a simple program to (1) create a CFStream to my server and read/write it (2) add SSL Context/IO to this stream and (3) successfully(!?) SSLHandsake.
My server now is just a dummy one created by OpenSSL (like: openssl s_server -key key.pem -cert cert.pem -CAfile CA.pem -accept 44330 -www).
It takes me lots of effort to achieve this step and I am actually stuck to continue the development.
The main problem of mine is the API docuemnt is not helpful. For example, I expect calling the "SSLCopyDistinguishedNames(ctx, names)" on my client will get the list of CA authorized by my server but it turns out returning nothing (e.g., size of names is 0).
Is there any good tutorial or Apple support to know API like this? or any working example? Is there any way I can dump the information on these "SecXXXRef" class, like SecTrustRef?

Login to Django web service using a secure connection

I have wrote a simple Django web service that provides an iOS app with JSON information containing download links.
I don't mind the JSON information to be clear text, but when the user logs in, I would like him to login with his username and password, then he would probably get some kind of key for future requests which I understand that can be sniffed out. For that first interaction, how could I protect the password and username from being clear text and sniffed?
I have decided I wanted to use a symmetric encryption to encrypt my password and have that key both on client and on server. (yes, I am aware that if someone goes to the trouble of binary hacking my app and sniffing packets from a customer he would be able to get the password in clear text, it's just not a likely concern).
I would like to use some kind of encryption that I can easily do in iOS and than decrypt in my django server. anyone has a suggestion on how to do that?
If you want to encrypt the communication between your django server and the client then you can use secure HTTP rather than plain old HTTP. This is done outside django, and is configured at the web server level. For example, if your django app is ran by a WSGI server like gunicorn or uWSGI which in return is handled by nginx (this is a common setup) then you would configure your nginx server to accept only secure HTTP requests and forward any standard http request to https. This way you can ensure that everything the client sends to the server is encrypted on the browser prior to sending. Similar setup is done with Apache, though I personally have never used Apache with django.
Since the OP feels that HTTPS is not a viable option a modification of CHAP Challenge-Handshake Authentication Protocol for the initial key creation might be an option.

How to extract the whole certificate chain using openssl

I am trying to extract a web site SSL certificate chain. I used Openssl as the following:
openssl s_client -connect hostname:443 -showcerts
But this gives me the first cetificate only. while I need the whole chain certificate. How can I achieve this please ?
That generally means that the server is not sending the whole chain. So openssl cannot give it to you.
The best solution usually is to get what you can from that output - and then search for the Serial, DN and similar through google or through the CA's website and fetch it from there. And with that build your own, client side, chain.
Unfortunately it is very common for websites to be mis-configured.
Sorry :)
Dw.

Firefox add-on client-server security

I'm working on a Firefox add-on. At one point in the add-on, it needs to contact my server, give it a URL, then the server will process the URL (it's not a quick or easy process) and send back a link to the resulting file (on Amazon S3). However, since Firefox add-ons are mostly open-source by nature, how can I protect that one call to the server from being discovered by malicious people and then abused? (I only want users of my add-on to be able to make that call to the server...)
I was thinking about using some sort of key or something, but since Firefox add-ons are all open-source that wouldn't really work. I also thought about writing a binary component, but I have almost no experience in C++ (but maybe for something simple like this I could learn) - but then how could I protect calls to the binary component? Also, how could I protect from network sniffers and such? Would it be possible to somehow include encryption of some sort in that binary component so network sniffers cannot detect what is being sent to the server? (I found this question: Client-Server security and authentication but it was a bit over my head.)
When you distribute an extension you are basically giving people the car keys, so it's hard to stop them from taking the car for a joyride. The most secure solution is the one you suggested: use a binary component and authenticate the connection with username/password or PKI certificates. If you use HTTPS then the connection will be encrypted. This isn't totally secure (the binary component could be reverse-engineered by a determined hacker) but it will certain deter casual attacks. Note, however, that implementing, building and maintaining a binary component is significantly harder than the JavaScript equivalent.
An alternative would be to put the user through a one-time registration process when they install the extension. This could even happen in the background, and the user would get some credentials (e.g. a PKI key pair) at the end that they would use for subsequent communication with the server. If you're worried about people overusing the server, then presumably doing so via the extension wouldn't be great either. This way you can track the usage of each user (via the extension or not) and limit it as necessary.
In the end I don't think that there is much you can do. You could have a binary library in your add-on and call it via js-ctypes (it is easier to implement and maintain than a binary XPCOM component). But nothing will stop people from taking your extension and changing its JavaScript logic in any way that they like. You can make it harder by using some logic like this:
Client to server: "Extension version 1.2.3 wants to make a request."
Server to client: "Take your chrome://... file, bytes M to N, what SHA1 checksum do you get for them?"
Client to server: "SHA1 checksum is ..., please process URL ... now."
But this is also everything but fail-proof, it merely makes abusing your service somewhat harder. Same goes for automatic registration - if your extension can register then an attacker can create an account as well.

Resources