WebRTC over Local Network - node.js

I'm building a React website that I want to use WebRTC to basically be able to make audio/video calls to other devices, only on my local network. Because the getUserMedia requires HTTPS, I'm running into issues whereby I basically have to bypass the SSL warnings (the "visit website anyway" buttons), which I don't want to do.
I'm using my laptop to act as the connection broker/signaling server to allow the clients to connect with each other--if I downgrade the capabilities to HTTP for text chat only, this works great--but the whole purpose is to use audio/video, so I need that SSL layer.
My question is: how do I setup the SSL layer properly so that I don't have to bypass the warnings and accept a self-signed certificate?
Strictly speaking, the self-signed certificate does work and I can do this using it, but it seems self-defeating, so it's not really the way I want to go.
Again, this is only for intranet usage, so I don't know if that makes it easier or harder, but that's my constraint.
EDIT:
The server is written in NodeJS. I've found some documentation suggesting that Node can be given additional CAs (e.g. NODE_EXTRA_CA_CERTS). Is this something that I can leverage? Would a client html page utilize this in any meaningful way?
This link seems promising: https://engineering.circle.com/https-authorized-certs-with-node-js-315e548354a2. The main thing I'm not understanding is how I would utilize that ca: fs.readFileSync('ca-crt.pem') line for a given request, as it seems like the code there is actually making the request (but one would have already been made to the server in my case, no?). https://nodejs.org/api/https.html#https_https_request_options_callback seems to indicate something similar, as well.

It is totally possible to register a domain name, and then point it at something in the Private Address Range. I do this for local development sometimes. I registered pion.io and got a wildcard cert via LetsEncrypt.
You could also use mkcert. Then either in /etc/hosts or in your router itself you can give a FQDN to your signaling/web server.
There is also the --unsafely-treat-insecure-origin-as-secure argument for Chromium, I haven't used it lately though not sure if it still works.

Related

SSL/TSL for React Frontend and Express Backend?

I have been learning more about web development so this is likely a dumb question or I do not have the knowledge to search for the answer properly.
I am revamping my current personal website (hosted on Github pages). I am making a React frontend which will be served via Github pages and with an Express backend (likely through cyclic). I want to add SSL/TSL Encryption for encrypted communication between the frontend and backend.
To my knowledge, SSL works via the server sending it's certificate to the client. It also will send it's public key so that the client can use the key to encrypt the message, send it to the server which uses the private key to decrypt said message. To me this means that I definitely would need to get a certificate for my backend.
However, I have some knowledge into how RSA encryption works (I know this is not the same) but it seems like this means that messages from the server to the client would not be secure. Would this mean that if I needed messages to be encrypted going that way that I would need to add a certificate. I personally cannot think of an example but I am sure there might be one.
First, is my assumption correct? If this is the case, how would I do so in both the general sense and with the services I am using?
Thank you for any help and I apologize for any mistakes I made, I figured to put out my thought process.
GitHub pages will do the SSL/HTTPS for you but you as part of configuring your custom domain. See Securing your GitHub Pages site with HTTPS.
In the "Code and automation" section of the sidebar, click Pages.
Under "GitHub Pages," select Enforce HTTPS.
If you were using your own servers, most people use Nginx to terminate SSL. Node.js can do it but most often Nginx is used as a reverse-proxy and SSL termination point.

How do I confirm Man in the Middle attack with these hints?

