Aplikacja Android pobieranie danych z serwera, ale w bezpieczny sposób

Oczywiście nie jestem ekspertem od Androida ani Javy. To, co chcę zrobić w mojej aplikacji na Androida, to załadować dane z serwera. Już pracuję nad tą częścią i dołączony jest kod źródłowy. Ale chcę to zrobić w sposób bezpieczny. Jako pierwszy krok, zamiast http://thisismyurl.com/a.php?action=get chcę to zrobić z nazwą użytkownika/hasłem w ten sposób: http://username:[email protected]/a.php?action=get Jak to zrobić? Czy powinienem dodać nazwę użytkownika i hasło do adresu url?

Powiedzmy, że osiągnąłem to, że nie będzie to przydatne, ponieważ ktoś może po prostu otworzyć apk i dekompilować kod źródłowy i uzyskać adres url i nazwę użytkownika / hasło. czy jest na to naprawdę bezpieczny sposób?

Mam nadzieję, że mnie zrozumiano.
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();

    }   

}
Author: warvariuc, 2014-03-24

6 answers

Na początek powinieneś najpierw zastanowić się, co chcesz osiągnąć i Jak , a następnie zdecydować, czego potrzebujesz.

Po pierwsze, musisz być pewny, że złośliwi użytkownicy będą próbowali złamać Twoją aplikację, a jeśli Twoja aplikacja przechowuje poufne dane finansowe, osobiste lub inne, trwałość wzrośnie wykładniczo.

To powiedziawszy, kilka rozważań:

  • Hardcoding keys into your code is a bad idea. Jeśli to zrobisz, to tylko kwestia czasu, żeby krakers rozszyfrował, jakiego klucza użyłeś.

  • Klawisze kodowania twardego w adresie URL to jeszcze gorszy pomysł. Pamiętaj, że twój adres URL będzie podróżował przez wiele miejsc przed osiągnięciem punktu końcowego (twojego serwera), a tymczasem każdy, który miał dostęp do ruchu, zobaczy Twoje poświadczenia, a nawet bez wysiłku, gdy wysyłasz je niezaszyfrowane.

  • W zależności od tego, jak wygenerujesz swoje klucze, proponuję użyć albo szyfrowanie symetryczne lub asymetryczne:

    • Jeśli planujesz przechowywać unikalne hasło dla wszystkich swoich klientów (co jest, nawiasem mówiąc, również złym pomysłem, ponieważ jeśli złośliwy użytkownik złamie twój klucz, może mieć Wszystkie Informacje o Twoim kliencie), możesz użyć symetrycznej metody szyfrowania, takiej jak AES. Po prostu szyfrujesz swoje wiadomości, wysyłasz je przez HTTP POST (Na przykład) i odszyfrowujesz je po drugiej stronie. Całkiem prosta koncepcja.

    • Jeśli planujesz wygenerować klucz dla każdego z Twoich klientów masz dodatkowe utrudnienia, które musisz jakoś sprawić, aby twój serwer znał klucz, który wygenerowałeś, lub twój klient wiedział, który klucz wygenerował dla Klienta (w zależności od tego, jak sobie z tym radzisz). W tym kontekście możesz użyć podejścia next points(które jest w zasadzie tym, które polecam spośród tych wszystkich).

  • Możesz po prostu użyć metody szyfrowania asymetrycznego . Oznacza to, że serwer generuje parę klucze, jeden publiczny i jeden prywatny. Użytkownicy (klienci) będą mieli publiczny do szyfrowania wiadomości i wysyłania ich na serwer. Być może zastanawiasz się: jak chronić moje wiadomości, aby nikt nie mógł ich odszyfrować poza moim serwerem? Tam dołącza się klucz prywatny, możesz po prostu odszyfrować wiadomości, Jeśli masz klucz prywatny. Dlatego nie chcesz dzielić się nim z nikim (stąd pochodzi jego nazwa). W ten sposób Twoi klienci mogą mieć twój klucz publiczny w dowolnym momencie bez potrzeby maskowania, a następnie używasz go do szyfrowania tekstu i wysyłania go. Serwer odszyfruje wiadomość za pomocą klucza prywatnego i odpowiednio ją przetworzy.

Zalety tego ostatniego podejścia to:

  • Nie musisz się martwić, jak bezpiecznie dotrzeć do drugiej strony, ponieważ będzie on szyfrowany i tylko serwer jest w stanie odszyfrować.

  • Nie musisz generować klucza dla każdego z klientów.

  • Jeśli wybierzesz dobry asymetryczny algorytm, taki jak SSL / TLS, nie musisz martwić się o jego pękanie (a przynajmniej nie tak bardzo, jak gdybyś wybrał inne podejście).

  • Wymiana starej pary kluczy jest tak łatwa, jak wygenerowanie nowej pary, wymiana starego klucza prywatnego i sprawienie, aby klienci mieli nowy klucz publiczny.

