Перейти к содержанию

Слабый пароль шифрования базы данных

Критичность: СРЕДНИЙ
Способ обнаружения: DAST, API

Описание

Пароль, который используется для шифрования базы данных, не удовлетворяет критериям по длине, простоте или частоте использования. Основным параметром надежности хранения данных в зашифрованной базе данных на устройстве является пароль, который применяется для шифрования. Если выбранный пароль слишком простой или присутствует в базе самых распространенных паролей, велика вероятность подбора пароля и компрометации информации.

Рекомендации

При применении пароля для шифрования БД, встает вопрос о его безопасном хранении. Существует несколько вариантов, когда при успешной аутентификации в приложении серверная часть присылает секрет на основе которого формируется пароль, используемый для открытия или шифрования базы данных.

Другим вариантом может быть формирование ключа шифрования (который может быть использован как пароль от базы) на основе пароля пользователя. В этом случае нет необходимости в хранении ключа шифрования, так как он генерируется “на лету“ с использованием пароля, который ввел пользователь:

Правила:

  1. Явно определяйте режим шифрования и дополнения блоков.

  2. Используйте криптостойкие технологии шифрования, включающие алгоритм, режим блочного шифрования и режим дополнения блоков.

  3. В процессе генерации ключа на основе пароля используйте «соль» (salt).

  4. В процессе генерации ключа на основе пароля используйте достаточное количество итераций хеширования.

  5. Используйте ключ с длиной, которая обеспечит криптостойкость шифрования.

    package com.appsec.android.cryptsymmetricpasswordbasedkey;
    
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.spec.InvalidKeySpecException;
    import java.util.Arrays;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    
    public final class AesCryptoPBEKey {
    
        // *** 1 *** Явно определяйте режим шифрования и дополнения блоков.
        // *** 2 *** Используйте криптостойкие технологии шифрования, включающие алгоритм, режим блочного шифрования и режим дополнения блоков
        // Параметры передаваемые в метод getInstance класса Cipher: алгоритм шифрования, режим блочного шифрования, режим дополнения блоков
        // в этом примере следующие значения: алгоритм шифрования=AES, режим блочного шифрования=CBC, режим дополнения блоков=PKCS7Padding
        private static final String TRANSFORMATION = "AES/CBC/PKCS7Padding";
    
        // Строка, используемая для получения экземпляра класса, который будет генерировать ключ
        private static final String KEY_GENERATOR_MODE = "PBEWITHSHA256AND128BITAES-CBC-BC";
    
        // *** 3 *** В процессе генерации ключа на основе пароля используйте "соль" (salt)
        // Длина строки "соли" в байтах
        public static final int SALT_LENGTH_BYTES = 20;
    
        // *** 4 *** В процессе генерации ключа на основе пароля используйте достаточное количество итераций хеширования
        // Указание числа повторений смешиваний, используемых при генерации ключей с помощью PBE
        private static final int KEY_GEN_ITERATION_COUNT = 1024;
    
        // *** 5 *** Используйте ключ с длиной, которая обеспечит криптостойкость шифрования
        // Длина ключа в битах
        private static final int KEY_LENGTH_BITS = 128;
    
        private byte[] mSalt = null;
    
        public byte[] getSalt() {
            return mSalt;
        }
    
        private void initSalt() {
            mSalt = new byte[SALT_LENGTH_BYTES];
            SecureRandom sr = new SecureRandom();
            sr.nextBytes(mSalt);
        }
    
        private static final SecretKey generateKey(final char[] password, final byte[] salt) {
            SecretKey secretKey = null;
            PBEKeySpec keySpec = null;
    
            try {
                // *** 2 *** Используйте криптостойкие технологии шифрования, включающие алгоритм, режим блочного шифрования и режим дополнения блоков
                // Получение экземпляра класса для генерации ключа
                // В этом примере используется класс KeyFactory, который применяет алгоритм SHA256 для генерации AES-CBC 128-битного ключа
                SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);
    
                // *** 3 *** В процессе генерации ключа на основе пароля используйте "соль" (salt)
                // *** 4 *** В процессе генерации ключа на основе пароля используйте достаточное количество итераций хеширования
                // *** 5 *** Используйте ключ с длиной, которая обеспечит криптостойкость шифрования
                keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);
                // Очистка пароля - требуется для усложнения процедуры отладки и невключения пароля в дамп памяти
                Arrays.fill(password, '?');
                // Генерация ключа
                secretKey = secretKeyFactory.generateSecret(keySpec);
            } catch (NoSuchAlgorithmException e) {
            } catch (InvalidKeySpecException e) {
            } finally {
                keySpec.clearPassword();
            }
    
            return secretKey;
        }
    }
    

В дальнейшем получившееся значение ключа можно использовать в качестве пароля для шифрования базы данных и нет необходимости в его хранении.

Ссылки

  1. https://github.com/sqlcipher/android-database-sqlcipher

  2. https://github.com/OWASP/owasp-mstg/blob/master/Document/0x05d-Testing-Data-Storage.md#sqlite-databases-encrypted

  3. https://cwe.mitre.org/data/definitions/521.html

К началу