Protecting mobile app from man-in-the-middle attack - security

We are working on a mobile app that communicates with the backend through REST API over SSL. Mobile device executes cert validation on the API call (using standard libraries in mobile frameworks).
If we try to connect the mobile device through proxy (such as Charles), we see all the traffic, but it is encrypted - as expected.
However, if I enable SSL proxy, generate root certificate and install that cert on my device, I will see all the data in clear text through Charles - again, as expected.
The question is, how to prevent this?
The main target, of course, is to expose data ONLY if device calls allowed server with a valid certificate for that server.

Off hand the only way to prevent such a thing if the attacker has that level of access to the device would be to use SSL thumb printing. You would initiate a connection to the server. Retrieve the SSL certificate and compare this to a hard coded value within the app code. If this does not match abort the connection and don't send the data.
The issue with this however is the overhead if the SSL updates. You would need to release an update to the app with a fresh thumbprint value. This would also stop people using the app until they updated to the latest version.

The only way to prevent this is through certificate pinning, but if the attacker is able to install a root certificate before you connect for the first time to your API, you can still be MiM'ed.

Related

HTTPS React app inside intranet still shows as untrusted

We have a Node.js application with React frontend for warehouse management. One of the features of the app is a real-time QR code reader (Which requires webcam access that is only available if the website is running under a secured connection).
This application is accessible only inside the intranet network (eg.: 192.168.157.12:80) and has no domain. I know after some research that the way is to obtain a self-signed certificate and I already did that successfully.
The problem is that it shows on the client-side as an "untrusted" certificate and require the user to confirm/bypass a bunch of warning to access the app - this is a no-go for us because a lot of the users are not tech-savvy and it presents a significant issue.
Is there any way to show the self-signed certificate as fully valid inside the local network on Windows PC and Android tablet with chrome browser and not bother the user with any warnings and alerts?
If not, can you please suggest any other method how to handle this?
Thank You.

Secure HTTPS connection to Node.js server from client

I am developing a backend for a mobile application using Node.js to handle HTTPS requests. I have set up an SSL to connect from the client to the server and was wondering if this was secure enough.
I don't have experience with intercepting endpoints from the mobile devices, but I have seen that it is possible for people to monitor internet traffic out of their cellphones and pick up endpoints to server requests. I have seen hacks on tinder where people can see response JSON and even automate swipes by sending http requests to tinder's endpoints.
My real concern is that people will be able to update/read/modify data on my backend. I can implement OAuth2 into my schema as well but I still see cases in which people could abuse the system.
My main question is whether or not using HTTPS is secure enough to protect my data, or if a session authentication system is needed like OAuth2.
Thanks.
HTTPS, providing it is properly configured, will ensure the message was not read or changed en route and that the client can know the server it is talking to is not a fake.
It will secure the transport. It will not secure the application.
For example supposing you have an app that allows you to send a message saying https://www.example.com/transfermoney?from=Kyle&to=BazzaDP&amount=9999.99 and the server does just that based on those parameters. Then I could send that message myself - I've no need to intercept any app messages.
Normally the server needs authentication as well as HTTPS to, for example, verify only Kyle user can send above message and not anyone else. HTTPS normally only gives server authentication not client authentication (unless using two way certificate HTTPS).
So the question is, even if an attacker cannot read or alter any messages between app and server can they still cause harm? That is the measure of whether it is secure enough.
A SSL connection is only secure with the content you are sending.
SSL encrypts and ensures the authenticity of the whole connection, including the requested method and URL
So i would say just using the SSL encryption is save to transfer data between - i might consider OAuth2 for password etc.
But i would recommend to use GET for retrieval data and post for authorized data
You're building an armored tunnel between two open fields.
Assuming that you use current SSL protocols and settings, and valid certificates from trusted issuers, you can pretty much assume the network is OK.
However it's still entirely possible to compromise any or all of your transaction from the client. Security really depends on the device and how well it's configured and patched.

Is it secure to check a self-signed certificate based on it's fingerprint?

