EncryptedSharedPreferences: چیست، API و نحوه استفاده

نویسنده: IT Sectr منتشر شده: 2026-03-14 زمان مطالعه: 10 دقیقه

EncryptedSharedPreferences — مؤلفه‌ای از کتابخانه AndroidX Security است که رمزنگاری شفاف داده‌های ذخیره شده از طریق API SharedPreferences را فراهم می‌کند. برخلاف SharedPreferences معمولی که داده‌ها در یک فایل XML باز ذخیره می‌شوند، EncryptedSharedPreferences به طور خودکار کلیدها و مقادیر را قبل از نوشتن روی دیسک رمزنگاری می‌کند. طبق Android Developers، کتابخانه از AES-256 GCM برای مقادیر و AES-256 SIV (RFC 5297) برای کلیدها استفاده می‌کند و محرمانگی و یکپارچگی داده‌ها را تضمین می‌کند.

خلاصه

  • EncryptedSharedPreferences — پوششی بر روی SharedPreferences با رمزنگاری خودکار تمام داده‌های ذخیره شده
  • رمزنگاری از AES-256 GCM برای مقادیر و AES-256 SIV برای کلیدها از طریق Android Keystore استفاده می‌کند
  • رمزنگاری تأیید شده (AEAD) تضمین می‌کند که داده‌ها پس از نوشتن تغییر نکرده‌اند
  • کلید اصلی در Android Keystore ذخیره می‌شود و در دستگاه‌های دارای TEE به صورت سخت‌افزاری محافظت می‌شود
  • API کاملاً با SharedPreferences سازگار است — جایگزینی بدون تغییر کد خواندن و نوشتن انجام می‌شود

EncryptedSharedPreferences چیست؟

EncryptedSharedPreferences — کلاسی از بسته androidx.security.crypto است که در AndroidX Security 1.0.0 (2019) معرفی شد. این کلاس رابط SharedPreferences را پیاده‌سازی می‌کند، اما تمام عملیات نوشتن (putString, putInt, putBoolean و غیره) داده‌ها را از قبل رمزنگاری می‌کنند و عملیات خواندن قبل از بازگرداندن آن‌ها را رمزگشایی می‌کنند.

مشکل SharedPreferences معمولی

SharedPreferences استاندارد داده‌ها را در یک فایل XML در دایرکتوری برنامه ذخیره می‌کند (/data/data/package/shared_prefs/). فایل رمزنگاری نشده است — با دسترسی root به دستگاه یا تحلیل پشتیبان، تمام داده‌ها به صورت XML ساده قابل خواندن هستند. توکن‌های احراز هویت، کلیدهای API، اطلاعات شخصی کاربر برای مهاجم قابل دسترس می‌شود.

EncryptedSharedPreferences این مشکل را در سطح کتابخانه حل می‌کند: داده‌ها قبل از نوشتن روی دیسک رمزنگاری می‌شوند و هنگام خواندن رمزگشایی می‌شوند. توسعه‌دهنده نیازی به فراخوانی دستی توابع رمزنگاری ندارد — API مشابه SharedPreferences معمولی باقی می‌ماند.

تاریخچه و نسخه‌ها

کتابخانه AndroidX Security v1.0.0 در دسامبر 2019 منتشر شد. EncryptedSharedPreferences جایگزین رویکرد قدیمی با رمزنگاری دستی از طریق Cipher + SharedPreferences شد. نسخه پایدار فعلی 1.1.0-alpha06 (2024) است که از API 19+ پشتیبانی می‌کند. کتابخانه بخشی از Jetpack است و به مجوزهای اضافی نیاز ندارد.

به گفته Google Security Blog (2024)، EncryptedSharedPreferences روش توصیه شده برای ذخیره تنظیمات محرمانه برنامه است که نیازی به همگام‌سازی از طریق ابر ندارند. برای سناریوهای پیچیده‌تر، Room با رمزنگاری از طریق SQLCipher پیشنهاد می‌شود.

EncryptedSharedPreferences چگونه کار می‌کند؟

EncryptedSharedPreferences از طرح رمزنگاری دو سطحی استفاده می‌کند: کلید اصلی (Master Key) در Android Keystore ذخیره می‌شود و برای رمزنگاری داده‌ها از کلیدهای مشتق شده استفاده می‌شود. این ترکیبی از حفاظت Keystore و کارایی رمزنگاری متقارن است.

طرح رمزنگاری: AES-256 GCM + SIV

