Usuari:Raúl Sanchez/Proves
Enmascarament
modificaQue és?
modificaEn Android, l'emmascarament fa refèrencia a les diferents precaucions que es poden prendre per protegir una app contra els intents de descodificació d'una app per veure el codi original (enginyeria inversa). Això pot ser una greu amenaça, especialment si la nostra app conté dades privades com passwords o números de comptes bancaris.
Mètodes d'emmascarament
modificaA continuació es mostren uns exemples de mesures d'emmascarament, llistats de menys a més eficaç.
Strings.xml
modificaSi hem de guardar el valor de l'API key o un string important, l'ho més probable és que el guardem en l'arxiu "strings.xml" de la nostra aplicació. Desgraciadament, aquests valor es fàcilment visualitzable per qualsevol persona utilitzant la comanda strings
. Aquesta comanda es troba inclosa en tots els sistemes operatius basats en Unix, pero també es pot trobar per Windows i altres.
Per exemple, per un apk amb el següent arxiu "strings.xml" [1] :
<resources>
<string name="app_name">HidingPasswords</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="server_password">My_S3cr3t_P@$$W0rD</string>
</resources>
Si utilitzéssim la comanda strings [@ apk] | grep My
[2], veuríem per consola:
$ strings app-x86-universal-debug.apk | grep My
My_S3cr3t_P@$$W0rD
És cert, que podríem canviar el nom de la variable perquè no fos tan obvi el seu propòsit, però això no ens protegiria de què algú ho pogués esbrinar estudiant el nostre codi.
Source code
modificaUn altre lloc on podríem guardar valors és en el mateix codi java de la nostra aplicació. Això complica l'extracció de la variable ja que aquest codi serà comprimit dintre del apk i no serà directament visible utilitzant la comanda strings
.
Per exemple, per un apk amb el següent arxiu "MainActivity.java" [3]
public class MainActivity extends AppCompatActivity {
//A simple static field to store sensitive keys
private static final String myNaivePasswordHidingKey = "My_S3cr3t_P@$$W0rD";
//A marginally better effort to store a key in a byte array (to avoid string analysis)
private static final byte[] mySlightlyCleverHidingKey = new byte[]{
'M','y','_','S','3','c','r','3','t','_','P','@','$','$','W','0','r','D','_','2'
Per trobar les passwords aquest cop caldrà descompilar el codi primer abans de fer servir la comanda strings
sobre l'arxiu "classes.dex" que tindrem descompilat.
$ unzip app-x86-universal-debug.apk
$ strings classes.dex | grep My
My_S3cr3t_P@$$W0rD_2
My_S3cr3t_P@$$W0rD
Build Config
modificaPodríem crear variables en l'arxiu "build.gradle" del nostre projecte i després donar valors a aquests variables dintre de "local.properties" o "gradle.properties". Aquest mètode és una bona idea si mantenim un repositori públic com Github, ja que aquests darrers fitxers són ignorats per .gitignore
i per tant, no seran visibles públicament. Tot i això, un cop vulguem publicar l'app, aquests fitxers tindran que ser afegits al .apk i seran fàcilment visibles.
ProGuard/DexGuard
modificaProGuard ve incorporat en els SDK Tools des d'android 2.3 i és molt senzill d'utilitzar. Només cal activar-ho en el nostre fitxer "build.gradle":
android {
buildTypes {
release {
//minifyEnabled indica si volem minimitzar y obfuscar el codi amb ProGuard.
minifyEnabled true
//getDefaultProguardFile('proguard-android.txt') agafa les regles de codificació per defecte,
//que venen amb la distribució d'android
//'proguard-rules.pro' indica que afegeixi les regles personalitzables.
//Aquest fitxer es troba en la carpeta root del mòdul
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
Nota: Si utilitzem ProGuard no podrem fer servir l'Instant run. Podem optimitzar el codi sense fer servir ProGuard durant els debug, com es veu aquí. Cal anar amb compte, però, ja que es possible que ProGuard elimini codi que cregui inútil, creant errors en la compilació. Per assegurar que una class no s'elimini cal afegir en l'arxiu de configuració ("proguard-rules.pro"):
-keep public class [Nom de la class]
o afegir @Keep
abans de la declaració de la class o funció.
DexGuard és la versió comercial de ProGuard amb un preu consultable en la web oficial i variable depenent de la magnitud de la nostra app. Afegeix mesures més complexes i personalitzades.
Codificació
modificaUna de les aproximacions més efectives. Consisteix en codificar el missatge utilitzant algun mètode de codificació com base64[4][5]. Això augmenta la complexitat del codi, fent-ho molt difícil per a un possible atacant de desxifrar el valor de la variable sense un estudi profund de l'aplicació. Tot i això, continua sent possible trobar aquesta informació.
A continuació podem veure un exemple[6] de codificació fent servir operacions XOR i codificació base64:
MainActivity.java
public class MainActivity extends AppCompatActivity {
//Guardem la clau ja codificada amb base64, en un par de strings. Podem veure com
//es va crear aquesta key mirant la funció "generateKeyXorParts" del arxiu "HidingUtil.java"
private static final String[] myCompositeKey = new String[]{
"oNQavjbaNNSgEqoCkT9Em4imeQQ=","3o8eFOX4ri/F8fgHgiy/BS47"
};
//Utilitzatnt la llibreria base64 descodifiquem la clau i després les ajuntem fent un AND the byte a byte
public void useXorStringHiding(String myHiddenMessage) {
byte[] xorParts0 = Base64.decode(myCompositeKey[0],0);
byte[] xorParts1 = Base64.decode(myCompositeKey[1], 0);
byte[] xorKey = new byte[xorParts0.length];
for(int i = 0; i < xorParts1.length; i++){
xorKey[i] = (byte) (xorParts0[i] ^ xorParts1[i]);
}
//Ara que tenim la clau descodificada, la podem utilitzar per amagar el missatge
HidingUtil.doHiding(myHiddenMessage.getBytes(), xorKey, false);
}
}
HidingUtil.java
import android.util.Base64;
import android.util.Log;
public class HidingUtil {
private static final String TAG = "HidingUtil";
//Funció per codificar un missatge fent una operació XOR amb la clau
public static int xorValues(byte[] msg, byte[] pwd){
int i;
for(i = 0; i < msg.length; i++){
int keyOffset = i % pwd.length;
msg[i] = (byte) (msg[i] ^ pwd[keyOffset]);
}
return i;
}
//Funció que codifica el missatge cridant a xorValues i després codifica el missatge amb base64
public static void doHiding(byte[] msg, byte[] pwd, boolean isHidden){
xorValues(msg, pwd);
if(!isHidden){
String hiddenMessage = Base64.encodeToString(msg, 0);
Log.i(TAG, String.format("Hidden Message: %s", hiddenMessage));
doHiding(msg, pwd, true);
}else{
Log.i(TAG, String.format("Unhidden Message: %s", new String(msg)));
}
}
//Funció per generar el par de claus codificades fent XOR d'un byte de la key i un número aleatori
//després els dos pars de claus són codificats amb base64
public static String[] generateKeyXorParts(String key){
String[] keyParts = new String[2];
byte[] xorRandom = new byte[key.length()];
byte[] xorMatch = new byte[key.length()];
byte[] keyBytes = key.getBytes();
for(int i = 0; i < key.length(); i++){
xorRandom[i] = (byte)(256 * Math.random());
xorMatch[i] = (byte) (xorRandom[i] ^ keyBytes[i]);
}
keyParts[0] = Base64.encodeToString(xorRandom, 0);
keyParts[1] = Base64.encodeToString(xorMatch, 0);
Log.i(TAG, "XOR Key Part 0: " + keyParts[0]);
Log.i(TAG, "XOR Key Part 1: " + keyParts[1]);
return keyParts;
}
}
Servidor extern
modificaEl mètode més efectiu i recomanat per Google. Consisteix en mai mantenir localment cap dada personal i en comptes d'això, enviar-les a un servidor extern propi on podem aplicar mètodes de seguretat molt més estrictes.
Conclusió
modificaPer tal d'ofuscar el codi i que sigui més difícil de fer enginyeria inversa, ProGuard és una eina molt útil. Desgraciadament, cap mètode pot amagar completament el valor d'una variable. Per tant, es recomana desar tota possible informació delicada en un servidor extern.
Bibliografia
modifica- Afegir ProGuard a un Android Project https://developer.android.com/studio/build/shrink-code.html
- Estratègies d'emmascarament https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/
- Connexions segures amb Android https://developer.android.com/training/articles/security-ssl.html
Referències
modifica- ↑ «Exemple de String.xml» (en anglés). [Consulta: 29/10/2017].
- ↑ «Strings (Unix)» (en anglés). Wikipedia. [Consulta: 29/10/2017].
- ↑ «Exemple de MainActivity.java» (en anglés). [Consulta: 29/10/2017].
- ↑ «Codificació Base64» (en anglés). Wikipedia. [Consulta: 30/10/2017].
- ↑ «Documentació llibreria Base64 en Android» (en anglés). [Consulta: 30/10/2017].
- ↑ «Exemple codificació» (en anglés). [Consulta: 30/10/2017].