امنیت اندروید برای توسعه دهندگان
فهرست مطالب
آخرین به روزرسانی در 29/07/2022
در این مقاله قصد داریم در رابطه با امنیت اندروید و نکات امنیتی آن صحبت کنیم.
در واقع همراه با پرداختن به پروتکل ها و ساختارهای امنیتی اندروید به شما خواهیم گفت که
چگونه می توانید با رعایت نکاتی امنیت تلفن همراه خود را در برابر بدافزارها و ویروس ها بیشتر حفظ بکنید.
امنیت اندروید
اندروید دارای ویژگی های امنیتی داخلی می باشد که باعث می شود دستگاه شما از ورود هر گونه
بد افزاری از طریق اپلیکیشن های ویروسی ایمن باشد.
ویژگی های امنیتی زیر به شما کمک می کند تا اپلیکیشن های ایمنی برای اندروید بسازید :
Android Application Sandbox که دادههای برنامه و اجرای کد شما را از سایر برنامهها جدا میکند.
فناوری هایی مانند ASLR، NX، ProPolice، safe_iop، OpenBSD dlmalloc، OpenBSD calloc و
Linux mmap_min_addr در اندروید برای کاهش خطرات مرتبط با خطاهای رایج مدیریت حافظه می باشد.
مجوزهای اعطا شده توسط کاربر برای محدود کردن دسترسی به ویژگی های سیستم و داده های کاربر.
مجوزهای تعریف شده توسط برنامه برای کنترل داده های برنامه بر اساس هر برنامه.
بسیار حائز اهمیت می باشد که موارد بالا و پروتکل های امنیتی اندروید که در ادامه به معرفی آنها خواهیم پرداخت آشنا باشید تا بتوانید از حداکثر توان امنیتی برای اپلیکیشن های ساخته شده استفاده کنید.
مهم ترین مسئله امنیتی
مهم ترین و رایج ترین نگرانی امنیتی برای یک برنامه در Android این است که آیا
داده هایی که در دستگاه ذخیره می کنید برای سایر برنامه ها قابل دسترسی است یا خیر.
سه راه اساسی برای ذخیره داده ها در دستگاه وجود دارد :
- حافظه داخلی (Internal storage)
- حافظه خارجی (External storage)
- Content providers
در ادامه مسائل امنیتی مرتبط با هر رویکرد را شرح خواهیم داد.
استفاده از حافظه داخلی
به طور پیشفرض، فایلهایی که در حافظه داخلی ذخیره می شوند فقط برای همان برنامه قابل دسترسی هستند.
اندروید این پروتکل امنیتی را تضمین می کند.
اما به طور کلی، از مودها MODE_WORLD_WRITEABLE یا MODE_WORLD_READABLE
برای فایلهای IPC خودداری کنید، زیرا این حالتها توانایی محدودیت دسترسی به دادههای برنامههای خاص را فراهم نمیکنند.
و همچنین هیچ گونه کنترلی بر فرمت داده ها ارائه نمیدهند.
اگر میخواهید دادههای خود را با سایر فرآیندهای برنامه به اشتراک بگذارید،
در عوض از یک Content providers استفاده کنید، که مجوز خواندن و نوشتن را به برنامههای دیگر ارائه میدهد و میتواند مجوزهای پویا را به صورت موردی اعطا کند.
برای ایجاد حفاظت بیشتر برای داده های حساس، می توانید فایل های لوکال را با استفاده از کتابخانه Security رمزگذاری کنید.
این معیار می تواند از یک دستگاه گم شده بدون رمزگذاری سیستم فایل محافظت کند.
استفاده از حافظه خارجی
فایلهای ایجاد شده در حافظه خارجی، مانند SD کارت ها، در تمامی بخش ها قابل خواندن و نوشتن هستند.
از آنجا که حافظه خارجی می تواند توسط کاربر حذف شود و همچنین توسط هر برنامه ای اصلاح شود،
بسیار توصیه می شود که اطلاعات حساس را با استفاده از حافظه خارجی ذخیره نکنید.
برای خواندن و نوشتن فایل ها در حافظه خارجی به روشی امن تر، از کتابخانه Security استفاده کنید که کلاس EncryptedFile را ارائه می دهد.
هنگام مدیریت داده ها از حافظه خارجی باید اعتبار سنجی ورودی را همانطور که با داده های هر منبع نامعتبر انجام می دهید انجام دهید.
قبل از بارگذاری پویا نباید فایل های اجرایی یا کلاس را در حافظه خارجی ذخیره کنید.
اگر برنامه شما فایلهای اجرایی را از حافظه خارجی بازیابی میکند، فایلها باید قبل از بارگیری پویا توسط گوگل امضا شده و از نظر رمزنگاری تأیید شوند.
استفاده از content providers
content providers مکانیزم ذخیره سازی ساختار یافته ای را ارائه می دهند که می تواند
به برنامه شخصی شما محدود شود یا برای دسترسی به سایر برنامه ها صادر شود.
اگر قصد ندارید به برنامه های دیگر دسترسی به ContentProvider خود ارائه دهید،
آنها را به عنوان android:exported=false در مانیفست برنامه علامت بزنید.
در غیر این صورت، ویژگی android:exported را روی true تنظیم کنید تا به سایر برنامهها اجازه دسترسی به دادههای ذخیرهشده را بدهید.
هنگام ایجاد یک ContentProvider که برای استفاده توسط سایر برنامه ها صادر می شود،
می توانید یک مجوز برای خواندن و نوشتن مشخص کنید، یا می توانید مجوزهای مجزایی را برای خواندن و نوشتن مشخص کنید.
اگر از یک ContentProvider برای به اشتراک گذاری داده ها فقط بین برنامه های خود استفاده می کنید،
ترجیحاً از ویژگی android:protectionLevel برای محافظت از امضای برنامه استفاده کنید.
مجوزهای امضا شده نیازی به تأیید کاربر ندارند، بنابراین تجربه کاربری بهتر و دسترسی کنترل شده تری
به دادههای ContentProvider زمانی که برنامههایی که به دادهها دسترسی دارند با همان کلید امضا میشوند، ارائه میکنند.
ContentProvider همچنین میتوانند با اعلام ویژگی android:grantUriPermissions و استفاده از
FLAG_GRANT_READ_URI_PERMISSION و FLAG_GRANT_WRITE_URI_PERMISSION در شی Intent که مؤلفه را فعال میکند،
دسترسی دقیقتری را فراهم کنند. دامنه این مجوزها را می توان با عنصر <grant-uri-permission> محدودتر کرد.
استفاده از مجوزهای دسترسی
از آنجایی که در اندروید تمامی برنامهها از یکدیگر جدا و به صورت مستقل هستند،
برنامهها باید به صراحت منابع و دادههای خود را در صورت نیاز به اشتراک بگذارند.
آنها این کار را با اعلام مجوزهای مورد نیاز خود برای قابلیتهای اضافی که توسط سندباکس اولیه ارائه نشده است، از جمله دسترسی به ویژگیهای دستگاه مانند دوربین، انجام میدهند.
درخواست مجوز
شما باید تعداد مجوزهایی را که برنامه شما درخواست می کند به حداقل برسانید.
محدود کردن دسترسی به مجوزهای حساس خطر سوء استفاده ناخواسته از آن مجوزها را کاهش میدهد.
همچنین برنامه شما را برای مهاجمان آسیبپذیرتر میکند.
به طور کلی، اگر مجوزی برای عملکرد برنامه شما لازم نیست، آن را درخواست نکنید.
اگر قابلیتی وجود دارد که برنامه نمی تواند بدون آن اجرا شود، آن را با استفاده از عنصر در فایل مانیفست اعلام کنید.
اگر بتوانید برنامه خود را به گونه ای طراحی کنید که نیازی به مجوز نداشته باشد، حتما اینکار را بکنید.
به عنوان مثال، به جای درخواست دسترسی به اطلاعات دستگاه برای ایجاد یک شناسه منحصر به فرد،
یک GUID برای برنامه خود ایجاد کنید (به بخش مربوط به مدیریت داده های کاربر مراجعه کنید).
یا به جای استفاده از حافظه خارجی (که نیاز به مجوز دارد)، داده ها را در حافظه داخلی ذخیره کنید.
علاوه بر درخواست مجوزها، برنامه شما می تواند از عنصر برای محافظت از IPC که به امنیت حساس است و در معرض سایر برنامه ها مانند ContentProvider است استفاده کند.
به طور کلی، توصیه می کنیم در صورت امکان از کنترل های دسترسی به غیر از مجوزهای تأیید شده توسط کاربر استفاده کنید زیرا مجوزها ممکن است برای کاربران گیج کننده باشد.
به عنوان مثال، استفاده از سطح حفاظت از امضا را در مجوزهای ارتباط IPC بین برنامه های کاربردی ارائه شده توسط یک توسعه دهنده در نظر بگیرید.
شبکه در اندروید
شبکه سازی در اندروید تفاوت قابل توجهی با سایر محیط های لینوکس ندارد.
نکته کلیدی اطمینان استفاده از پروتکل های مناسب برای داده های حساس است، مانند HttpsURLConnection برای ترافیک وب که پروتکلی کاملا امن است.
باید از HTTPS در هر جایی که HTTPS روی سرور پشتیبانی میشود، استفاده کنید،
زیرا دستگاههای تلفن همراه اغلب به شبکههایی متصل میشوند که ایمن نیستند، مانند نقاط اتصال Wi-Fi عمومی.
ارتباطات encrypted socket-level و رمزگذاری شده را می توان به راحتی با استفاده از کلاس SSLSocket پیاده سازی کرد.
برخی از برنامه ها از پورت های شبکه میزبان محلی برای مدیریت IPC حساس استفاده می کنند.
شما نباید از این روش استفاده کنید زیرا این رابط ها توسط سایر برنامه های موجود در دستگاه قابل دسترسی هستند.
در عوض، از مکانیزم Android IPC در جایی که امکان احراز هویت وجود دارد، مانند یک سرویس استفاده کنید.
اتصال به INADDR_ANY بدتر از استفاده از حلقه بک است زیرا در این صورت برنامه شما ممکن است از هر جایی درخواست دریافت کند.
مدیریت داده های کاربر
به طور کلی، بهترین رویکرد برای امنیت داده های کاربر، به حداقل رساندن استفاده از API هایی است
که به داده های حساس یا شخصی کاربر دسترسی دارند.
اگر به دادههای کاربر دسترسی دارید و میتوانید از ذخیره یا انتقال آن اجتناب کنید، دادهها را ذخیره یا انتقال ندهید.
در نظر بگیرید که آیا راهی وجود دارد که منطق برنامه شما می تواند با استفاده از یک فرم هش یا غیر قابل برگشت داده پیاده سازی شود.
به عنوان مثال، برنامه شما ممکن است از هش آدرس ایمیل به عنوان کلید اصلی برای جلوگیری از انتقال یا ذخیره آدرس ایمیل استفاده کند.
این امر شانس افشای ناگهانی داده ها را کاهش می دهد و همچنین احتمال تلاش مهاجمان برای سوء استفاده از برنامه شما را کاهش می دهد.
اگر برنامه شما نیاز به دسترسی به داده های حساس دارد، ارزیابی کنید که آیا باید آن را به یک سرور منتقل کنید یا می توانید عملیات را روی کلاینت اجرا کنید.
برای جلوگیری از انتقال داده های کاربر، هر کدی را با استفاده از داده های حساس روی کلاینت اجرا کنید.
استفاده از WebViwe
از آنجایی که WebView محتوای وب را مصرف میکند که میتواند شامل HTML و جاوا اسکریپت باشد،
استفاده نادرست میتواند باعث ایجاد مشکلات رایج امنیتی وب مانند cross-site-scripting (JavaScript injection) شود.
Android شامل تعدادی مکانیسم برای کاهش دامنه این مشکلات بالقوه با محدود کردن قابلیت WebView به حداقل عملکرد مورد نیاز برنامه شما است.
اگر برنامه شما مستقیماً از جاوا اسکریپت در WebView استفاده نمی کند، () setJavaScriptEnabled را فراخوانی نکنید.
برخی از کدهای نمونه از این روش استفاده می کنند، که ممکن است در برنامه مجدداً از آن استفاده کنید،
بنابراین در صورت عدم نیاز، آن فراخوانی را حذف کنید.
به طور پیش فرض، WebView جاوا اسکریپت را اجرا نمی کند، بنابراین امکان اسکریپت cross-site-scripting وجود ندارد.
از addJavaScriptInterface با دقت خاصی استفاده کنید زیرا به جاوا اسکریپت اجازه میدهد تا
عملیاتی را که معمولاً برای برنامههای Android رزرو شده است فراخوانی کند.
اگر از آن استفاده می کنید،() addJavaScriptInterface را فقط در صفحات وبی قرار دهید که تمام ورودی های آن ایمن است.
اگر برنامه شما با WebView به داده های حساس دسترسی پیدا می کند، ممکن است بخواهید
از روش () clearCache برای حذف فایل های ذخیره شده محلی استفاده کنید.
همچنین می توانید از هدرهای سمت سرور مانند no-cache استفاده کنید تا نشان دهید که یک برنامه نباید محتوای خاصی را در حافظه پنهان ذخیره کند.
رمزنگاری در اندروید
اندروید علاوه بر پشتیبانی از رمزگذاری کامل filesystem و ارائه کانال های ارتباطی امن،
طیف گسترده ای از الگوریتم ها را برای محافظت از داده ها با استفاده از رمزنگاری ارائه می کند.
به طور کلی، باید بدانید که نرم افزار شما از کدام ارائه دهندگان امنیتی Java Cryptography Architecture (JCA) استفاده می کند.
سعی کنید از بالاترین سطح پیاده سازی چارچوب از قبل موجود استفاده کنید که می تواند مورد استفاده شما را پشتیبانی کند.
در صورت وجود، از ارائهدهندگان ارائهشده توسط Google به ترتیب مشخص شده توسط Google استفاده کنید.
اگر نیاز به بازیابی ایمن یک فایل از یک مکان شبکه شناخته شده دارید، یک URI ساده HTTPS ممکن است کافی باشد و نیازی به دانش رمزنگاری نداشته باشد.
اگر به یک تونل امن نیاز دارید، به جای نوشتن پروتکل خود، از HttpsURLConnection یا SSLSocket استفاده کنید.
اگر از SSLSocket استفاده می کنید، توجه داشته باشید که تأیید نام میزبان را انجام نمی دهد.
اگر متوجه شدید که باید پروتکل خود را پیاده سازی کنید، نباید الگوریتم های رمزنگاری خود را پیاده سازی کنید.
از الگوریتم های رمزنگاری موجود، مانند AES و RSA ارائه شده در کلاس Cipher استفاده کنید.
علاوه بر این، شما باید بهترین شیوه ها را دنبال کنید:
از AES 256 بیتی برای اهداف تجاری استفاده کنید. (اگر در دسترس نیست، از AES 128 بیتی استفاده کنید.)
برای رمزنگاری elliptic curve (EC) از کلید عمومی 224 یا 256 بیتی استفاده کنید.
بدانید چه زمانی از حالت های بلوک CBC، CTR یا GCM استفاده کنید.
از استفاده مجدد IV/counter در حالت CTR اجتناب کنید. مطمئن شوید که از نظر رمزنگاری تصادفی هستند.
هنگام استفاده از رمزگذاری، یکپارچگی را با استفاده از حالت CBC یا CTR با یکی از عملکردهای زیر پیاده سازی کنید:
- HMAC-SHA1
- HMAC-SHA-256
- HMAC-SHA-512
- Mode GCM
از یک مولد اعداد تصادفی ایمن، SecureRandom، برای مقداردهی اولیه کلیدهای رمزنگاری تولید شده توسط KeyGenerator استفاده کنید.
استفاده از کلیدی که با مولد اعداد تصادفی ایمن تولید نمی شود، قدرت الگوریتم را به میزان قابل توجهی ضعیف می کند و ممکن است حملات آفلاین را امکان پذیر کند.
(اگر نیاز به ذخیره کلید برای استفاده مکرر دارید، از مکانیزمی مانند KeyStore استفاده کنید
که مکانیزمی را برای ذخیره طولانی مدت و بازیابی کلیدهای رمزنگاری فراهم می کند.)
استفاده از سرویس ها
یک سرویس اغلب برای ارائه عملکرد برای سایر برنامه ها استفاده می شود.
هر کلاس سرویس باید یک اعلان <service> متناظر در فایل مانیفست خود داشته باشد.
به طور پیش فرض، سرویس ها صادر نمی شوند و نمی توانند توسط هیچ برنامه دیگری فراخوانی شوند.
با این حال، اگر فیلترهای intent را به اعلان سرویس اضافه کنید، به طور پیش فرض صادر می شود.
بهتر است به صراحت مشخصه android:exported را اعلام کنید تا مطمئن شوید که همانطور که می خواهید رفتار می کند.
سرویس ها همچنین می تواند با استفاده از ویژگی android:permission محافظت شود.
با انجام این کار، سایر برنامهها باید یک عنصر <uses-permission> مربوطه را در مانیفست خود
اعلام کنند تا بتوانند سرویس را شروع، متوقف یا متصل کنند.
یک سرویس میتواند با فراخوانی () checkCallingPermission قبل از اجرای آن فراخوانی،
از تماسهای IPC منفرد با مجوز محافظت کند.
شما باید از مجوزهای اعلامی در مانیفست استفاده کنید، زیرا این مجوزها کمتر نیازمند نظارت هستند.
بارگذاری پویای کد
در اندروید به شدت از لود کد از خارج از APK برنامه شما جلوگیری می شود.
انجام این کار به طور قابل توجهی احتمال به خطر افتادن برنامه را به دلیل تزریق کد یا دستکاری کد افزایش می دهد.
اگر برنامه شما کد را به صورت پویا لود می کند، مهمترین چیزی که باید در مورد کدهای بارگذاری شده پویا به خاطر بسپارید این است که با همان مجوزهای امنیتی APK برنامه اجرا می شود.
کاربر بر اساس هویت شما تصمیم می گیرد برنامه شما را نصب کند و کاربر انتظار دارد که هر کدی را که در برنامه اجرا می شود، از جمله کدهایی که به صورت پویا بارگذاری می شود، ارائه دهید.
خطر امنیتی اصلی مرتبط با بارگذاری پویا کد این است که کد باید از یک منبع قابل تأیید باشد.
اگر ماژولها مستقیماً در APK شما گنجانده شدهاند، نمیتوانند توسط برنامههای کاربردی دیگر اصلاح شوند.
بسیاری از برنامهها سعی میکنند کد را از مکانهای ناامن بارگیری کنند، مانند دانلود از شبکه از طریق پروتکلهای رمزگذاری نشده یا از حافظه خارجی.
این مکانها میتوانند به اشخاصی در شبکه اجازه دهند محتوای در حال انتقال یا برنامه دیگری را در دستگاه کاربر تغییر دهد تا محتوای دستگاه را تغییر دهد.
استفاده از کد نیتیو
به طور کلی، به جای استفاده از کد نیتیو با Android NDK، باید از Android SDK برای توسعه برنامه استفاده کنید.
برنامه های ساخته شده با کد نیتیو پیچیده تر بوده و خطاهای رایج بیشتری را به خصوص در حافظه به خود اختصاص می دهند.
اندروید با استفاده از هسته لینوکس ساخته شده است و آشنایی با بهترین شیوه های امنیت توسعه لینوکس به ویژه در صورت استفاده از کد نیتیو مفید است.
یک تفاوت مهم بین اندروید و اکثر محیط های لینوکس، Application Sandbox است.
در اندروید، همه برنامهها، از جمله برنامههایی که با کد نیتیو نوشته شدهاند، در Application Sandbox اجرا میشوند.
در ابتدایی ترین سطح، یک راه خوب برای فکر کردن به آن برای توسعه دهندگان آشنا با لینوکس این است که بدانند به هر برنامه یک UID منحصر به فرد با مجوزهای بسیار محدود داده می شود.
این با جزئیات بیشتر در نمای کلی امنیت اندروید مورد بحث قرار گرفته است،
و حتی اگر از کد نیتیو استفاده می کنید، باید با مجوزهای برنامه آشنا باشید.
مهرسا امینی
برنامه نویس ، انیماتور ، سئوکار
در زندگی رویاهات را دنبال کن