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

Потенциально чувствительная информация, найденная энтропийным анализом

Критичность: НИЗКИЙ

Описание

Платформа Стингрей осуществляет поиск чувствительной информации в большом количестве источников:

  • файлы приложения;
  • базы данных (частный случай файлов приложения);
  • системный журнал;
  • сетевая активность;
  • межпроцессное взаимодействие;
  • Deeplink и Applink, как частный случай межпроцессного взаимодействия;
  • код и ресурсы приложения;
  • и многие другие.

Информация в этих источниках представлена в различных форматах, каждый из которых нужно правильно анализировать. Для обнаружения чувствительной информации Стингрей использует правила — регулярные выражения, с помощью которых осуществляется поиск как в структурированных данных (JSON, XML и т. д.), так и в произвольном тексте. Однако полностью охватить все разнообразие возможных чувствительных данных не представляется возможным, именно поэтому появился поиск информации по энтропии. Поиск потенциально чувствительной информации осуществляется по строкам из данных соответствующих модулей и основан на вычислении энтропии Шеннона (также известной как информационная энтропия) для каждого фрагмента текста длиной более десяти или опционально любого другого количества символов. Другими словами, система ищет все строки и данные, которые имеют высокую энтропию и потенциально могут являться чувствительной информацией (различные токены или сессионные идентификаторы). Безусловно, многие срабатывания могут быть нерелевантны, но мы придерживаемся правила, что лучше показать информацию, чем потенциально пропустить дефект.

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

Рекомендуется дополнительно проверить найденную информацию на предмет конфиденциальности и допустимости ее хранения на устройстве в открытом виде.

Рассмотрим хранение чувствительной информации с использованием шифрования на примере библиотеки CryptoSwift.

import CryptoSwift

extension String {

    func aesEncrypt(key: String, iv: String) throws -> String {
        let data = self.data(using: .utf8)!
        let encrypted = try! AES(key: key, iv: iv, padding: .pkcs7).encrypt([UInt8](data))
        let encryptedData = Data(encrypted)
        return encryptedData.toHexString()
    }

    func aesDecrypt(key: String, iv: String) throws -> String {
        let data = self.dataFromHexadecimalString()!
        let decrypted = try! AES(key: key, iv: iv, padding:.pkcs7).decrypt([UInt8](data))
        let decryptedData = Data(decrypted)
        return String(bytes: decryptedData.bytes, encoding: .utf8) ?? "Could not decrypt"
    }

    func dataFromHexadecimalString() -> Data? {
        var data = Data(capacity: count / 2)
        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
        regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, count)) { match, flags, stop in
            let byteString = (self as NSString).substring(with: match!.range)
            let num = UInt8(byteString, radix: 16)
            data.append(num!)
        }
            return data
    }

}

extension Data {

    var bytes: Array<UInt8> {
        return Array(self)
    }

    func toHexString() -> String {
        return bytes.toHexString()
    }

}

Основной сложностью в данном случае будет генерация ключа и его безопасное хранение, но как идея — можно генерировать ключ на основе алгоритма PBKDF2 «на лету» и вообще не хранить его локально.

Ссылки

  1. https://betterprogramming.pub/encrypting-common-scenarios-in-swift-34168034190c
  2. https://developer.apple.com/documentation/applearchive/encrypting_and_decrypting_a_string
К началу