Reverse engineering is a great problem for android apk. Anyone can easily generate code from apk file using dex2jar and jd. Proguard can gives little bit security by changing the variable/method name. Problem is .so file. As an example, i have a so file which has a encrypt and decrypt method in it. If someone get my apk then he can easily get the so file and by creating a new project with same package name (not hidden in native loading class) he can use the functions without any problem.
Is there any solution to prevent this?? Is there any way so that i can identify my project from native code and reject the request if it comes from invalid project? Eclipse sign the apk with a key-store and password. Can i check the sign information from native code??
My 2 cents are that Proguard is just a basic obfuscator(till a point). There are many other services/tools(which might not be completely free) but do good obfuscation, app integrity protection, Tamper detection and Tamper defence etc. Check out Arxan and DashO Pro.
You might try to use them for more protection. They even work with rooted devices. Hope this helps in someway.
The problem
This is a classic problem with any intermediary bytecode language: JVM languages (Java, Groovy, Akka, etc.), CLR languages (C#, ASP.NET, etc.) and more. Since the procedures to compile the source code to its intermediary bytecode are well-documented and fairly straight-forward, it isn't all that difficult to reverse engineer the bytecode back into source.
As #Shobhit Puri has already pointed out, a good obfuscator will help deter most would-be attackers from expending the energy to decompile your bytecode. But any determined attacker with enough skills will be able to reverse engineer any obfuscated code (please note that there are many high quality Java de-obfuscators out there...) you can generate.
So how does one mitigate this?
Your best bet is to store any sensititve resources or business logic on the server, and have the client (your Android app) access those resources or invoke that business logic in a defensive way. By "defensive", I mean you code the client in such a way that any attacker who successfully obtained your full source code wouldn't be able to ascertain anything meaningful with it.
For instance, instead of:
// Get password from user input:
String password = getUserInput();
// Make sure password is correct.
if(password.equals("12345") {
// Grant access to the system
} else {
throw new SecurityException("Blah whatever");
}
You have this:
// Get password from user input:
String password = getUserInput();
// Make sure password is correct.
String correctPassword = passwordService.fetchFromServer();
if(password.equals(correctPassword) {
// Grant access to the system
} else {
throw new SecurityException("Blah whatever");
}
If an attacker were to get access to your source code, and you provide access to the password somewhere on the client-side (even if its encrypted), eventually they'll figure out how to break in. But if you fetch the magical password from the server, and never reference its value anywhere on the client, then they now need to break into your server to get access to it.
Then all you have to do is properly secure your app server, and for that you have excellent prospects like:
Apache Shiro
OWASP ESAPI
Webcastellum WAF
Spring Security
...and countless more; welcome to the world of websec
Note that in my code example above, ultimately there is no perfect defense against a skilled-enough attacker. For instance, a skilled attacker could sniff the network traffic between the client and the server during the time that the passwordService#fetchFromServer() call was made. If the password is returned as plaintext, voila - they have it. Even if the password is returned using SSL or some other strong encryption, your client will need to store or access the private key for that encryption somewhere locally. Once they have the private key, they'll be able to access the password. All this to say:
There is no such thing as perfect security. There is no such thing as an unhackable system. The purpose of your security should be to make the cost of obtaining the resource far greater than the value of the resource itself.
Bottom Line
As a smart developer, you need to assume that the attackers will exploit your client application every which way. You need to assume that they will eventually gain access to your client's source code, and even understand how it communicates with your server. And on the server-side, you need to assume that every request coming from a client is an attack, and treat it as such. This will put you in the right state of mind to code defensively.
What you need to beef up on is server-side security, and that is not trivial by any means. But if you just remember to keep all sensitive code and data on the server, and access it defensively on the client-side, you'll do more to protect your app than any obfuscator can offer you. HTH and happy coding.
Related
A few days ago one person decompiled my app and show me an issue in my source code. I was hardcoding the links and the password of my server in source code of the app, I didn't know through decompiling anyone can see my source code. I use proguard but proguard doesn't obfuscate strings. This left me wondering how is the right way to do this? How can my app make api calls and the server can authenticate it? I did a research but I did't see much content talking about this. My app doesn't manage users and passwords. The user and password that I store in my code are the ones to login in the server.
Yes, it is pretty easy to see decompiled Java code to get keys and the like.
There are a few things to do:
Ensure the "application keys" or "tokens" are not a secret with deep admin privileges. Many SaaS / API Providers give you multiple keys. One is a client key that is limited in privileges/actions that can be performed, and a server key that has more privileges but won't be leaked out via client code. In you case, you shouldn't share the same server login/admin passwords. Leverage Principle of least privilege (https://en.wikipedia.org/wiki/Principle_of_least_privilege)
Ensure the string is a static final. In this case, Compiler and Proguard which allow string inlining. This makes it a little harder to know what the string is for. If you have a single "Config" class, it's pretty easy to search for 'facebook' in facebookAppId, 'secret' googleSecret, etc.
To be really secure, you can perform some encryption, or other algorithm on the string, but this means you also store the encryption secret in the code itself also.
In general, I believe (1) gives the most since you should always assume any string in client can be found/hacked, whether Android/Java with Proguard or minified javascript.
From this. We can't prevent reversing engineer.
But how do we detect if app have modified and trying to access our server?
Especially in iOS and Android.
Something we have used with success for a while now is the following :
During the compile phase, make MD5's of the DLL's & Executable and save them to a place the server can access.
Before the client connects to the server, have it compute the MD5's as well
OnConnect, send the MD5's to the server and have the server validate them
Since the correct MD5's should be a secret to the server, you will catch early attempts made to modify the code, and flag those accounts for further review. But even then an above-amature level dev will figure this out and just send the MD5's you are expecting.
It's not fool proof, but i honestly believe nothing is, all you can do is complicate it as much as possible, this does complicate things a little bit since the MD5's will change every time you publish an update, you could even hash the MD5 with the connectionID, which would make each connection's hash it sends to the server unique.
Using this approach will make it impossible to disabled/remove the checks, because the server always expects an MD5/Hash to be sent.
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead("path-to-your.file"))
{
return md5.ComputeHash(stream); // returns the MD5 byte[]
}
}
As the post you linked to said very well :
You basically can't protect your application from being modified. And any protection you put in there can be disabled/removed, You can do different tricks to make hacking harder though.
I've closed this question. But I've an idea. Hope some of you consider and comment about this.
As the answer said.
You basically can't protect your application from being modified. And any protection you put in there can be disabled/removed, You can do different tricks to make hacking harder though.
Any protection in client can be removed.
How about
Put the verification code on server.
Download this code and run it at runtime. (each run must expect unique result)
Send verification result to server for authorise it.
Because you have download a part of script. you have to download DLL from server side or alternative use this
I'm making an application where users can store data on the device. I was thinking about using database storage. But I've been reading somewhere that it is possible to manipulate data that is stored locally on the device. So what would be the best way to avoid such "attack" on the data? I have been thinking about encrypting each field in the database, but again then I have to store an encryption key on the device as well(?), which again I guess can be located? So does anyone have any other ideas/improvent of my thoughts?
Thanks for any help!
I'm looking for a way to make it a big challenge
Challenge accepted :)
The first thing you should do is to store the data in your app directory since it is not readable for the user / other apps on a regular device. Links to app data con be obtained from Context e.g. Context.html#getDir(). The directories you get from Environment are public.
That prevents average users from getting the data. But a lot of people have rooted devices and can access the data without problems, so that is still pretty insecure.
To make it a lot harder you'll need encryption. Any strong encryption that is not fundamentally broken like WEP will do. Using encryption you force the user to find the key (and encryption method) since the encrypted data can't be decrypted in reasonable time.
That leads to the problem of having a secret key somewhere available to your app but not the user. And this is the part where you need to get creative since there is no secure way to do that.
The simplest way is to put the key in plaintext in your app code. Like private static final String SECRET = "42". By simply having encrypted files you will already stop most users from digging further since at that point you need some programming skills to read the data.
If the user has those skills he will likely start to look at the code of your app (using e.g. dex2jar + jd-gui). You should do the same if you want to know how hard it is to reverse engineer your app.
Understanding the code / finding the encryption method + password will get harder if you use proguard to obfuscate the code because app internal class-, method- and variable names will be shortened to A.B.c(d) like code. But method calls to Android's API can't be renamed since you would need to rename the methods on the device. Also string constants like "42" won't be changed.
The next step of making it harder is to replace that constant by something dynamically generated by your code. The basic example below for example builds the password by dividing numbers by two. The advantage when using this approach is that the password is no longer stored in plaintext and you need to understand / reverse engineer the method that converts the data into the password.
private static final byte[] password = {8, 4};
private String getPassword(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(String.valueof(b / 2));
}
return sb.toString();
}
// returns "42" if I did not make a mistake
The next vulnerable point is that calls to device crypto APIs can be easily located (since they can't be renamed) which makes it a lot easier to figure out where to look for the encryption. If you don't want to write your own crypto method which I would strongly suggest you don't because a slight error in here may corrupt data or break the complete encryption.
That problem can be hardened if you use reflection for example (calling methods by supplying the name of the method / class supplied in a String). That String can as well be obfuscated like above example did with the password.
If you do all that and don't use a method not as simple as this one you can make it really hard. dexguard for example can do that for you but it's not free and has the problem that the same method is used for many apps and a lot more people will try to break that than your custom method.
Finding a good method to hide information in your app that is used to generate a key and a method to hide the key generation & encryption / decryption is best figured out by yourself so the method itself is not public knowledge.
You can use combine a lot of techniques to hide the information like moving parts of that into native code so Java guys like me have a hard time or use a network connection to let your server do some work.
But in the end it's all Security through obscurity and all the extra security measures don't benefit the user but require extra processing time & additional app size.
So what would be the best way to avoid such "attack" on the data?
Do not put it on the device.
I want to make the data secure against the user of the app.
Then do not put it on the device. It is the user's device and the user's bandwidth, and hence it is the user's data.
But I'm looking for a way to make it a big challenge if the user finds out he/she will try to do so.
Simply using a database or something else on internal storage will stop 99% of Android device users from accessing your data. There is nothing you can do to stop the remaining 1%.
I look forward to develop an Android / iPhone application, those will be using a private API (Non-Free) with embedded client-key.
Now, since it is possible to reverse-engineer application binaries and scrap out strings. I am worried of losing my client-key and there by exposing the private API to the attacker.
How to manage this ? Can you provide links to articles discussing such situations ?
Considering I have development access to the private API, what mechanism can I built in to that to preserve the privacy of the whole system.
It will always be possible to use the private API if you have access to your applications code (see this thread as well). You can make it harder, though. And you can restrict the use of the API with the following options
1) if it's not "your" API, don't put the key into the app but into a server you are running to serve as proxy for the foreign service (you probably still want another key for your server to go into the app then)
2) encrypt/scramble the key so it is not grabbed easily:
simple example for scrambling: put the key into a file; generate a random file of same length; xor the key file with the random file (and write it to disk again); whenever you need the key read both files and xor them again (any reversable operation instead of xor will do - more complex operation, spread over your code will make it harder for the reverse engineer)
encrypt your key using a passphrase spread over you app (on deployment android apps are obfuscated anyways, so finding it gets a bit harder)
3) if it's your service or you have a proxy set up, restrict the number of uses per client/IP or offer only parts of the service over your proxy
Note, option 1 may even be required if you have a contract which forbids to make your key public.
I'm wanting to create an android app that gathers information and then uploads to a server -- however I don't want people to be able to edit the file before it's sent to the server. I can do the first part of it, but am unable to do the second part. Can anyone tell me the best way to go about this? I don't mind if the user knows what's in the file, just don't want them editing it and then uploading their edited information to the server.
You're pretty much out of luck since the application is run by the user and the output is controlled by the user. The only way you could take over user's system so he would have no control over it would be using trusted computing with all of the ethical and philosophical implications - see eg. Can You Trust Your Computer? by Richard Stallman. The only thing you can hope for is having a secure connection between your server and user's systems (SSL/TLS) but this is still user's system over which you have no control.
The only correct answer here is Zed's.
The rest of the answers rely on Security through obscurity.
The bottom line is: if device is not totally locked down (= trusted computing) then users can reverse-engineer the application/file-format/network-protocol and submit false data.
Fact of life: people with huge resources (media industry, IT industry) have tried to pull this off (DVD, BluRay, game consoles, etc..) but eventually talented engineers on minimum budget have been able to break this protection schemes.
So, it might work, but only if data is not important and nobody bothers to break it.
There are a couple of approaches you could use here:
Encrypt the file before its saved to the device, the user will be unable to read/modify it.
Encrypt the connection to the server, SSL can protect against a 3rd party interfering with it.
Don't save the file in a public location, place it inside your app's private data directory. The user will be unable to access it.
Depending on how sensitive this information is going to determine which combination of methods to use.
Well as for Android you cannot prevent people from accessing files on the public filesystem.
Maybe there are better ways to handle this but I would simply crypt and decrypt the data before submitting and by using a passphrase or some sort of parity check one could validate the data.
Some rough ideas:
You could view the information that is being sent to the server to the user and then ZIP the file that's being sent with a password beforehand so the user doesn't get a chance to edit it:
Write a password protected Zip file in Java
Of course, you'll have to make sure the user doesn't know the password ...
Or you could build a checksum of the text that's sent and validate the checksum on the server. Here, again, you have to make sure the user doesn't know how the checksum is built and change it accordingly.
Or you could not safe the information to a file at all but into the app's database or private filespace (where non-root-users can't access it).
Whether it's the pasword or the checksum, you could send that information to your server with a normal HTTP-request so it won't be "visible" to the user (followed by a second request that actually sends the file), but if we're talking about users that know how to handle network-sniffers on their phone (needs root, AFAIK), you'll have bad luck, it's their device and their data that's trying to leave it after all :)You could try to use a secure connection to fix this.
What you could do :
Sign the file with your application
Check the signature on the server, check if the certificate is a certificate that is authorized
This will help a bit, but you'll still have the private key bundled with your application... someone may be able to find it and then sign modified files...
Another idea : can you compute the data or is it user generated ? If it's computed why not just compute the data and send it to the server (over SSL) without even writing it to the filesystem ?