Как защитить общие настройки Android?

Общее местоположение, где SharedPreferences хранятся в приложениях Android:

 /data/data//shared_prefs/ 

Пользователь с привилегиями root может перейти к этому местоположению и может изменить его значения. Сохранение его защиты имеет большое значение.

Сколько способов мы можем зашифровать весь shared_pref's xml файл shared_pref's xml ?

Мы все знаем, что мы можем шифровать и сохранять данные в shared_pref's xml файле shared_pref's xml , но это не только на 100% безопасно, поэтому необходимо зашифровать весь файл ключом. Нужна помощь в понимании различных способов шифрования всего xml файла. Это общий вопрос, различные методы шифрования, обсуждаемые в качестве ответов здесь, могут быть полезны всем разработчикам в обеспечении безопасности приложений.

Следует отметить, что общие предпочтения Android основаны на значении ключа на основе XML. Вы не можете изменить этот факт (поскольку он нарушит его синтаксический анализатор), в лучшем случае вы можете зашифровать как ключ, так и значение, чтобы пользователь root мог читать, но не имел ни малейшего представления о том, что он читает.

Для этого вы можете использовать простое шифрование, подобное этому

 public static String encrypt(String input) { // This is base64 encoding, which is not an encryption return Base64.encodeToString(input.getBytes(), Base64.DEFAULT); } public static String decrypt(String input) { return new String(Base64.decode(input, Base64.DEFAULT)); } 

Вот как вы могли бы использовать это

 // Write SharedPreferences preferences = getSharedPreferences("some_prefs_name", MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.putString(encrypt("password"), encrypt("dummypass")); editor.apply(); // Or commit if targeting old devices // Read SharedPreferences preferences = getSharedPreferences("some_prefs_name", MODE_PRIVATE); String passEncrypted = preferences.getString(encrypt("password"), encrypt("default")); String pass = decrypt(passEncrypted); 

Вы должны знать, что SharedPreferences никогда не были созданы для обеспечения безопасности, это просто простой способ сохранить данные.

Вы также должны знать, что шифрование, которое я использовал, не является самым безопасным, но это просто.

Существует несколько библиотек, которые обеспечивают лучшее шифрование, например

Но все они приходят к тому факту, что формат файла по-прежнему является XML и основан на ключевом значении. Вы не можете изменить этот факт. Смотри ниже.

 cat /data/data/your.package.application/shared_prefs/prefs-test.xml   0AB7Y28XEvbQcnXpEZ4j9PtqzFLtm2V3KBXjTO1V704=  The key is "hemmelighet" and the value is "dette er en hemmelighet". 

Если безопасность является проблемой, выходящей за frameworks того факта, что SharedPreferences по-прежнему основаны на ключевом значении и в формате XML, вам нужно полностью избегать этого.

Вы должны зашифровать свои данные и записать в SharedPreferences. Когда вы хотите получить эти данные, вы должны расшифровать их из SharedPreferences. вам нужен следующий вспомогательный class для этого

 public class Encryption { private final Builder mBuilder; private Encryption(Builder builder) { mBuilder = builder; } public static Encryption getDefault(String key, String salt, byte[] iv) { try { return Builder.getDefaultBuilder(key, salt, iv).build(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } private String encrypt(String data) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException { if (data == null) return null; SecretKey secretKey = getSecretKey(hashTheKey(mBuilder.getKey())); byte[] dataBytes = data.getBytes(mBuilder.getCharsetName()); Cipher cipher = Cipher.getInstance(mBuilder.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, secretKey, mBuilder.getIvParameterSpec(), mBuilder.getSecureRandom()); return Base64.encodeToString(cipher.doFinal(dataBytes), mBuilder.getBase64Mode()); } public String encryptOrNull(String data) { try { return encrypt(data); } catch (Exception e) { e.printStackTrace(); return ""; } } public void encryptAsync(final String data, final Callback callback) { if (callback == null) return; new Thread(new Runnable() { @Override public void run() { try { String encrypt = encrypt(data); if (encrypt == null) { callback.onError(new Exception("Encrypt return null, it normally occurs when you send a null data")); } callback.onSuccess(encrypt); } catch (Exception e) { callback.onError(e); } } }).start(); } private String decrypt(String data) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { if (data == null) return null; byte[] dataBytes = Base64.decode(data, mBuilder.getBase64Mode()); SecretKey secretKey = getSecretKey(hashTheKey(mBuilder.getKey())); Cipher cipher = Cipher.getInstance(mBuilder.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey, mBuilder.getIvParameterSpec(), mBuilder.getSecureRandom()); byte[] dataBytesDecrypted = (cipher.doFinal(dataBytes)); return new String(dataBytesDecrypted); } public String decryptOrNull(String data) { try { return decrypt(data); } catch (Exception e) { e.printStackTrace(); return null; } } public void decryptAsync(final String data, final Callback callback) { if (callback == null) return; new Thread(new Runnable() { @Override public void run() { try { String decrypt = decrypt(data); if (decrypt == null) { callback.onError(new Exception("Decrypt return null, it normally occurs when you send a null data")); } callback.onSuccess(decrypt); } catch (Exception e) { callback.onError(e); } } }).start(); } private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance(mBuilder.getSecretKeyType()); KeySpec spec = new PBEKeySpec(key, mBuilder.getSalt().getBytes(mBuilder.getCharsetName()), mBuilder.getIterationCount(), mBuilder.getKeyLength()); SecretKey tmp = factory.generateSecret(spec); return new SecretKeySpec(tmp.getEncoded(), mBuilder.getKeyAlgorithm()); } private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException { MessageDigest messageDigest = MessageDigest.getInstance(mBuilder.getDigestAlgorithm()); messageDigest.update(key.getBytes(mBuilder.getCharsetName())); return Base64.encodeToString(messageDigest.digest(), Base64.NO_PADDING).toCharArray(); } public interface Callback { void onSuccess(String result); void onError(Exception exception); } private static class Builder { private byte[] mIv; private int mKeyLength; private int mBase64Mode; private int mIterationCount; private String mSalt; private String mKey; private String mAlgorithm; private String mKeyAlgorithm; private String mCharsetName; private String mSecretKeyType; private String mDigestAlgorithm; private String mSecureRandomAlgorithm; private SecureRandom mSecureRandom; private IvParameterSpec mIvParameterSpec; public static Builder getDefaultBuilder(String key, String salt, byte[] iv) { return new Builder() .setIv(iv) .setKey(key) .setSalt(salt) .setKeyLength(128) .setKeyAlgorithm("AES") .setCharsetName("UTF8") .setIterationCount(1) .setDigestAlgorithm("SHA1") .setBase64Mode(Base64.DEFAULT) .setAlgorithm("AES/CBC/PKCS5Padding") .setSecureRandomAlgorithm("SHA1PRNG") .setSecretKeyType("PBKDF2WithHmacSHA1"); } private Encryption build() throws NoSuchAlgorithmException { setSecureRandom(SecureRandom.getInstance(getSecureRandomAlgorithm())); setIvParameterSpec(new IvParameterSpec(getIv())); return new Encryption(this); } private String getCharsetName() { return mCharsetName; } private Builder setCharsetName(String charsetName) { mCharsetName = charsetName; return this; } private String getAlgorithm() { return mAlgorithm; } private Builder setAlgorithm(String algorithm) { mAlgorithm = algorithm; return this; } private String getKeyAlgorithm() { return mKeyAlgorithm; } private Builder setKeyAlgorithm(String keyAlgorithm) { mKeyAlgorithm = keyAlgorithm; return this; } private int getBase64Mode() { return mBase64Mode; } private Builder setBase64Mode(int base64Mode) { mBase64Mode = base64Mode; return this; } private String getSecretKeyType() { return mSecretKeyType; } private Builder setSecretKeyType(String secretKeyType) { mSecretKeyType = secretKeyType; return this; } private String getSalt() { return mSalt; } private Builder setSalt(String salt) { mSalt = salt; return this; } private String getKey() { return mKey; } private Builder setKey(String key) { mKey = key; return this; } private int getKeyLength() { return mKeyLength; } public Builder setKeyLength(int keyLength) { mKeyLength = keyLength; return this; } private int getIterationCount() { return mIterationCount; } public Builder setIterationCount(int iterationCount) { mIterationCount = iterationCount; return this; } private String getSecureRandomAlgorithm() { return mSecureRandomAlgorithm; } public Builder setSecureRandomAlgorithm(String secureRandomAlgorithm) { mSecureRandomAlgorithm = secureRandomAlgorithm; return this; } private byte[] getIv() { return mIv; } public Builder setIv(byte[] iv) { mIv = iv; return this; } private SecureRandom getSecureRandom() { return mSecureRandom; } public Builder setSecureRandom(SecureRandom secureRandom) { mSecureRandom = secureRandom; return this; } private IvParameterSpec getIvParameterSpec() { return mIvParameterSpec; } public Builder setIvParameterSpec(IvParameterSpec ivParameterSpec) { mIvParameterSpec = ivParameterSpec; return this; } private String getDigestAlgorithm() { return mDigestAlgorithm; } public Builder setDigestAlgorithm(String digestAlgorithm) { mDigestAlgorithm = digestAlgorithm; return this; } }} - public class Encryption { private final Builder mBuilder; private Encryption(Builder builder) { mBuilder = builder; } public static Encryption getDefault(String key, String salt, byte[] iv) { try { return Builder.getDefaultBuilder(key, salt, iv).build(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } private String encrypt(String data) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException { if (data == null) return null; SecretKey secretKey = getSecretKey(hashTheKey(mBuilder.getKey())); byte[] dataBytes = data.getBytes(mBuilder.getCharsetName()); Cipher cipher = Cipher.getInstance(mBuilder.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, secretKey, mBuilder.getIvParameterSpec(), mBuilder.getSecureRandom()); return Base64.encodeToString(cipher.doFinal(dataBytes), mBuilder.getBase64Mode()); } public String encryptOrNull(String data) { try { return encrypt(data); } catch (Exception e) { e.printStackTrace(); return ""; } } public void encryptAsync(final String data, final Callback callback) { if (callback == null) return; new Thread(new Runnable() { @Override public void run() { try { String encrypt = encrypt(data); if (encrypt == null) { callback.onError(new Exception("Encrypt return null, it normally occurs when you send a null data")); } callback.onSuccess(encrypt); } catch (Exception e) { callback.onError(e); } } }).start(); } private String decrypt(String data) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { if (data == null) return null; byte[] dataBytes = Base64.decode(data, mBuilder.getBase64Mode()); SecretKey secretKey = getSecretKey(hashTheKey(mBuilder.getKey())); Cipher cipher = Cipher.getInstance(mBuilder.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey, mBuilder.getIvParameterSpec(), mBuilder.getSecureRandom()); byte[] dataBytesDecrypted = (cipher.doFinal(dataBytes)); return new String(dataBytesDecrypted); } public String decryptOrNull(String data) { try { return decrypt(data); } catch (Exception e) { e.printStackTrace(); return null; } } public void decryptAsync(final String data, final Callback callback) { if (callback == null) return; new Thread(new Runnable() { @Override public void run() { try { String decrypt = decrypt(data); if (decrypt == null) { callback.onError(new Exception("Decrypt return null, it normally occurs when you send a null data")); } callback.onSuccess(decrypt); } catch (Exception e) { callback.onError(e); } } }).start(); } private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance(mBuilder.getSecretKeyType()); KeySpec spec = new PBEKeySpec(key, mBuilder.getSalt().getBytes(mBuilder.getCharsetName()), mBuilder.getIterationCount(), mBuilder.getKeyLength()); SecretKey tmp = factory.generateSecret(spec); return new SecretKeySpec(tmp.getEncoded(), mBuilder.getKeyAlgorithm()); } private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException { MessageDigest messageDigest = MessageDigest.getInstance(mBuilder.getDigestAlgorithm()); messageDigest.update(key.getBytes(mBuilder.getCharsetName())); return Base64.encodeToString(messageDigest.digest(), Base64.NO_PADDING).toCharArray(); } public interface Callback { void onSuccess(String result); void onError(Exception exception); } private static class Builder { private byte[] mIv; private int mKeyLength; private int mBase64Mode; private int mIterationCount; private String mSalt; private String mKey; private String mAlgorithm; private String mKeyAlgorithm; private String mCharsetName; private String mSecretKeyType; private String mDigestAlgorithm; private String mSecureRandomAlgorithm; private SecureRandom mSecureRandom; private IvParameterSpec mIvParameterSpec; public static Builder getDefaultBuilder(String key, String salt, byte[] iv) { return new Builder() .setIv(iv) .setKey(key) .setSalt(salt) .setKeyLength(128) .setKeyAlgorithm("AES") .setCharsetName("UTF8") .setIterationCount(1) .setDigestAlgorithm("SHA1") .setBase64Mode(Base64.DEFAULT) .setAlgorithm("AES/CBC/PKCS5Padding") .setSecureRandomAlgorithm("SHA1PRNG") .setSecretKeyType("PBKDF2WithHmacSHA1"); } private Encryption build() throws NoSuchAlgorithmException { setSecureRandom(SecureRandom.getInstance(getSecureRandomAlgorithm())); setIvParameterSpec(new IvParameterSpec(getIv())); return new Encryption(this); } private String getCharsetName() { return mCharsetName; } private Builder setCharsetName(String charsetName) { mCharsetName = charsetName; return this; } private String getAlgorithm() { return mAlgorithm; } private Builder setAlgorithm(String algorithm) { mAlgorithm = algorithm; return this; } private String getKeyAlgorithm() { return mKeyAlgorithm; } private Builder setKeyAlgorithm(String keyAlgorithm) { mKeyAlgorithm = keyAlgorithm; return this; } private int getBase64Mode() { return mBase64Mode; } private Builder setBase64Mode(int base64Mode) { mBase64Mode = base64Mode; return this; } private String getSecretKeyType() { return mSecretKeyType; } private Builder setSecretKeyType(String secretKeyType) { mSecretKeyType = secretKeyType; return this; } private String getSalt() { return mSalt; } private Builder setSalt(String salt) { mSalt = salt; return this; } private String getKey() { return mKey; } private Builder setKey(String key) { mKey = key; return this; } private int getKeyLength() { return mKeyLength; } public Builder setKeyLength(int keyLength) { mKeyLength = keyLength; return this; } private int getIterationCount() { return mIterationCount; } public Builder setIterationCount(int iterationCount) { mIterationCount = iterationCount; return this; } private String getSecureRandomAlgorithm() { return mSecureRandomAlgorithm; } public Builder setSecureRandomAlgorithm(String secureRandomAlgorithm) { mSecureRandomAlgorithm = secureRandomAlgorithm; return this; } private byte[] getIv() { return mIv; } public Builder setIv(byte[] iv) { mIv = iv; return this; } private SecureRandom getSecureRandom() { return mSecureRandom; } public Builder setSecureRandom(SecureRandom secureRandom) { mSecureRandom = secureRandom; return this; } private IvParameterSpec getIvParameterSpec() { return mIvParameterSpec; } public Builder setIvParameterSpec(IvParameterSpec ivParameterSpec) { mIvParameterSpec = ivParameterSpec; return this; } private String getDigestAlgorithm() { return mDigestAlgorithm; } public Builder setDigestAlgorithm(String digestAlgorithm) { mDigestAlgorithm = digestAlgorithm; return this; } }} 

то вы можете писать в SharedPreferences путем шифрования ваших данных следующим образом

  Encryption encryption = Encryption.getDefault("Key", "Salt", new byte[16]); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences.Editor editor = preferences.edit(); editor.putString("token", encryption.encryptOrNull(userModel.getToken())); editor.apply() 

вы можете, наконец, прочитать данные SharedPreferences следующим образом. Таким образом, конфиденциальная информация будет более безопасной при сохранении на аппаратном уровне телефона

 final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); Encryption encryption = Encryption.getDefault("Key", "Salt", new byte[16]); String token = encryption.decryptOrNull(preferences.getString("token","")); 
 public class NodeCrypto { private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!) private IvParameterSpec ivspec; private SecretKeySpec keyspec; private Cipher cipher; private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!) public void doKey(String key) { ivspec = new IvParameterSpec(iv.getBytes()); key = padRight(key,16); Log.d("hi",key); keyspec = new SecretKeySpec(key.getBytes(), "AES"); try { cipher = Cipher.getInstance("AES/CBC/NoPadding"); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public byte[] encrypt(String text,String key) throws Exception { if(text == null || text.length() == 0) throw new Exception("Empty string"); doKey(key); byte[] encrypted = null; try { cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); encrypted = cipher.doFinal(padString(text).getBytes()); } catch (Exception e) { throw new Exception("[encrypt] " + e.getMessage()); } return encrypted; } public byte[] decrypt(String code,String key) throws Exception { if(code == null || code.length() == 0) throw new Exception("Empty string"); byte[] decrypted = null; doKey(key); try { cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); decrypted = cipher.doFinal(hexToBytes(code)); } catch (Exception e) { throw new Exception("[decrypt] " + e.getMessage()); } return decrypted; } public static String bytesToHex(byte[] data) { if (data==null) { return null; } int len = data.length; String str = ""; for (int i=0; i 

Base64 НЕ шифрует! Не используйте его! Да, пользователи root могут получить доступ к этим данным. Одна вещь, которую вы можете сделать, это использовать AES для шифрования этих данных или использования одного файла базы данных NoSQL и шифрования этого файла. Когда приложение открывается, вы расшифровываете базу данных и используете ее для хранения информации или шифрования всех файлов независимо.

Смотрите здесь: https://code.tutsplus.com/tutorials/storing-data-securely-on-android–cms-30558

  • Как расшифровать зашифрованную строку AES-256 из CryptoJS с помощью Java?
  • Почему безопасность через неясность - плохая идея?
  • Шифрование настроек приложения в web.config
  • Шифрование файлов cookie в ASP.NET
  • Хранение данных кредитной карты
  • Interesting Posts

    «Разрешить этому устройству разбудить компьютер» отключено

    как экспортировать html-данные в pdf в angularjs

    Существуют ли какие-либо инструменты для периодической проверки наличия веб-сайта?

    вопрос с “@id” против “@ + id” в позиционировании в Relative Layout

    Значимые миниатюры для видео с использованием FFmpeg

    Как различать несколько устройств ввода в C #

    Открыть файл Excel для чтения с помощью VBA без отображения

    Обнаружение страницы, удаляющей пользователя с помощью ретранслятора

    MVC 4 как правильно передать данные из controllerа для просмотра

    Предупреждать, когда не вызывается

    Рисование прозрачной кнопки

    Кнопка отключения jQuery (НЕ ПОДКЛЮЧИТЬ), пока поле не проверит + плагин Validation

    Как выполнить функтор или lambda в заданном streamе в Qt, GCD-стиле?

    Закрепить JSF для обновления страницы / просмотра / формы при открытии через ссылку или кнопку возврата

    Как реализовать свойство только для чтения

    Давайте будем гением компьютера.