How can I secure my desktop app calling my API? - node.js

My desktop app is used by customers. A customer is a user with a License Key AND his computer's MAC address. The desktop application can only be used on ONE instance.
So when a user buys a license and registers it (meaning he downloaded, opened the desktop app, entered and submitted his license key), I will first retrieve his MAC address and then do a POST request to my API, /user with parameters in that way {license-key: "license_here", mac-address: "mac_here"} so these are saved into my database.
Now, how should I do to secure the API calls in the desktop app, once the user is registered?
Let's say a user wants to access his setting tab, should I provide {license-key: "license_here", mac-address: "mac_here"} as parameters to the GET request and check if it matches his License Key and MAC address in my database, and if it does, display all his settings retrieved from the database on the setting tab?
Or is there a more secure way to do that?
Another way I thought would be for example to hash the license key and the MAC address, concat them and use that an authentication token that I would use for each request.
I am using an API instead of saving locally because I will create a mobile app once I am done with the desktop app, and I will need to share information between both apps.
Using NodeJS with Express and MongoDB/Mongoose.

What you are doing is attempting to authenticate the computer using some data/knowledge that only it has (its MAC and licence key). This is easy to get around as an unlicensed computer can spoof the data and fool you into thinking the request is coming from an licensed computer. If you only transmit the license/MAC data then its possible for any other computer with the knowledge to also impersonate a licensed computer just by intercepting a single request - all the info required to impersonate is contained within the request.
You can't enforce uniqueness of a computer without specialised hardware. This usually takes the form of a dedicated microchip that contains a key or certificate. The data cannot be read from the chip, but the chip can be used to create a digital signature.
Without dedicated hardware the best you can do is to use a unique license key per computer and require all requests to be signed using this key. This relies on the key being private (the signature is sent with the message, not the key itself) and is no guarantee as you don't control the client computer.
Edit - How this works:
Issue a license key to each client. On your server, record each key you issue against the MAC address of the computer it is assigned to. You should probably collect the MAC address at the time of issuing the licence. Do not get clients to 'register' their license. Clients must use the key to sign each request they send and include the signature and MAC in each request. At the server you validate each incoming request by looking up the key using the MAC address and recreating the signature yourself. If the signature matches the one supplied by the client then you know its genuine. Remember - this is still not foolproof! I can buy one license from you and install it on any number of computers so long as I get them all to fake the approved MAC address. I can also give my key to my friends and have them fake the MAC address too.

Related

ASP.NET web api: detect access from new device

I have asp.net web api used by mobile app. In facebook I see notifications like "access to your account from new device". I want to implement the same. Device could be connected to different wi-fi or 3G so to use ip addrress is not good. How to define access from new device and remember it for future in "trusted devices"?
You could look at a combination of pieces of data to uniquely identify see EFF's website on browser fingerprinting.
But the common approach is to set a cookie and check if it is present in future visits.
You need a unique identifier for each device.
In case of a computer it could be a mac address, if it's a mobile device they each have a unique identifier you could send together with the request.
You would then keep a list of these IDs on the API side and every time a request comes in, just check if that ID is in the list you already have. If not then there it is .. new device.
Here is another discussion which could be relevant to your scenario : What is a good unique PC identifier?

How does X11 authorization work? (MIT Magic Cookie)

