سؤال

Obviously I am no android or java expert. What I want to do in my Android app is, load data from a server. I already got working this part and sourcecode is attached. But I want to do it in a way which is secure. As a first step, instead of http://thisismyurl.com/a.php?action=get I want to do it with username/password like this: http://username:password@thisismyurl.com/a.php?action=get How would I do it? Should I just add the username and password part to the url?

Lets say I've accomplished that this will not be of any of use, because someone can just open the apk and decompile the sourcecode and get the url and the username/password. so is there a truly secure way of doing that?

I hope I am getting understood here.

String url = "http://thisismyurl.com/a.php?action=get";
String result = Web.executeWeb(url);

public class Web {

    public static String executeWeb(final String url) {

        final StringBuilder sb = new StringBuilder();

        Thread thread = new Thread(new Runnable() {
            public void run() 
                {
                try 
                {
                    InputStream is = (InputStream) new URL(url).getContent();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    String result, line = reader.readLine();
                    result = line;
                    while((line=reader.readLine())!=null){
                        result+=line;
                    }

                    sb.append(result);
                    //System.out.println(result);       
                    //Log.i("My Response :: ", result);

                } catch (Exception e)
                {
                // TODO: handle exception
                }
            }
          });   

        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return sb.toString();

    }   

}
هل كانت مفيدة؟

المحلول

To start with, you should firstly consider what you want to achieve and how and afterwards decide what you need.

Firstly, you have to be clear that malicious users will try to crack your app, and if your app stores financial, personal or other kind of sensitive data, the persistence will increase exponencially.

That being said, a few considerations:

  • Hardcoding keys into your code is a bad idea. If you do that, it's just matter of time for a cracker to decipher what key have you used.

  • Hardcoding keys in the URL is even a worse idea. Keep in mind your URL will travel through a lot of places before reaching the end point (your server) and meanwhile anyone who was access to see that traffic will see your credentials, and even without effort as you're sending them unencrypted.

  • Depending on how will you generate your keys, I'd suggest using either symmetric or asymmetric encryption:

    • If you plan to store an unique password for all your clients (which is, by the way, also a bad idea, because if the malicious user breaks your key, they might have all your client's information), you could use a symmetric encryption method like AES. You simply encrypt your messages, send them via HTTP POST (for example) and decrypt it on the other side. Pretty easy concept.

    • If you plan to generate a key for each of your clients, you have the additional handicap that you somehow need to make your server know the key you have generated, or your client know which key has generated for the client (dependind on how you face it). In this context you could use the next points approach (which is basically the one I would recommend from amongst all these).

  • You could simply use an assymetric encryption method. That means that the server generates a pair of keys, one public and one private. Users (clients) will have the public one to encrypt messages and send them to the server. You might be wondering: And how do I protect my messages so noone can decrypt them but my server? That's where the private key joins, you can just decrypt messages if you have the private key. That's why you don't want to share it with anyone (that's where its name comes from). This way, your clients may have your public key at anytime without any obfuscation needs, then you use it to encrypt some text and send it. The server will decrypt the message using its private key and process it accordingly.

Advantages of this last approach are:

  • You don't have to worry on how to make your key reach the other party securely, as it will be encrypted and just the server is able to decrypt.

  • You don't need to generate a key for each of your clients.

  • If you choose a good asymmetric algorithm such as SSL/TLS, you don't need to worry about its cracking (or at least, not as much as if you had chosen some other approach).

  • Replacing an old pair of keys is such easy as generating a new pair, replacing the old private key and make your clients have the new public key.

You might want to have a look at these links:

  1. Public-key cryptography

  2. Symmetric-key algorithm

  3. Advanced Encryption Standard (AES)

  4. Transport Layer Security

نصائح أخرى

what I did is that , I used AES encryption for this. whenever user register i send an encryption key and version in the header to the appliation so all communication will be encrypted.server always check for the version of key and then decrypt accordingly. if new key available server send new key to the application and then application update key and then decrypt with that.

i used these method to decrypt and encrypt in android.

   public  byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
    Cipher cipher = Cipher.getInstance(cipherTransformation);
    SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
    cipherText = cipher.doFinal(cipherText);
    return cipherText;
}