1I have an app installed on my android device that shows me if the SHA256 fingerprint has been changed. It often shows that it has been altered when I run it for YouTube.com and it once showed for Instagram.com. I tried using a VPN and it didn't show afterwards.
The app basically says that it detects the SSL interception of web traffic which will decrypt an encrypted session. The test is accomplished by comparing the HTTPS certificate fingerprint of the website on your device vs the fingerprint shown on an external server.
I'm curious if it is really a concern as I do a lot of private video calls on Instagram. Are those getting recorded or anything without my knowledge?
PS: I do not have any shady app on my device.
Check the actual certificate the sites return. Certificates will expire after a while, meaning they get replaced with new versions.
Besides that, bigger sites with multiple datacenters, such as YouTube (Google) and Instagram (Facebook), might even use different certificates for different regions. This would explain why it doesn't show up while using a VPN. Also because of IP routing, special server configurations, ... you might end up connecting to different servers/regions (with different certificates) from day to day or so.
Assuming that the certificate is properly signed, valid and not revoked, you should be fine, even if the fingerprint changes. For malicious people to perform a man-in-the-middle attack with a valid SSL, they'd either need to have a valid certificate themselves (which would get revoked), access to the site's servers (which is a lost cause) or add a malicious root certificate to your device (which is a whole other problem).
The test is accomplished by comparing the HTTPS certificate
fingerprint of the website on your device vs the fingerprint shown on
an external server.
Mind that that external server might also have a different/outdated fingerprint compared to you, for any of the reasons above or others.

Encrypting Amazon S3 URL over the network to secure data access

