How to secure webservice URL?

2020-03-08 08:23发布

问题:

I have an android app with web service urls. If anyone decrypts my apk file, the webservice url will become visible.I am using HTTP POST for calling web service.

Anyone can read the code by decompiling the apk file from this site.

My registration page url got hacked and sending bulk request to this url with post data. I was using a API_KEY and send the API_KEY with post data. API_KEY was stored in gradle.properties file.

I did not used

 minifyEnabled true
 shrinkResources true
 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'`  when its got hacked.

After some search, i know that there is no 100% secure methods to hide url.

My code for registration is :

String link = "http://xxxxxxxxxx.php";

String data = URLEncoder.encode("name", "UTF-8") + "=" + URLEncoder.encode(name, "UTF-8");
data += "&" + URLEncoder.encode("phone", "UTF-8") + "=" + URLEncoder.encode(phone, "UTF-8");
data += "&" + URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode(password, "UTF-8"); 

URL url = new URL(link);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();

I don't know if it is the correct method to post data to a Url.

How can i secure my source code?

Can i store all my web service url in server?

I am beginner to android. Please help!

回答1:

There is no way to protect "secret" information such as URLs embedded in an APK. A determined / motivated hacker can defeat any scheme you care to design ... if he / she has access to a platform where your app is being run.

In order for your app to run, the app running on the user's device needs to be able to decrypt the hidden URL. The user can either intercept the URL in decrypted form in the app's address space, or he / she can reverse engineer the algorithm and decryption key you are using to do the decryption.

Another "attack" is that your app needs to use the URL to make a request. That request can be intercepted on the users device before it is protected by the SSL / TLS channel to your (presumably) HTTPS enabled service.

And on top of that, if you embed a "secret" URL into an app and that secret is compromised and you have to turn off / relocate your server, then you are making problems for all (legitimate, paying, etc) users of your app. They won't be happy campers.

The correct approach is to make your service secure ... and use some kind of authentication mechanism so that hackers need more than just the URL to make requests. Users can / should be issued with individual credentials (e.g. auth keys), and you need to implement a way to invalidate a given users' credentials at the server end.



回答2:

I use it this in all android application I developed

gradle.properties

API = http://ec2xxxxx.compute.amazonaws.com
API_KEY = $2c11SoL/NjJ28

create utils.gradle

utils.gradle

        class Utils {
        static def r = new Random(System.currentTimeMillis())
    }

    def String toJavaCodeString(String string) {
        byte[] b = string.getBytes();
        int c = b.length;
        StringBuilder sb = new StringBuilder();

        sb.append("(new Object() {");
        sb.append("int t;");
        sb.append("public String toString() {");
        sb.append("byte[] buf = new byte[");
        sb.append(c);
        sb.append("];");

        for (int i = 0; i < c; ++i) {
            int t = Utils.r.nextInt();
            int f = Utils.r.nextInt(24) + 1;

            t = (t & ~(0xff << f)) | (b[i] << f);

            sb.append("t = ");
            sb.append(t);
            sb.append(";");
            sb.append("buf[");
            sb.append(i);
            sb.append("] = (byte) (t >>> ");
            sb.append(f);
            sb.append(");");
        }

        sb.append("return new String(buf);");
        sb.append("}}.toString())");

        return sb.toString();} 
ext.toJavaCodeString = this.&toJavaCodeString

build.gradle

apply from: "utils.gradle"
   android {
    defaultConfig {
        buildConfigField 'String', 'API', toJavaCodeString(API)
        buildConfigField 'String', 'API_KEY', toJavaCodeString(API_KEY)
    }}

and access your private url;

    public static final String API = BuildConfig.API;


回答3:

"URL" stands for Universal Resource Locator. The whole point of a URL is to access some kind of resource, and to do this, you obviously have to tell the network you are connecting to what it is you want to fetch.

Now if you are worried that a hacker can access your source code, then surely he can also hook up Wireshark or Fiddler and simply observe what connections your app is making, and what info you are passing along and receiving back.

Sorry, but I simply can't see any good way around this.

If you're worried about your server/services being hacked or DOS`ed, I think you had better focus on securing them as well as you can, rather than trying to hide them.



回答4:

I have fixed this in two ways

  1. Encrypted the URL in my code with my private key and on request call i decrypted it again,

    public static String encryptIt(String value) {
    try {
        DESKeySpec keySpec = new DESKeySpec(new byte[]{105, 107, 18, 51, 114, 83, 51, 120, 121}); 
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey key = keyFactory.generateSecret(keySpec);
    
        byte[] clearText = value.getBytes("UTF8");
        // Cipher is not thread safe
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, key);
    
        //   Log.d("aa", "Encrypted: " + value + " -> " + encrypedValue);
        return Base64.encodeToString(cipher.doFinal(clearText), Base64.DEFAULT);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return value;
    

    }

and decript it by using this

  public static String decryptIt(String value) {
    try {
        DESKeySpec keySpec = new DESKeySpec(new byte[]{105, 107, 18, 51, 114, 83, 51, 120, 121});//cryptoPass.getBytes("UTF8"));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey key = keyFactory.generateSecret(keySpec);

        byte[] encrypedPwdBytes = Base64.decode(value, Base64.DEFAULT);
        // cipher is not thread safe
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decrypedValueBytes = (cipher.doFinal(encrypedPwdBytes));

        // Log.d("aa", "Decrypted: " + value + " -> " + decrypedValue);
        return new String(decrypedValueBytes);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return value;
}

note in my case that the private key is new byte[]{105, 107, 18, 51, 114, 83, 51, 120, 121} i think it was $ecrEt or something like i forget it.

so if they decompile the APK they wan't be able to find the service link inside you code.

so the base url will be like this public static final String ROOT_API = "aHR0cHSC86LSy9tbS2JpuZW50aWtoYWAbGUJhdC5qbw==";

2- Also you have to add progaurd to your code

BUT, they can smurfing the netweok and find the url if the hacker is advance person, in this case you have to user SSl certificate "https" and make the webserivce POST.

hope you got my point.