I currently develop a small system consisting of an embedded server (including a small display) and some mobile devices (at the moment just Android phones).
These mobile devices should be able to talk to the embedded server over a secure channel. For this purpose, the server generates a self-signed SSL certificate during the very first boot process.
If a new mobile device should be connected to the server, the server displays a QR code consisting of:
Server IP
SSL certificate fingerprint
Random device ID
The user scans this QR code using his mobile device. The mobile device connects to the server and checks whether the SSL certificate fingerprint matches the one scanned before.
Is this considered secure? If not, how would you solve this problem?
An alternative approach:
On the very-first boot, the server generates a certificate request and sends it to a central CA server which signs the certificate. The client devices has installed the CA certficate and verifies the server certificate against it.
However, everyone could send a certificate request to the CA server and would get a signed certificate. (One could propably implement some authentication for the CA server using a "master key" but once that is extracted from a system image, the whole authentication becomes useless). In addition this setup requires a central server which I like to avoid since the product may be used in a "offline" environment.
Yes, this is considered secure because the fingerprint of the server's certificate is transferred to the client via a trusted mechanism (being physically next to the server to receive the fingerprint via a difficult to tamper with transport mechanism). If a MITM attack were to be attempted after the initial setup, even though server name would be the same, different keys would have been generated so the fingerprint would be different and the client would detect this and can appropriately reject the communication.
It could also be argued that this method is more secure because the client does not need to trust a 3rd party to verify the authenticity of the certificate. CAs do occasionally issue fraudulent certificates.

app authentication [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
securing connection to php server
I'm writing an mobile application to access an online database (I'm more interested in the high-level algorithm/protocol than the platform-specific implementation).
Since keeping the DB updated require a lot of work I want to restrict the access to my sponsored application only (I don't want other apps to take advantage of my DB for free). To do this I need to authenticate the application itself, but how can I do it?
If I store some sort of credentials within the app somebody could try to disassemble the program, retrieve the data and write his own application bypassing mine (even if I encrypt the credentials I still need to store somewhere the decryption key...)
What you want to do is employ mutually-authenticated SSL, so that your server will only accept incoming connections from your app and your app will only communicate with your server.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. You can use the keytool included with the Android SDK (if you're using Android; there are similar tools out there for other platforms) for this purpose. Then create a self-signed client and deploy that within your application in a custom keystore included in your application as a resource (keytool will generate this as well). Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
If someone/something other than your app attempts to connect to your server, the SSL connection will not be created, as the server will reject incoming SSL connections that do not present the client certificate that you have included in your app.
A step-by-step for this is a much longer answer than is warranted here. I would suggest doing this in stages as there are resources on the web about how to deal with self-signed SSL certificate in Android, both server and client side. There is also a complete walk-through for Android applications in my book, Application Security for the Android Platform, published by O'Reilly.
Now...you are right in that someone with access to the mobile app could recover the private key associated with the client-side certificate. It would be in a BKS keystore that would be encrypted but your app would need to supply a password to open that keystore. So, someone could reverse engineer your app (fairly easy on the Android platform), grab the password, grab the keystore, and decrypt it to recover the client-side private key. You can mitigate this someway by obfuscating the app to make reversing the keystore password more difficult, or asking the user to log in to the app and using that password to derive the password the the keystore, etc...it really depends on the level of risk you're willing to take on for your application.

How would I protect a private API

I am working on a REST API to be used by a mobile application I am writing, mostly for the purpose of communicating with a database.
The mobile application makes calls to URLs like this:
example.com/mobileapi/getinfo
And carries certain POST payload along with each call.
I'm not worried about user authentication etc.
However, what I am worried about is, if someone were to use the mobile application along with a network monitoring tool like Fiddler or Wireshark, they could document all the URLs being called, along with all the POST parameters. That would be enough information to create their own app that uses my API.
How can I prevent this? I considered hardcoding a Key into my application and have that included as a POST parameter with each request, but that would be visible as well.
What you want to do is employ mutually-authenticated SSL, so that your server will only accept incoming connections from your app and your app will only communicate with your server.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. If you're using Android, you can use the keytool included with the Android SDK for this purpose; if you're using another app platform, similar tools exist for them as well. Then create a self-signed client and deploy that within your application in a custom keystore included in your application as a resource (keytool will generate this as well). Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
If someone/something other than your app attempts to connect to your server, the SSL connection will not be created, as the server will reject incoming SSL connections that do not present the client certificate that you have included in your app.
A step-by-step for this is a much longer answer than is warranted here. I would suggest doing this in stages as there are resources on the web about how to deal with self-signed SSL certificate in Android (I'm not as familiar with how to do this on other mobile platforms), both server and client side. There is also a complete walk-through in my book, Application Security for the Android Platform, published by O'Reilly.

Resources