I am interested in an in-depth answer explaining how exactly X11 authorization works and especially MIT Magic Cookies.
I understand that what it actually does is to forbid access to everyone else except the user that is logged in, also there are some control mechanisms that control whether a client application can connect to an X display server or not.
I also found that there are five standard access control mechanisms and they can be categorized in three main categories:
Access based on host
Access based on cookie
Access based on user
But from this point and on I don't really understand the way these work and what ways they exactly use in order to do the authorizations.
Well, first of all there is a file ~/.Xauthority on the machine.
Notice that (usually on machine with GUI) wrong permissions of this file, can cause a login screen loop... (took me hours to understand that).
As you mentioned there are 5 mechanisms:
Host access: the server has host access list (if a network address exists in this list, the connection is permitted). the list is managed using xhost command. NOTE: this doesn't allow more than a single connection simultaneously. I don't know more about this method because I don't really used it. but you can see man Xserver GRANTING ACCESS section :)
MIT-magic-cookie-1: Generating 128bit of key ("cookie"), storing it in ~/.Xauthority (or where XAUTHORITY envvar points to). The client sends it to server plain! the server checks whether it has a copy of this "cookie" and if so, the connection is permitted. the key is generated by DMX.
XDM-authorization-1: Again, there is a key stored in ~/.Xauthority. this key consists 2 parts- 56bit DES encryption key and 64bits of random data used as the authenticator.
When you connect to the server the client generate 192bits of data: ctime combined with 48bits identifier (for tcp/ip: ip address+port, for local connections it's the PID and 32 bit unique id). the DES key is used to encrypt the data and then it is sent to server. the server validate the user by decrypting it then validating the 64bits authenticator and additional data.
sun-des-1: it uses asymmetric encryption, the server has a public key which he uses to decrypt incomming requests. it also uses the "host list". This require some additional mechanisms in the network, I don't have such network so again, I don't understand this mechanism well.
server interpreted: It can be implemented in so many ways... but in general, the client send 2 string to server. The second string is the user entry (such as username) and the first string is the entry type (such as localuser).
NOTE: the 2nd, 3rd and 4th mechanisms store the keys inside ~/.Xauthority therefore anyone who has access to this file, can connect to the server pretending to be "you".
xauth command can parse Xauthority file and extract the interesting values.
$ xauth
Using authority file /home/ME/.Xauthority
xauth> list
ME/unix:10 MIT-MAGIC-COOKIE-1 5e443c146376d0bdadfd712bfe7654be
ME/unix:0 MIT-MAGIC-COOKIE-1 c48ddba801384dce3aaaa9d442931ea12
xauth> info
Authority file: /home/ME/.Xauthority
File new: no
File locked: no
Number of entries: 2
Changes honored: yes
Changes made: no
Current input: (stdin):2
xauth>
The data is changed....

How to make sure that only the authorized user can access a feature provided by the server?

We are building an android application and one of its features is to book a cab service provider's cab (say an Uber).
We have an application specific user ID. Let us call it AUID. To book the cab, the application would Post a request to server and send AUID along with other relevant information (like lat, long etc). How do I make sure at the server end that the request is indeed coming from the correct user and it is safe to book the cab? In the current form, if a third party gets to know the AUID of another person, the third party can book a cab on behalf of that person.
One of the solutions I thought of was using asymmetric encryption. The application would hold the public key and the server would contain the private key. Instead of sending the user ID to the server, we'll instead send an encrypted key where the key would be AUID + timestamp encrypted using the public key. We'll then decrypt the message using private key at server end to obtain the AUID. If the timestamp at server does not lie within a certain interval of the timstamp sent by the client, we reject the request.
Is this a safe enough approach? Is there any other practice widely followed for such scenarios?
What you propose is sensible: encrypt the AUID on the client app and verify on the server. As comments suggest, SSL is vital.
The problem is that if how to encrypt the AUID is in your app, it can be figured out by anyone dedicated enough.
You can drastically reduce the risks of fake requests by issuing a separate encryption key for each user. This means that if someone cracks your code, they can still only spoof from one account. However, once an attacker had decompiled your app, they could theoretically start new accounts, get a valid encryption key and spoof requests.
What you need for 100% reliability is some form of authentication which is not stored in the client app - like a password or TouchID on iOS or fingerprint api on Android M. So when a user orders a cab, they need to enter some piece of information which you also encode with the AUID and check on the server. That secret information is not stored in your app, so no-one can fake requests.
Requiring a password from a user is pretty inconvenient. Fingerprint scanning is much easier and probably acceptable. You could also use a trust system - if the user has ordered cabs before and everything was OK, they can order without special authentication. Using Trust together with individual encryption keys is pretty effective because anyone trying to spoof requests would need to do a successful order before being able to spoof - which is probably too much hassle for them.

Securing a login system without passwords

I'm developing a mobile application for a company. Everyone at the company has an #company.com email address. The app itself is confidential, so it will only be installed on employees' devices. This app communicates with an external server to store and retrieve data.
Ideally what I would like to accomplish is to let people log in to the app by just providing their email address, without a password. Here is my current thinking:
A new user opens the app for the first time on a certain device and puts in their email address. The email address is sent to the server, along with a static token embedded in the application (which is the same for all instances of the application).
The server verifies the token and the fact that the email address is #company.com. It responds with a new token/key for use only with that user and device, which the client stores in plain text locally. That key is effectively the user's password. It is hashed, stored in the server database, and marked as disabled.
There are two possibilities at this point:
The server sends an email to that address confirming that they want to log in on a new device. The email contains a link which, when clicked, marks the key as enabled. There would need to be rate-limiting on new device requests so people can't get spammed if someone discovers the token embedded in the app.
An administrator specifically approves new device requests.
Every subsequent client request to the server must include the key.
Assuming all communication is over SSL, does this sound like a secure strategy? Is there a more secure or simpler approach?
Additionally, what is the best way to generate the token that will be stored client-side? Since I want users to only put in their email address the first time they use the app, I believe that this token will never change. Here is my current algorithm (PHP) loosely based on Drupal's drupal_get_token():
// Usage: get_token($email) or get_token($client_token)
function get_token($value = '') {
$salt = hash('sha256', 'Some static, predefined phrase');
$hmac = base64_encode(hash_hmac('sha256', $email, $salt, TRUE));
return $hmac;
}
As you can see it doesn't protect against parallel attacks (e.g. if someone figured out the predefined phrase and algorithm and they had access to the database, they could generate hashes and compare them against the ones stored in the database) but because the original key value is already long I don't think this would be nearly as effective as it would be against normal passwords. Additionally I am not sure of a way to create a dynamic salt that an attacker would not already have access to if they could access the database (or honestly if it would even matter at that point, since getting access to the database would expose the data we're trying to keep confidential anyway).
After some research and more thought, I believe that the answer to this question comes down to the vulnerability of the local storage. Since it's safe to assume in this case that only company employees will be using the app, there is insignificant risk of malicious code running in it even if there was a problem in the code that would make that possible. As a result the main risk is from some other app taking advantage of a security hole in the OS's local storage implementation to read the local private key off the disk. Since the existence of the app should not be known to anyone outside the company, it is very unlikely that this information would be directly targeted. So I think this is an acceptable process for this company.
In the general case though, anyone considering implementing a similar model should be aware of the risks of basically storing a password in plain text locally. (This is as opposed to storing a password in the user's head, or equally likely in plain text in a password file elsewhere on their machine; it's your call which is more secure.)

Identifying a device accessing an html page

The goal:
Limit access to authorized devices who access my HTML5(.html) webapp.
Here's the dilemma:
I have an HTML5 Offline app(.html) that will load all of its resources from a web accessible URL. I want to restrict access to specified devices.
The problem:
Identifying the device. Since .html pages cannot retrieve the mac
address of the device, and if the user could specify the mac address
it could easily be forged.
Since all of the devices will be the same(iPads). User-Agent would not allow me to uniquely identify the device and it could always be faked.
Is there anyway to identify a device by a unique value within Webkit/Safari that can not be forged easily? Mac address would be the ideal value to get, but since this is not possible I am looking for any other ideas that would help identify a device uniquely.
In a perfect world, the device would load the webapp, the webapp would make an ajax request to the CMS to validate the unique identifier of the device and return the result.
Any ideas or thoughts are appreciated. Thanks!
Your best solution here would be to deploy mutually-authenticated SSL between your client tablets and your server. You can use self-signed certificates here so you don't need to buy any from a CA. This will ensure that your server only accepts requests from tablets that have the client-side certificate (configure your server to only accept the self-signed client certificates deployed on your tablets for client authentication).
This would have to be done on the server side. The web client (browser) sends a request to the server with it's details. Now you could do it with javascipt
var browser = navigator.appName;
if (browser == "bad") window.location = "http://example.com";
but the device has to load and execute the code.
The best way would be to use PHP
$browser = $_SERVER['HTTP_USER_AGENT'];
if ($browser == "bad") header ("Location: http://example.com");
but either way you do it it is always possible to give false details since you supply the information in the request.

Resources