像“SERVER_URL”这样的属性应该存在于基于gradle的Android项目中?

时间:2015-09-08 10:36:12

标签: android android-gradle

在Gradle Android项目中,我应该在哪里定义SERVER_URL等常量或一些静态密码?显然,我会在代码中使用它。

  1. build.gradle文件中作为构建配置字段
  2. gradle.properties文件中(我不知道如何通过代码获取这些属性)
  3. 位于props文件夹
  4. 中的另一个res文件

    每种情况下的安全性如何?

    感谢。

2 个答案:

答案 0 :(得分:1)

您的问题有两种方法。

  

1>在您的应用程序中存储静态URL

有人可以看到URL并不重要(他们可以通过嗅探网络得到这个)。您可能希望确保请求来自可信客户端。您也可以在请求中维护一些密钥。

  

2 - ;在您的应用程序中存储密码

我找到了一个很好的解决方案,可以通过加密将其存储在 SharedPreferences 中。复制/粘贴下面的代码以创建加密的SharedPreferences。

只需将您自己的SharedPreferences对象包装在此对象中,您读/写的任何数据都将自动加密和解密。例如

final SharedPreferences prefs = new ObscuredSharedPreferences( 
this, this.getSharedPreferences(YOUR_PREFS_FILE_NAME, Context.MODE_PRIVATE) );

// eg.    
prefs.edit().putString("test","test").commit();
prefs.getString("test", null);

班级代码,

/**
 * Warning, this gives a false sense of security.  If an attacker has enough access to
 * acquire your password store, then he almost certainly has enough access to acquire your
 * source binary and figure out your encryption key.  However, it will prevent casual
 * investigators from acquiring passwords, and thereby may prevent undesired negative
 * publicity.
 */
public class ObscuredSharedPreferences implements SharedPreferences {
    protected static final String UTF8 = "utf-8";
    private static final char[] SEKRIT = ... ; // INSERT A RANDOM PASSWORD HERE.
                                               // Don't use anything you wouldn't want to
                                               // get out there if someone decompiled
                                               // your app.


    protected SharedPreferences delegate;
    protected Context context;

    public ObscuredSharedPreferences(Context context, SharedPreferences delegate) {
        this.delegate = delegate;
        this.context = context;
    }

    public class Editor implements SharedPreferences.Editor {
        protected SharedPreferences.Editor delegate;

        public Editor() {
            this.delegate = ObscuredSharedPreferences.this.delegate.edit();                    
        }

        @Override
        public Editor putBoolean(String key, boolean value) {
            delegate.putString(key, encrypt(Boolean.toString(value)));
            return this;
        }

        @Override
        public Editor putFloat(String key, float value) {
            delegate.putString(key, encrypt(Float.toString(value)));
            return this;
        }

        @Override
        public Editor putInt(String key, int value) {
            delegate.putString(key, encrypt(Integer.toString(value)));
            return this;
        }

        @Override
        public Editor putLong(String key, long value) {
            delegate.putString(key, encrypt(Long.toString(value)));
            return this;
        }

        @Override
        public Editor putString(String key, String value) {
            delegate.putString(key, encrypt(value));
            return this;
        }

        @Override
        public void apply() {
            delegate.apply();
        }

        @Override
        public Editor clear() {
            delegate.clear();
            return this;
        }

        @Override
        public boolean commit() {
            return delegate.commit();
        }

        @Override
        public Editor remove(String s) {
            delegate.remove(s);
            return this;
        }
    }

    public Editor edit() {
        return new Editor();
    }


    @Override
    public Map<String, ?> getAll() {
        throw new UnsupportedOperationException(); // left as an exercise to the reader
    }

    @Override
    public boolean getBoolean(String key, boolean defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Boolean.parseBoolean(decrypt(v)) : defValue;
    }

    @Override
    public float getFloat(String key, float defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Float.parseFloat(decrypt(v)) : defValue;
    }

    @Override
    public int getInt(String key, int defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Integer.parseInt(decrypt(v)) : defValue;
    }

    @Override
    public long getLong(String key, long defValue) {
        final String v = delegate.getString(key, null);
        return v!=null ? Long.parseLong(decrypt(v)) : defValue;
    }

    @Override
    public String getString(String key, String defValue) {
        final String v = delegate.getString(key, null);
        return v != null ? decrypt(v) : defValue;
    }

    @Override
    public boolean contains(String s) {
        return delegate.contains(s);
    }

    @Override
    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }

    @Override
    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener onSharedPreferenceChangeListener) {
        delegate.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
    }




    protected String encrypt( String value ) {

        try {
            final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.System.ANDROID_ID).getBytes(UTF8), 20));
            return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);

        } catch( Exception e ) {
            throw new RuntimeException(e);
        }

    }

    protected String decrypt(String value){
        try {
            final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.System.ANDROID_ID).getBytes(UTF8), 20));
            return new String(pbeCipher.doFinal(bytes),UTF8);

        } catch( Exception e) {
            throw new RuntimeException(e);
        }
    }

}

修改

您可以使用NDK存储密码常量。要存储和检索密钥,您需要在我们的应用程序中编写以下代码。

static {
    System.loadLibrary("library-name");
}

public native String getSecretKey();

使用NDK保存在文件中以下功能

Java_com_example_exampleApp_ExampleClass_getSecretKey( JNIEnv* env,
                                              jobject thiz )
{
    return (*env)->NewStringUTF(env, "giveMeSecretKey".");
}

现在您可以轻松检索我们的密钥并使用它来加密我们的数据。

byte[] keyPassword = getSecretKey().getBytes();

答案 1 :(得分:1)

一种方法是在gradle.properties中定义每个敏感值,并确保从VCS中排除此文件。然后,您可以让Gradle将字符串资源添加到您的构建中,这些资源可以通过正常方式访问。这样做的另一个好处是,您可以为不同的产品口味使用不同的值。

// gradle.properties

MY_SECRET_PASSWORD=password



// build.gradle

buildTypes {
    debug {
        resValue "string", "my_secret_password", MY_SECRET_PASSWORD
    }
}


// MainActivity.java
String password = getString(R.string.my_secret_password);