برای مقادیر از AES-256 GCM (Galois/Counter Mode) استفاده می‌شود — حالت رمزنگاری تأیید شده (AEAD) که محرمانگی و یکپارچگی داده‌ها را تضمین می‌کند. برای کلیدها (نام پارامترها) AES-256 SIV (RFC 5297) اعمال می‌شود — رمزنگاری قطعی که برای جستجو بر اساس کلید بدون افشای محتوای آن ضروری است.

هر فایل EncryptedSharedPreferences شامل جفت‌های کلید-مقدار رمزنگاری شده است. ساختار فایل: ابتدا هدر با فراداده (نسخه، شناسه کلید)، سپس لیستی از ورودی‌های رمزنگاری شده. فایل XML معتبر نیست و با ویرایشگرهای متن قابل خواندن نیست.

MasterKey و KeyStore

کلاس MasterKey مسئول ایجاد و مدیریت کلید اصلی 256 بیتی است که در Android Keystore ذخیره می‌شود. MasterKey.Builder امکان پیکربندی: نوع ذخیره‌سازی (Keystore یا نرم‌افزاری)، حفاظت با بیومتریک، عمر کلید را فراهم می‌کند. به طور پیش‌فرض، کلید اصلی در Android Keystore با الگوریتم AES/GCM/NoPadding تولید می‌شود.

kotlin
import androidx.security.crypto.MasterKey
import androidx.security.crypto.EncryptedSharedPreferences