I want to host copyrighted data on a Amazon S3 bucket (to have a larger bandwidth available than what my servers can handle) and provide access to these copyrighted data for a large numbers of authorized clients.
My problem is:
i create signed expiring HTTPS URL for these resources on the server side
these URL are sent to clients via a HTTPS connection
when the client uses these URL to download the contents, the URL can be seen in clear for any man-in-the-middle
In details, the URL are created via a Ruby On Rails server using the fog gem.
The mobile clients I'm talking about are iOS devices.
The proxy I've used for my test is mitmproxy.
The URL I generated looked like this:
https://mybucket.s3.amazonaws.com/myFileKey?AWSAccessKeyId=AAA&Signature=BBB&Expires=CCC
I'm not a network or security expert but I had found resources stating nothing was going clear over HTTPS connections (for instance, cf. Are HTTPS headers encrypted?). Is it a misconfiguration of my test that led to this clear URL? Any tip on what could have gone wrong here? Is there a real chance I can prevent S3 URL to go clear over the network?
So firstly, when sending a request over SSL all parameters are encrypted. If you were to look at the traffic going through a normal proxy you wouldn't be able to read them.
However, many proxies allow interception of SSL data by creating dummy certificates. This is exactly what mitmproxy does. You may well have enabled this and not realised it (although you would have had to install a client-side certificate to do this).
The bottom line is that your AWS URLs could be easily intercepted by somebody looking to reverse engineer your app, either through a proxy or by tapping into the binary itself. However, this isn't a 'bad thing' per se: Amazon themselves know this happens, and that's why they're not sending the secret key directly in the URL itself, but using a signature.
I don't think this is a huge problem for you: after all, you're creating URLs that expire, so even if someone can get hold of them through a proxy they'll only be able to access the URL for as long as it is valid. To access your resources post-expiry would require direct access to your secret key. Now, it actually turns out this isn't impossible (since you've probably hard-coded it into your binary), but it's difficult enough that most users won't be bothering with it.
I'd encourage you to be realistic with your security and copyright prevention: when you've got client-side native code it's not a matter of if it gets broken but when.

Can I make my own secure HTTP connection to a specific server

I am thinking about writing a secure connection between a specific client and a specific server over HTTP. Of course SSL is the best and most obvious choice. But I keep thinking I could do the do the cryptography myself.
Note that this isn't about connecting any client to a specific server, but a specific client (e.g. a Java client app on my PC) to a specific server (my website hosted somewhere else). SO third-party certification doesnt seem necessary, since the server knows exactly which client to look out for and the cleint knows exactly which server to find.
If I want to upload a file from client to server. I could encrypt it manually (AES or other) and have the key hardcoded into the client app and also put in a file on the server, out of public view.
Please tell me if I'm crazy, stupid or pushing at windmills. Is my idea possible?
The short answer is, "No you can't." You can write some code that you think implements a secure connection, but actually it will be insecure. Designing and implementing a secure connection is a very skilled job; just see what a security consultant would charge you for doing that.
Since you are asking the question here, it is reasonable to assume that you are not such a person. Since you do not have the required skills and experience, anything you produce would be insecure.
Use existing standards where all the obvious errors, and a lot of the not so obvious ones, have been avoided for you.
Your idea possible, and really, if you just need to send file to specific URL, it would be easier to make a POST request with encrypted data (if URL/headers don't need to be secure for you).
Trying to roll your own replacement for SSL is a bad idea. Don't roll your own crypto. Instead, you should use SSL. It does what you need.
Given that you need to authenticate both the client and the server, you should use SSL with client certificates (as well as server certificates, which are standard).

Security advice: SSL and API access

My API (a desktop application) communicates with my web app using basic HTTP authentication over SSL (Basically I'm just using https instead of http in the requests). My API has implemented logic that makes sure that users don't send incorrect information, but the problem I have is that someone could bypass the API and use curl to potentially post incorrect data (obtaining credentials is trivial since signing up on my web app is free).
I have thought about the following options:
Duplicate the API's logic in the web app so that even if users try to cheat the system using curl or some other tool they are presented with the same conditions.
Implement a further authentication check to make sure only my API can communicate with my web app. (Perhaps SSL client certificates?).
Encrypt the data (Base 64?)
I know I'm being a little paranoid about users spoofing my web app with curl-like tools but I'd rather be safe than sorry. Duplicating the logic is really painful and I would rather not do that. I don't know much about SSL client certificates, can I use them in conjunction with basic HTTP authentication? Will they make my requests take longer to process? What other options do I have?
Thanks in advance.
SSL protects you from the man-in-the-middle attacks, but not from attacks originated on the client side of the SSL. A client certificate built into your client API would allow you to identify that data was crafted by the client side API, but will not help you figuring out if client side manually modified the data just before it got encrypted. Technically ssavy user on the client end can always find a way to modify data by debugging through your client side API. The best you can do is to put roadblocks to your client side API, to make it harder to decipher it. Validation on the server side is indeed the way to go.
Consider refactoring your validation code so that it can be used on both sides.
You must validate the data on the server side. You can throw nasty errors back across the connection if the server-side validation fails — that's OK, they're not supposed to be tripped — but if you don't, you are totally vulnerable. (Think about it this way: it's the server's logic that you totally control, therefore it is the server's logic that has to make the definitive decisions about the validity of communications.)
Using client certificates won't really protect you much additionally from users who have permission to use the API in the first place; if nothing else, they can take apart the code to extract the client certificate (and it has to be readable to your client code to be usable at all). Nor will adding extra encryption; it makes things much more difficult for you (more things to go wrong) without adding much safety over that already provided by that SSL connection. (The scenario where adding encryption helps is when the messages sent over HTTPS have to go via untrusted proxies.)
Base-64 is not encryption. It's just a way of encoding bytes as easier-to-handle characters.
I would agree in general with sinelaw's comment that such validations are usually better on the server side to avoid exactly the kind of issue you're running into (supporting multiple client types). That said, you may just not be in a position to move the logic, in which case you need to do something.
To me, your options are:
Client-side certificates, as you suggest -- you're basically authenticating that the client is who (or what, in your case) you expect it to be. I have worked with these before and mutual authentication configuration can be confusing. I would not worry about the performance, as I think the first step is getting the behavior your want (correctness first). Anyway, in general, while this option is feasible, it can be exasperating to set up, depending on your web container.
Custom HTTP header in your desktop app, checking for its existence/value on the server side, or just leveraging of the existing User-Agent header. Since you're encrypting the traffic, one should not be able to easily see the HTTP header you're sending, so you can set its name and value to whatever you want. Checking for that on the server side is akin to assuring you that the client sending the request is almost certainly using your desktop app.
I would personally go the custom header route. It may not be 100% perfect, but if you're interested in doing the simplest possible thing to mitigate the most risk, it strikes me as the best route. It's not a great option if you don't use HTTPS (because then anyone can see the header if they flip on a sniffer), but given that you do use HTTPS, it should work fine.
BTW, I think you may be confusing a few things -- HTTPS is going to give you encryption, but it doesn't necessarily involve (client) authentication. Those are two different things, although they are often bundled together. I'm assuming you're using HTTPS with authentication of the actual user (basic auth or whatever).

Resources