Możesz rzucić okiem na te linki:

  1. Kryptografia klucza publicznego

  2. Klucz symetryczny algorytm

  3. Advanced Encryption Standard (AES)

  4. Transport Layer Security

 7
Author: nKn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 09:20:11
String httpsURL = "https://www.abcd.com/auth/login/";

String query = "email="+URLEncoder.encode("[email protected]","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());
 0
Author: Kanaiya Katarmal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 07:15:39

To , co zrobiłem, to to, że użyłem do tego szyfrowania AES. za każdym razem, gdy użytkownik się zarejestruje, wysyłam klucz szyfrowania i wersję w nagłówku do aplikacji, aby cała komunikacja była szyfrowana.serwer zawsze sprawdza wersję klucza, a następnie odpowiednio odszyfrowuje. jeśli dostępny jest nowy klucz, serwer wysyła nowy klucz do aplikacji, a następnie klucz aktualizacji aplikacji, a następnie odszyfrowuje go.

Użyłem tej metody do odszyfrowywania i szyfrowania w Androidzie.

   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;
}

I w zapytaniu dodaj nagłówek jak

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

I kiedy przyjdzie odpowiedź sprawdzam nowy klucz jak

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);
                }
        }
 0
Author: Waqar Ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 07:16:20

Po pierwsze, nigdy nie pracuj z samym hasłem, pracuj tylko z reprezentacją hash (funkcja sha1) hasła. Po drugie, możesz użyć protokołu SSL (https)do ustanowienia bezpiecznego połączenia. Podsumowując, po kliknięciu przycisku login, Uzyskaj hasło z edittext i utwórz jego hash. Po stronie serwera również użyj reprezentacji hash. Następnie wyślij dane jako treść żądania https do www.yoursite.com/login a w treści żądania będą Twoje dane. Wyślij jako json f.e...

 0
Author: Palejandro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 07:43:25

Szyfrowanie nie jest rozwiązaniem.

Jeśli ktoś chce adresu URL, użytkownika i hasła, które są przechowywane w kliencie, nie można go uniknąć. Nawet jeśli jest zaszyfrowany, musisz dostarczyć klientowi klucz deszyfrujący, który następnie może zostać zdekompilowany.

Nie można zapobiec inżynierii odwrotnej interfejsu usługi.

I dlatego nie może uniemożliwić innym klientom korzystania z interfejsu usługi. Łatwo wywęszyć ruch sieciowy za pomocą Skrzypek . Nawet SSL nie stanowi problemu, ponieważ możemy manipulować samym klientem, zanim dane zostaną zaszyfrowane.

Zobaczmy inne wątki o inżynierii odwrotnej.

 0
Author: Christian Strempfer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:32:48

Kontynuacja odpowiedzi nKn:

Jednym ze sposobów robienia tego, co chcesz zrobić, jest użycie zarówno szyfrowania asymetrycznego, jak i symetrycznego.]}

  1. Klient inicjuje połączenie z serwerem
  2. Serwer generuje parę kluczy publicznych i prywatnych do szyfrowania asymetrycznego (na przykład RSA).
  3. serwer wysyła klucz publiczny niezaszyfrowany tekstem jawnym do klienta
  4. klient generuje nowy niepowiązany klucz do szyfrowania symetrycznego (AES dla przykład).
  5. Klient używa klucza publicznego sprzed szyfrowania klucza algorytmu symetrycznego i wysyła go do serwera.
  6. Serwer odszyfruje wiadomość za pomocą klucza prywatnego, a teraz obie strony mają wspólny klucz symetryczny do użycia.

To podejście zmusza klienta do generowania nowego klucza symetrycznego za każdym razem, więc serwer musi zachować poprawny klucz dla każdego połączenia/sesji. Nie możesz użyć tego podejścia, jeśli chcesz statycznego klucza symetrycznego, do tego możesz użyć inne podejście:

  1. Klient generuje asymetryczną parę kluczy i wysyła klucz publiczny do klienta.
  2. Serwer używa klucza publicznego do szyfrowania klucza symetrycznego i wysyłania go do klienta.
  3. Klient odszyfruje wiadomość za pomocą klucza prywatnego i niszczy klucz prywatny tak szybko, jak to możliwe. - Teraz obie strony mają ten sam symetryczny klucz

Przy drugim podejściu możesz po prostu zapisać klucz symetryczny na serwerze i nie musisz przechowywać inny klucz dla każdego połączenia/sesji. Nadal radzę ci okresowo zmieniać klucz symetryczny, tak dla pewności.

Oba podejścia nie zmuszają cię do wpisywania kluczy twardych do kodu klienta, ani do wysyłania kluczy symetrycznych w postaci zwykłego tekstu. Jedyną rzeczą, która jest wysyłana w postaci zwykłego tekstu, jest klucz publiczny, a to wcale nie jest problemem, stąd nazwa "klucz publiczny".

 0
Author: Bob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-27 11:28:08