We've been developing a web application (PHP, using the Yii PHP framework) that is going to be used for data entry. The clients will be users from both the LAN and WAN (many of the remote clients will be behind a proxy, reaching our network using one IP address with NAT). What we basically want is to guarantee the validity of data in the way that no malicious user alters it.
Is there a way to programmatically identify each client in a unique way, so that I can guarantee (at least at some good percent) that no malicious remote user will connect? We were thinking of gathering the MAC addresses of all remote users and using a (non-web) client that generates a hash string that the user will input in the web application and then proceed if this authentication scheme passes. As I said, using other non-web applications for the remote client is an option.
Is such a solution as the one I describe above viable? Should we see other solutions, like maybe a VPN?
A VPN is a typical solution to the problem of locking out everyone except those you've explicitly given access --- basically you're rejecting all connections to the site that aren't authenticated in your local network or vpn. That way you dont have to write any funky logic for your actual web application.
I think this is an ideal solution because it allows the application to be maintainable in the future when other developers step in... furthermore it will require less of your developers and will ultimately keep costs down.
Normal user authentication is generally OK, but if you have higher security needs you can provide clients X.509 certificates to install in their browser. VPN is of course an option but you just move authentication problem from website to network vpn.
What you are looking for are the SSH-Key pairs:
https://help.ubuntu.com/community/SSH/OpenSSH/Keys
There are much more ressources on this, the theory in brief:
Each client creates a pair of unique keys, a private and public one. The public goes onto your server, the private stays with him. Then the client uses the key to authenticate. The server calculates a valid public key from it and checks if you have such a key in your system. If a pair is found - authentication was successful. (I never used this so far for Web authentification)
Additionally you could use OTP (One Time Password) technology. Since it is normally bound on per-account basis it will be very secure:
https://github.com/lelag/otphp
Related
I want to have some user-facing server, say server A. For certain tasks server A should submit a job request on server B. When server B is done, it should write the results to the database or maybe make a call on server A and let server A handle the result (not quite sure about this part right now).
The question is:
how to securely connect server A and server B?
On the endpoints on server B I only want to allow calls from server A.
On server A I want certain end-points to only be available for server B (and maybe at some point some other worker machine server C, D.. etc).
I just don't find the right words to google for this. I suppose there are some really obvious buzzwords for this, but googling "Secure connection between 2 servers" does not yield what I am looking for.
I'm interested in the general name of this, but for the sake of completeness:
The user-facing server will be using php
The job-machines will be some node-apps
My own idea (but I don't know how to exactly implement it), would be something similar to when I connect via ssh to some server, where I just add my pub-key to the server. So it should be something along the lines: have a pub-key for server A stored on server B and vice versa. And then ensure, that only authenticated calls can be made to server B.
A full-fledged answer would be nice, but actually I am already happy to get a pointer into the right direction about what I should be googling for or maybe another question on SO.
The technical word you're looking for is "authentication" which is the process of establishing that a party is who they say they are. Closely related is "authorization" which is the process of determining if a party is permitted to do something.
For this problem, standard authentication techniques apply, very similar to how they would for a user. Generate a long, random authentication token and store it on server B. Connect from server B to server A using HTTPS, and pass the authentication token. A popular way to do this is with Bearer Authentication. Add the header:
Authorization: Bearer {access_token}
On server A, verify the token and execute the request if authorized.
This is just a specific way of implementing an API key. You could just as well put the access token (API key) directly into the request. It would be identical.
Typically these keys are stored in environment variables if you have a containerized or virtualized setup. I don't recommend storing them directly in the code (there are too many small mistakes that can lead to the code being visible).
There are more complex ways to do the same thing, and if you already have a good system for authenticating users, you can also just create a "service account" for server B and use your normal authentication scheme. But bearer tokens are a nice, simple way to handle machine-machine authentication without creating fake accounts.
Note that all approaches require that you be able to secure server B. Anyone who can access server B will be able to steal the token and impersonate the server. Mitigating this generally requires specialized hardware (such as an HSM), and is beyond the needs of most systems.
Though a bit more complex, another common technique is signing your requests. The advantage of signing is that you never have to send your authentication token over the network (even using HTTPS), and you only have to store the private key in one place (server B). This means that not even server A can masquerade as server B like it can with bearer authentication. I've often used JWS (JSON Web Signature) for this, but it is fairly complicated if you don't have a good library that handles it for you. Signing without JWS is tricky to get right, since you have to be very careful to sign everything that matters, and it's easy to overlook parts of the requests (headers for example). If you go down that road, you'll probably want a security expert to look it over.
Moving up from that, as Mikah notes, is OAuth2, but I generally don't recommend that for point-to-point authentication where you control everything and there aren't many entities. It's just a lot of complexity for little benefit. The point of OAuth2 is allowing centralized management of complex authentication environments. If you don't have those problems, complexity tends to reduce security, not improve it.
I'm currently working on a mobile application with an Objective C developer. Because of the nature of mobile devices and how they work, all data is retrieved through an API I have created.
For example, if the user is trying to find something specific to do with the application on a page (a search maybe), the application would make a request:
http://mydomain.com/api/search?param1=hello¶m2=world
If these calls are made from the mobile device through the application I know they are legitimate requests (what I class as legit, anyway). If they're coming from somewhere else I really need to stop that. For example, another developer could copy the exact same application and use the API I have built on my server and there is no way I know of that can stop them doing that.
Is there a way I can secure the API some how to stop the API from being accessed outside the app?
Assuming there are no user accounts for authentication, the only way to secure the app is to hardcode a security token in the mobile app. And even doing so, it won't be 100% secure, because of reverse engineering.
Your API only receive HTTP requests, so the only way to differenciate a legitimate with a non-legitimate request is to send a further information that will be considered as valid on your server side (as OAuth tokens), but if there are no user accounts, you will have to send an identical token shared by all apps (or following a commnon rule).
I think that the best solution here is to hardcode the security token, it will at least force "hackers" to reverse engineer your app and not just sniffing the network.
My iOS app needs to connect to a mysql server. To accomplish this, I'd like to create a webapp that acts as the middleman between the client side apps and the server side database.
My concern is that someone can simply figure out the URL that my app uses and pass their own URL parameters - and since the webapp has no idea whether legitimate data is being sent from my iOS app vs. someone just typing in the properly crafted URL from any web browser, the system will be vulnerable.
Let's say I have a PHP function for marking a user as "verified" (after I send them an email verification code). This is pretty standard stuff, but what's stopping someone from making the same request from a web browser?
Of course, the user that the app uses to make database queries will have limited privileges, so the rest of the database won't be at risk. However, even having users activating their accounts from outside the app would be catastrophic.
The option that I thought of was using https so that even if the user figures out the URL, they won't know the password and wouldn't be able to sniff it since it's encrypted from start to finish. Unfortunately, https can be expensive for a poor college student, so I'd like an alternative if one exists.
As stated before, there is no 100 % security possible. But there are several solutions that put together give great security.
Https
As you point out, this is an important part , as it prevents sniffing.
Sessions
Use sessions and don't allow any request without a valid session ( except the first, that must authenticate the app ).
Fingerprint
Check the user agent and set extra http headers, to get a fingerprint unique to your app. ( Still someone could sniff, but he needed to use curl or similar. )
Obfuscate requests
Build your query string and apply a hash function. The server needs to implement the reverse function. ?43adbf764Fz instead of ?a=1&b=2
Encrypt
This goes a step further. Use a shared secret to calculate a hash. On the server repeat the same. This is already strong security. In order to break, one needs to reverse engineer your app.
Use unique shared secret
You say it is a app for iOS. Upon installation a unique token is generated by iOS. Have your app register this token with your server. Like this you have a strong shared secret unique to each installation, and there would be no way to hack your web app.
First of all, a better question would be is this possible? My gut instinct is that it isn't entirely, but there may be some clever ways. Even if they just act as a deterrent, make it slightly harder for some one to hack, or even make it easier for me to detect suspicious activity.
Basically, I'm building a web service using PHP for my C#.NET program to connect to. Among other things, one of the most important purpose the web service serves is verifying license data. The program sends the licence key entered by the user to be checked, and if it is valid the web service will return the Name of the person who purchased the licence key so that the program knows to activate itself.
I am fully aware that there is no perfect anti-piracy scheme and that is my software will be cracked if people want it bad enough. However, I do not believe that there isn't anything I can do to make it very hard for people to crack my software.
I do have an SSL certificate so the program will be communicating with the web service using HTTPS, however that's the only security I have at the moment. I have thought about
Using long and obscure names so that the functions are hard to guess
Using MD5 to disguise the functions
Adding a username and password
Checking the User-Agent
etc.
However, I have read that there are applications available to simply extract strings from programs, which would render those measures completely ineffective. Still, I don't know how technical users have to be to use those applications. Is it still worth adding some of these measures to stop casual piracy? Which measures are the better ones and what will be the most effective?
Thanks in advance
You can distribute your C# application with a certificate bundled and sign your requests with the certificate. The server can then verify if the request was signed by your application and reject any other request.
Edit: Whoops, I only now understood that you want to secure you application even when in the hands of a malicious user. This, I don't think is possible. A hacker can decompile, scan the memory, read and decode files, etc and your certificate will be available in there if you distribute it with the application. An alternative would be to distribute an external security token (hardware device or flash storage) which will need to be plugged-in to the client computer. The token holds the certificate, keys or cyphers used to sign/encrypt your requests and it therefore doesn't stay with the application.
Your server-side SSL certificate will only guarantee that the communication channel is secure and the server is not lying about his identity. It doesn't guarantee anything about the client connecting. To also be sure that the client is identified, you need to use a form of client certificate that your server recognises.
We have the following:
iPhone native app, with login form that posts to:
A php script on remote web server which checks against MySQL user table.
For security, would it be best practice to use some two-way encryption to encrypt every request? including this initial login? otherwise the user and pass will simple be passed to the web app in the clear?
I suppose https would take care of it automatically...
It would be very wise to use SSL or TLS (the protocols that HTTPS uses) to communicate with the server. You could likely get this set up rather easily on a *nix or Windows server using OpenSSL. If you're on a shared host, they likely have an option to purchase an SSL certificate that's valid for a given period of time. This is a fairly trivial process and usually requires about a week (average) with most hosts to get set up.
It should also be noted that while it is never a bad idea to encrypt the login process, it will not make your system more secure "over all" if you have a login from the web that is not secured. For instance, if you secure communication with mobile devices, but not with desktops or laptops, your security may be for nigh. The security of your application is only as strong as its weakest link, so securing your entire application (for all platforms) is very important.
Also, keep in mind that a user's login credentials are only as valuable as the data or resources that they protect: if you encrypt the login information, it is also a good idea to encrypt the rest of the application as well. Wireless sniffing technology could easily steal session data, private user information, or other sensitive data. Securing the entire user session--rather than just the login procedure--is in your users' best interest.
Hope this helps!
Using https is probably the way to go. It's what it was designed for.