public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
    Cipher cipher = Cipher.getInstance(cipherTransformation);
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    plainText = cipher.doFinal(plainText);
    return plainText;
}

and in request add header like

request.addHeader("KeyVersion",String.valueOf(utils.getInt(Key.Key_Version)));
    request.addHeader("EmpId",String.valueOf(utils.getInt(Key.Emp_Id)));

and when response come i check for new key like

Header[] headers = response.getHeaders("KeyVersion");  

    if(headers.length>0){
        String keyVersion = headers[0].getValue();
        if (keyVersion == null) {
            System.out.println("Key 'Server' is not found!");
        } else {
                System.out.println("Key 'Server' found! -- with version "+keyVersion);
                if(utils.getInt("KeyVersion")<Integer.parseInt(keyVersion)){
                    utils.saveInt("KeyVersion", Integer.parseInt(keyVersion));
                    utils.saveString("Key", response.getHeaders("KeyValue")[0].getValue());
                    String s = response.getHeaders("KeyValue")[0].getValue();
                    System.out.println("key is "+s);
                }
        }

Encryption isn't the answer.

If someone wants the URL, user and password, which are stored in the client, you cannot avoid it. Even if it's encrypted, you have to provide the decryption key to the client, which then could be decompiled itself.

You cannot prevent reverse-engineering of your service interface.

And therefore cannot prevent other clients to use your service interface. It's easy to sniff the network traffic with Fiddler. Even SSL is no problem, because we can manipulate the client itself, before the data becomes encrypted.

Let's see some other SO threads about reverse-engineering.

Following on from nKn's answer:

One way of doing what you want to do is use both asymmetric and symmetric encryption, what you do is this:

  1. Client initiates a connection to the server
  2. Server generates a pair of public and private keys for asymmetric encryption (RSA for example).
  3. The Server sends the public key unecrypted in plaintext to the client
  4. The client generates a new unrelated key for the symmetric encryption (AES for example).
  5. Client uses the public key from before to encrypt the symmetric-algorithm key and send it to the server.
  6. Server decrypts the message using the private key, and now both sides have a common symmetric key to use.

This approach forces the client to generate a new symmetric key every time, so you need your server to keep the correct key for every connection/session. You cannot use this approach if you want a static symmetric key, for this you can use another approach:

  1. Client generates the asymmetric key pair and send the public key to the client.
  2. The Server uses the public key to encrypt the symmetric key and send it to the client.
  3. The Client decrypts the message using the private key, and destroys the private key as soon as possible. - Now both sides share the same symmetric key

With the second approach you can just store the symmetric key on your server and you don't have to store a different key for every connection/session. I would still advise you to periodically change the symmetric key, just to be sure.

Both approaches do not force you to hard code keys into your client code, or send symmetric keys in plaintext. The only thing that is sent in plaintext is the public key, and that is not a problem at all, hence the name "public key".

String httpsURL = "https://www.abcd.com/auth/login/";

String query = "email="+URLEncoder.encode("abc@xyz.com","UTF-8"); 
query += "&";
query += "password="+URLEncoder.encode("abcd","UTF-8") ;

URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
con.setRequestMethod("POST");

con.setRequestProperty("Content-length", String.valueOf(query.length())); 
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)"); 
con.setDoOutput(true); 
con.setDoInput(true); 

DataOutputStream output = new DataOutputStream(con.getOutputStream());  


output.writeBytes(query);

output.close();

DataInputStream input = new DataInputStream( con.getInputStream() ); 



for( int c = input.read(); c != -1; c = input.read() ) 
System.out.print( (char)c ); 
input.close(); 

System.out.println("Resp Code:"+con .getResponseCode()); 
System.out.println("Resp Message:"+ con .getResponseMessage());

First, never work with password itself, work only with hash representation(sha1 function) of password. Second, you can use SSL (https)to establish secure connection. To sum it up ,after user clicks on login button ,get password from edittext and create hash of it. On server side also use hash representation. Next, send data as body of https request to www.yoursite.com/login and in request body will be your data. Send it as json f.e...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top