fun getEncryptedPrefs() {
    val masterKey = MasterKey.Builder(context)
        .setKeyScheme(MasterKey.AES256_GCM_SPEC)
        .build()

    val prefs = EncryptedSharedPreferences.create(
        context,
        "secure_prefs",
        masterKey,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
}

پیکربندی رمزنگاری

EncryptedSharedPreferences.create پنج پارامتر دریافت می‌کند: زمینه، نام فایل، کلید اصلی، طرح رمزنگاری کلیدها و طرح رمزنگاری مقادیر. انتخاب طرح‌ها بر عملکرد و سطح حفاظت تأثیر می‌گذارد.

طرح‌های رمزنگاری کلیدها

AES256_SIV — رمزنگاری قطعی: کلیدهای مشابه همیشه متن رمزنگاری شده مشابهی تولید می‌کنند. این برای جستجو بر اساس کلید (SharedPreferences.getX(key)) ضروری است. عیب: مهاجم می‌تواند تشخیص دهد کدام کلیدها با تکرار متن‌های رمزی استفاده می‌شوند. AES256_SIV2 — نسخه بهبود یافته با تصادفی‌سازی اضافی.

برای مقادیر از AES256_GCM استفاده می‌شود. GCM یک IV 12 بایتی (بردار اولیه) و یک برچسب تأیید 16 بایتی به هر مقدار اضافه می‌کند. این محرمانگی (هیچ‌کس نمی‌تواند مقدار را بخواند) و تأیید (هیچ‌کس نمی‌تواند مقدار را بدون شناسایی تغییر دهد) را تضمین می‌کند.

حفاظت بیومتریک کلید اصلی

روش setUserAuthenticationRequired(true) در MasterKey.Builder قبل از دریافت کلید اصلی از Keystore تأیید بیومتریک را الزامی می‌کند. این یک لایه اضافی اضافه می‌کند: حتی اگر برنامه روی دستگاه باز شده اجرا شود، مهاجم نمی‌تواند EncryptedSharedPreferences را بدون Face ID یا Touch ID بخواند.

مهم: با setUserAuthenticationRequired، کلید اصلی در صورت تغییر یا حذف بیومتریک توسط کاربر غیرقابل دسترس می‌شود. باید KeyPermanentlyInvalidatedException را مدیریت کرده و با مهاجرت داده‌ها یک کلید اصلی جدید ایجاد کنید.

kotlin
fun createBiometricKey(): MasterKey {
    return MasterKey.Builder(context)
        .setKeyScheme(MasterKey.AES256_GCM_SPEC)
        .setUserAuthenticationRequired(true)
        .setRequestStrongBoxBacked(true)
        .build()
}

fun writeSecureToken(token: String) {
    try {
        prefs.edit().putString("auth_token", token).apply()
    } catch (e: KeyPermanentlyInvalidatedException) {
        // بیومتریک تغییر کرد — باید کلید را دوباره ایجاد کنید
    }
}

مثال استفاده در کاتلین

بیایید یک مثال کامل از ادغام EncryptedSharedPreferences در یک برنامه اندروید با کاتلین را بررسی کنیم. کتابخانه androidx.security:security-crypto از طریق Gradle اضافه می‌شود.

افزودن وابستگی

در فایل build.gradle (app) اضافه کنید: implementation «androidx.security:security-crypto:1.1.0-alpha06». برای پروژه‌های کاتلین، kotlin-stdlib نیز مورد نیاز است. مقداردهی اولیه MasterKey یک بار، معمولاً در Application.onCreate یا از طریق کانتینر DI انجام می‌شود.

خواندن و نوشتن داده‌ها

پس از ایجاد نمونه EncryptedSharedPreferences، API با SharedPreferences معمولی تفاوتی ندارد. edit() یک Editor برمی‌گرداند، همه روش‌ها (putString, getString, putBoolean, getBoolean) مشابه عمل می‌کنند. تفاوت فقط در داخل است: داده‌ها هنگام نوشتن رمزنگاری و هنگام خواندن رمزگشایی می‌شوند.

kotlin
class AuthRepository(context: Context) {
    private val prefs = createEncryptedPrefs(context)

    fun saveCredentials(login: String, password: String) {
        prefs.edit()
            .putString("login", login)
            .putString("password", password)
            .apply()
    }

    fun getToken(): String? {
        return prefs.getString("auth_token", null)
    }

    fun clearAll() {
        prefs.edit().clear().apply()
    }
}

مهاجرت از SharedPreferences معمولی

برای مهاجرت داده‌های موجود از SharedPreferences محافظت نشده به EncryptedSharedPreferences باید: تمام داده‌ها را از فایل قدیمی بخوانید، یک EncryptedSharedPreferences جدید ایجاد کنید، تمام داده‌ها را بنویسید، فایل قدیمی را حذف کنید. گوگل ابزار مهاجرت داخلی ارائه نمی‌دهد — توسعه‌دهنده آن را خودش پیاده‌سازی می‌کند.

مقایسه با SharedPreferences معمولی

انتخاب بین SharedPreferences و EncryptedSharedPreferences به نوع داده‌های ذخیره شده بستگی دارد. برای تنظیمات رابط کاربری (پوسته، زبان، مرتب‌سازی) SharedPreferences معمولی کافی است. برای اطلاعات محرمانه (توکن‌ها، رمزهای عبور، کلیدها) EncryptedSharedPreferences الزامی است.

عملکرد

EncryptedSharedPreferences به دلیل عملیات رمزنگاری کندتر از نوع معمولی است. نوشتن یک مقدار رشته‌ای حدود 5-15 میلی‌ثانیه طول می‌کشد (بسته به اندازه داده و شتاب سخت‌افزاری AES). خواندن — 2-5 میلی‌ثانیه. برای اکثر برنامه‌ها این قابل توجه نیست، اما در عملیات دسته‌ای (مهاجرت، بازیابی) بهتر است به جای commit() از apply() استفاده کنید.

امنیت

SharedPreferences معمولی هیچ حفاظت رمزنگاری ارائه نمی‌دهد: فایل XML توسط هر فرآیندی با دسترسی root یا از طریق adb backup قابل خواندن است. EncryptedSharedPreferences داده‌ها را در سطح برنامه رمزنگاری می‌کند و کلید اصلی در Android Keystore با امکان حفاظت سخت‌افزاری (StrongBox) ذخیره می‌شود.

ویژگیSharedPreferencesEncryptedSharedPreferences
ذخیره‌سازیXML بازفایل باینری رمزنگاری شده
رمزنگارینداردAES-256 GCM + SIV
حفاظت کلیدهانداردAndroid Keystore + StrongBox
عملکرد0.1-1 میلی‌ثانیه2-15 میلی‌ثانیه
توصیهتنظیمات UIتوکن‌ها، کلیدها، PII

چه زمانی EncryptedSharedPreferences را انتخاب کنیم

از EncryptedSharedPreferences برای ذخیره استفاده کنید: توکن بازخوانی OAuth، کلیدهای API برای سرویس‌های خارجی، ایمیل یا شماره تلفن کاربر، تنظیمات محرمانه برنامه (PIN، پرچم‌های احراز هویت). برای ذخیره داده‌های بیومتریک یا اسناد بزرگ، EncryptedSharedPreferences مناسب نیست — از EncryptedFile یا Room با SQLCipher استفاده کنید.

قاعده کلی: اگر نشت داده به کاربر یا کسب‌وکار آسیب می‌رساند — از EncryptedSharedPreferences استفاده کنید. اگر داده‌ها فقط آرایشی هستند (پوسته، زبان، مرتب‌سازی) — SharedPreferences معمولی. پیاده‌سازی EncryptedSharedPreferences از همان ابتدا منطقی است، بدون بازسازی: جایگزینی در پروژه موجود نیاز به مهاجرت و پردازش داده‌های قدیمی رمزنگاری نشده دارد.

به یاد داشته باشید که EncryptedSharedPreferences داده‌ها را فقط روی دیسک محافظت می‌کند — نه در حین کار برنامه. اگر مهاجم به حافظه فرآیند دسترسی داشته باشد، داده‌های رمزگشایی شده ممکن است رهگیری شوند. از حفاظت اضافی استفاده کنید: ProGuard/DexGuard برای مبهم‌سازی کد.

سوالات متداول

EncryptedSharedPreferences چه تفاوتی با DataStore دارد؟

Jetpack DataStore — جایگزین مدرن‌تری برای SharedPreferences است که بر اساس Flow و کوروتین‌های کاتلین ساخته شده است. DataStore به طور پیش‌فرض داده‌ها را رمزنگاری نمی‌کند، اما می‌تواند با EncryptedSharedPreferences ترکیب شود یا با رمزنگاری دستی از طریق Proto DataStore با پروتکل‌های رمزنگاری استفاده شود.

آیا می‌توان از EncryptedSharedPreferences برای حجم‌های زیاد داده استفاده کرد؟

توصیه نمی‌شود. EncryptedSharedPreferences برای حجم‌های کم (تا 100-200 کیلوبایت) طراحی شده است. برای داده‌های بزرگ از Room با SQLCipher یا رمزنگاری فایل از طریق EncryptedFile از همان کتابخانه AndroidX Security استفاده کنید.

آیا EncryptedSharedPreferences از مهاجرت هنگام به‌روزرسانی طرح پشتیبانی می‌کند؟

خیر، مهاجرت خودکار طرح وجود ندارد. هنگام تغییر ساختار داده، توسعه‌دهنده باید داده‌های قدیمی را از طریق KeyGen قدیمی به صورت دستی بخواند و از طریق جدید بنویسد. توصیه می‌شود نسخه طرح را در یک پارامتر جداگانه ذخیره کنید.

حداقل سطح API مورد نیاز چیست؟

AndroidX Security 1.0.0 از API 19+ (Android KitKat) پشتیبانی می‌کند. نسخه 1.1.0-alpha06 نیز از API 19+ پشتیبانی می‌کند. برای StrongBox به API 28+ و دستگاه با پشتیبانی سخت‌افزاری نیاز است (Google Pixel 3+, Samsung Galaxy S9+).

آیا ذخیره توکن بازخوانی در EncryptedSharedPreferences امن است؟

بله، توکن بازخوانی — یکی از سناریوهای اصلی استفاده است. رمزنگاری AES-256 GCM، کلید اصلی در Keystore، حفاظت بیومتریک — سطح کافی برای توکن‌های OAuth. برای توکن دسترسی با عمر کوتاه نیز مناسب است، اگرچه برخی تیم‌ها ترجیح می‌دهند آن را در حافظه ذخیره کنند.

نتیجه‌گیری

  • EncryptedSharedPreferences — پوشش SharedPreferences با رمزنگاری خودکار از طریق AES-256 GCM (مقادیر) و SIV (کلیدها)
  • کلید اصلی از طریق MasterKey.Builder ایجاد می‌شود و در Android Keystore با گزینه‌های بیومتریک و StrongBox ذخیره می‌شود
  • API کاملاً سازگار: edit, putString, getString, apply, clear — همه مانند SharedPreferences معمولی
  • عملکرد: 2-15 میلی‌ثانیه بر هر عملیات، که در سناریوهای استاندارد برای کاربر قابل توجه نیست
  • امنیت: رمزنگاری تأیید شده (AEAD) از خواندن و تغییر داده‌ها جلوگیری می‌کند
  • مهاجرت از SharedPreferences معمولی نیاز به انتقال دستی داده‌ها از طریق فایل‌های قدیمی و جدید دارد
  • از EncryptedSharedPreferences برای توکن‌ها، کلیدهای API، رمزهای عبور و سایر تنظیمات محرمانه استفاده کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید