Aprende a proteger el código fuente de tu aplicación cordova.

Cómo cifrar (proteger y encriptar) el código fuente de una aplicación de Android Cordova

Como ya sabrás, un archivo apk es en realidad solo un archivo zip, por lo que puede intentar cambiar el nombre (o simplemente forzar a su herramienta de descompresión para abrir el archivo apk) appname.apk.zipy extraerlo con cualquier utilidad zip. En este ejemplo vamos a construir una aplicación que usa React (no react native) y webpack para generar todo el código js en un solo archivo app.js. Luego construimos la aplicación usando cordova build android --releasey vemos el contenido del archivo generado por apk (compilación o depuración) project/platforms/android/build/outputs/apkcon una utilidad zip (en este caso vamos a usar WinRAR):

Encrypt Source Code Cordova App

Y si intentas editar algunos de los archivos extraídos (nuestro app.js), contendrá:

Cordova APK source code file content

Ves lo que veo ? El código fuente de tu aplicación, legible para cualquiera que sepa cómo abrir un APK con una utilidad zip . Aunque nuestro código está minimizado para la producción (no hecho por cordova sino por nosotros), el código sigue visible, puede estar bastante impreso y, por lo tanto, legible. Esto no es tan bueno (obviamente) ya que su código puede exponer fallas de seguridad (si las hay) en funciones como el inicio de sesión en su aplicación, el proceso de pagos, etc.

Como dicen muchos desarrolladores, y probablemente necesites saberlo, no existe un 100% de seguridad contra la ingeniería inversa . Sin embargo, puede hacer más para proteger el código de su aplicación, pero de hecho será más difícil sobre todo para el usuario medio, que solo busca en Google "Cómo hackear un APK". Si alguien realmente quiere piratear su aplicación, puede ser pirateada, tarde o temprano (a menos que su aplicación se comunique mucho con el servidor y la mayoría de las funcionalidades no estén en el dispositivo).

En este artículo aprenderá a proteger (o al menos aumentar el nivel de protección) del código fuente de su aplicación en Cordova.

1. Instala el complemento de cifrado

Vamos a utilizar el complemento cordova-plugin-crypt-file  para cifrar todos los archivos dentro de la wwwcarpeta de su proyecto (los archivos que están incluidos en el apk generado). Se puede usar en cualquier proyecto de cordova (incluso si usa Crosswalk) y aunque este tutorial está destinado a usarse solo en Android, el complemento en sí también es compatible con plataformas iOS.

Instale el complemento usando el siguiente comando en su terminal (una vez que esté ubicado en la carpeta de su proyecto):

cordova plugin add cordova-plugin-crypt-file

Una vez que el complemento esté instalado , comenzará a funcionar automáticamente y en cada compilación cifrará los archivos .

¿Cómo funciona el cifrado?

Este complemento utiliza el  algoritmo de cifrado AES / CBC / PKCS5Padding para cifrar los archivos. Los archivos son encriptados por el complemento usando una clave de encriptación generada aleatoriamente y un vector de inicialización (IV) durante la compilación de su aplicación (eso significa que los archivos originales dentro de su proyecto no serán modificados, solo los archivos del APK generado) . Como era de esperar, los archivos se descifrarán cada vez que su aplicación se inicie en el dispositivo instalado.

2. Personalización de los archivos que se deben cifrar

Como se mencionó anteriormente, los archivos están encriptados y no hay forma de desencriptarlos con Javascript. En caso de que necesite que un archivo no se cifre, puede personalizar qué archivos desea cifrar con una expresión regular personalizada. Sin embargo, deberá especificar esto en un archivo del complemento. Comience abriendo el plugin.xmlubicado en el /project/plugins/cordova-plugin-crypt-filey modifique la etiqueta cryptfiles.

De forma predeterminada, el complemento incluye la siguiente expresión regular que cifra todos los archivos css, htm, html y js dentro del directorio www:

<cryptfiles>
    <include>
        <file regex="\.(htm|html|js|css)$" />
    </include>
    <exclude>
    </exclude>
</cryptfiles>

Simplemente personalice la expresión regular para especificar qué archivos se cifrarán, por ejemplo, la siguiente etiqueta comprimirá solo html, htm, js pero no los archivos css y excluirá un solo archivo JS con el nombre example:

<cryptfiles>
    <include>
        <file regex="\.(htm|html|js)$" />
    </include>
    <exclude>
        <file regex="example.js" />
    </exclude>
</cryptfiles>

Guarde los cambios una vez realizados.

3. Verifique si los archivos están encriptados

Ahora, después de la instalación del complemento (y la personalización opcional de archivos para cifrar), puede verificar si el complemento está funcionando o no. Repita el mismo proceso mencionado al principio del artículo. Cree su aplicación (ya sea en modo de depuración o de lanzamiento) y use una utilidad zip para ver el contenido de la wwwcarpeta en su apk ( assets/www):

See Apk Content Zip Utility

Como puede ver, la estructura de los archivos sigue siendo la misma. Finalmente, edite cualquiera de los archivos (siempre que no esté excluido del cifrado) con un editor de código y verá que el contenido del archivo está cifrado:

Encrypted File Content Cordova

Parece ilegible ahora, ¿no ?. El complemento instalado descifrará los archivos durante el tiempo de ejecución, su aplicación se ejecutará como se esperaba y su código fuente tiene un mayor nivel de protección.

Seguridad extra

Puede usar ProGuard en su APK generado con Cordova. ProGuard optimiza el código de bytes, elimina las instrucciones de código no utilizadas y confunde las clases, campos y métodos restantes con nombres cortos. El código ofuscado dificulta la ingeniería inversa de su APK, lo cual es especialmente valioso cuando su aplicación usa funciones sensibles a la seguridad, como la verificación de licencias .

Crea el proguard-rules.proarchivo dentro de la /project/platforms/androidcarpeta con el siguiente contenido:

# By default, the flags in this file are appended to flags specified
# in /usr/share/android-studio/data/sdk/tools/proguard/proguard-android.txt

# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
  public static <fields>;
}

# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep public class * {
    public protected *;
}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
##---------------End: proguard configuration common for all Android apps ----------

#---------------Begin: proguard configuration for support library  ----------
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontwarn android.support.**
-dontwarn com.google.ads.**
##---------------End: proguard configuration for Gson  ----------

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.example.model.** { *; }

##---------------End: proguard configuration for Gson  ----------

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

Luego edite el build.gradlearchivo (dentro de /project/platforms/androido cree un complemento de Cordova que lo agregue al archivo de compilación automáticamente):

android {
    ...

    buildTypes {
        debug {
            minifyEnabled true
            useProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }

    ...
}

Como paso final, cree su apk en modo de lanzamiento usando cordova build android --releasey estará listo para comenzar.

ProGuard reduce su código para hacerlo un poco más difícil de leer (minimizado), lo que podría ralentizar el proceso de ingeniería inversa. Aunque ProGuard no oculta las constantes de cadena, está más especializado en el hermano de código cerrado para Android, DexGuard, y proporciona técnicas de protección de aplicaciones adicionales, como el cifrado de cadenas y el cifrado de clases.

Si conoces a un desarrollador de Cordova, que probablemente no conozca este problema, comparte este artículo. 

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores