টোকেন, কী এবং PII-এর জন্য Kotlin নিরাপদ স্টোরেজ চেকলিস্ট
টোকেন, কী এবং PII-এর জন্য Android Keystore, EncryptedSharedPreferences, এবং ডেটাবেস এনক্রিপশনের মধ্যে বেছে নেবার জন্য Kotlin নিরাপদ স্টোরেজ চেকলিস্ট।

আপনি যা রক্ষা করতে চাইছেন (সরল ভাষায়)
বিজনেস অ্যাপে নিরাপদ স্টোরেজ মানে এক জিনিস: কেউ যদি ফোন পায় (অথবা আপনার অ্যাপের ফাইলগুলো) তবুও তারা যা সংরক্ষণ করেছেন তা পড়তে বা পুনঃব্যবহার করতে পারবে না। এতে ডিস্কে থাকা ডেটা (data at rest) এবং ব্যাকআপ, লগ, ক্র্যাশ রিপোর্ট বা ডিবাগ টুল থেকে লিক হওয়া সিক্রেটগুলোও অন্তর্ভুক্ত।
একটি সাধারণ মেন্টাল টেস্ট: যদি একজন অপরিচিত ব্যক্তি আপনার অ্যাপের স্টোরেজ ফোল্ডার খোলে, তারা কী করতে পারত? অনেক অ্যাপে সবচেয়ে মূল্যবান জিনিসগুলো ফটো বা সেটিংস নয়। সেগুলো ছোট স্ট্রিং যে গুলো অ্যাক্সেস আনলক করে।
অন-ডিভাইস স্টোরেজে সাধারণত সেশন টোকেন (যাতে ব্যবহারকারী লগইনই থাকে), রিফ্রেশ টোকেন, API কী, এনক্রিপশন কি, ব্যক্তিগত ডেটা (PII) যেমন নাম ও ইমেইল, এবং অফলাইনে ব্যবহারের জন্য ক্যাশ করা ব্যবসায়িক রেকর্ড (অর্ডার, টিকিট, নোট) থাকে।
নিচে বাস্তব জীবনের সাধারণ ব্যর্থতা মোডগুলো:
- হারানো বা চুরি হওয়া ডিভাইস পরীক্ষা করা হয় এবং টোকেন কপি করে ব্যবহারকারীর সনাক্তকরণ করা।
- রুট করা ডিভাইস বা অ্যাক্সেসিবিলিটি কৌশল দিয়ে ম্যালওয়্যার বা একটি “হেল্পার” অ্যাপ লোকাল ফাইল পড়ে।
- স্বয়ংক্রিয় ডিভাইস ব্যাকআপ আপনার অ্যাপ ডেটা এমন জায়গায় নিয়ে চলে যেখানে আপনি পরিকল্পনা করেননি।
- ডিবাগ বিল্ডগুলো টোকেন লগ করে, ক্র্যাশ রিপোর্টে লিখে বা সিকিউরিটি চেক বন্ধ করে।
এই কারণে "শুধু SharedPreferences-এ রাখো" এমনকি টোকেন বা PII-র জন্যও গ্রহণযোগ্য নয়। Plain SharedPreferences এমন যে অ্যাপের ভেতরে একটি স্টিকি নোটে সিক্রেট লেখার মত: সুবিধাজনক, কিন্তু কেউ সুযোগ পেলে সহজে পড়তে পারবে।
সবচেয়ে কাজে লাগার মত শুরু করা হলো: প্রতিটি সংরক্ষিত আইটেমকে নাম দিন এবং দুটি প্রশ্ন করুন: এটা কি কিছু আনলক করে? এবং যদি এটা প্রকাশিত হয় তাহলে কী সমস্যা হবে? বাকিটা (Keystore, encrypted preferences, encrypted database) সেই অনুযায়ী নির্ধারিত হবে।
আপনার ডেটা শ্রেণিবদ্ধ করুন: টোকেন, কী, এবং PII
সব "সেনসিটিভ ডেটা" একসাথে বিবেচনা করা বন্ধ করলে সিকিউর স্টোরেজ সহজ হয়ে যায়। শুরু করুন যে অ্যাপ কি সংরক্ষণ করে এবং লিক হলে কি হবে সেটা তালিকাভুক্ত করে।
টোকেন পাসওয়ার্ডের মতো নয়। অ্যাক্সেস টোকেন ও রিফ্রেশ টোকেন সংরক্ষণ করা হয় যাতে ব্যবহারকারী সেশন চালু থাকে, কিন্তু এগুলোও উচ্চ-মূল্যের সিক্রেট। পাসওয়ার্ড কখনই সংরক্ষণ করা উচিত নয়। লগইনের প্রয়োজনে কেবল সেশন বজায় রাখতে যা লাগবে (সাধারণত টোকেন) সংরক্ষণ করুন এবং পাসওয়ার্ড যাচাই সার্ভারের ওপর ছেড়ে দিন।
কী ভিন্ন শ্রেণির। API কী, সাইনিং কি, এবং এনক্রিপশনের কী পুরো সিস্টেম আনলক করতে পারে, কেবল একটি ব্যবহারকারীর অ্যাকাউন্ট নয়। কেউ যদি ডিভাইস থেকে সেগুলো বের করে নেয়, তারা ব্যাপকভাবে অপব্যবহার করতে পারে। একটি ভালো নিয়ম: যদি কোনো মান অ্যাপের বাইরে ব্যবহৃত হয়ে অ্যাপকে নকল করে বা ডিক্রিপ্ট করতে পারে, তাহলে সেটিকে ইউজার টোকেনের তুলনায় উচ্চ ঝুঁকির হিসেবে বিবেচনা করুন।
PII হলো এমন কিছু যা একজন ব্যক্তিকে শনাক্ত করতে পারে: ইমেইল, ফোন, ঠিকানা, কাস্টমার নোট, সরকারি পরিচয়পত্র, স্বাস্থ্য সংক্রান্ত ডেটা। এমন ফিল্ডগুলোও সংবেদনশীল হয়ে ওঠে যখন একত্রে ব্যবহৃত হয়।
একটি দ্রুত লেবেলিং সিস্টেম যা ব্যবহারিকভাবে কাজ করে:
- Session secrets: access token, refresh token, session cookie
- App secrets: API keys, signing keys, encryption keys (সম্ভব হলে ডিভাইসে রাখা এড়ান)
- User data (PII): প্রোফাইল তথ্য, শনাক্তকারী, ডকুমেন্ট, স্বাস্থ্য বা আর্থিক ডেটা
- Device and analytics IDs: advertising ID, device ID, install ID (অনেক নীতিতে এগুলোও সংবেদনশীল)
Android Keystore: কবে ব্যবহার করবেন
Android Keystore তখনই বেস্ট যখন আপনি এমন সিক্রেটগুলি রক্ষা করতে চান যা কখনই ডিভাইস থেকে প্লেইন ফর্মে বেরোবে না। এটা ক্রিপ্টোগ্রাফিক কীগুলোর জন্য একটি সেফ, আপনার বাস্তব ডেটার জন্য ডাটাবেজ নয়।
এটা কী ভালো করে: কী জেনারেট করা এবং হোল্ড করা যা এনক্রিপশন, ডিক্রিপশন, সাইনিং বা ভেরিফিকেশনের জন্য ব্যবহৃত হয়। সাধারণত আপনি কোথাও অন্য জায়গায় একটি টোকেন বা অফলাইন ডেটা এনক্রিপ্ট করবেন, এবং Keystore কী সেটাই আনলক করবে।
হার্ডওয়্যার-ব্যাকড কীগুলি: বাস্তবে এর অর্থ
অনেক ডিভাইসে Keystore কীগুলো হার্ডওয়্যার-ব্যাকড হতে পারে। এর মানে কী অপারেশনগুলো একটি প্রোটেক্টেড এনভায়রনমেন্টের মধ্যে হয় এবং কী ম্যাটেরিয়াল বের করা যায় না। এটা ম্যালওয়্যার থেকে ঝুঁকি কমায় যা অ্যাপ ফাইল পড়তে পারে।
হার্ডওয়্যার-ব্যাকড সব ডিভাইসে নিশ্চিত নয়, এবং মডেল ও Android ভার্সন অনুযায়ী আচরণ ভিন্ন। কী অপারেশন বিফল হতে পারে এমন ধরে নিয়ে তৈরী করুন।
ইউজার অথেনটিকেশন গেটস
Keystore একটি কী ব্যবহার করার আগে ইউজারের উপস্থিতি (বায়োমেট্রিক বা ডিভাইস ক্রেডেনশিয়ালের) চাওয়া চালু করতে পারে। উদাহরণস্বরূপ, আপনি একটি এক্সপোর্ট টোকেন এনক্রিপ্ট করে রাখতে পারেন এবং কেবল ফিংগারপ্রিন্ট বা PIN নিশ্চিত করার পর এটি ডিক্রিপ্ট করতে দেবেন।
Keystore শক্তভাবে মানানসই যখন আপনি নন-এক্সপোর্টেবল কী চান, বায়োমেট্রিক বা ডিভাইস-ক্রেডেনশিয়াল অনুমোদন চান সংবেদনশীল কাজের আগে, এবং যখন আপনি পার-ডিভাইস সিক্রেট চান যা ব্যাকআপ বা সিঙ্ক করা উচিত নয়।
পিটফলসমূহের জন্য পরিকল্পনা করুন: লক স্ক্রিন সেটিং পরিবর্তন, বায়োমেট্রিক পরিবর্তন, বা সিকিউরিটি ইভেন্টের পরে কীগুলো ইনভ্যালিডেট হয়ে যেতে পারে। ব্যর্থতার প্রত্যাশা রাখুন এবং একটি পরিষ্কার ব্যাকফল: ইনভ্যালিড কী সনাক্ত করুন, এনক্রিপ্টেড ব্লব মুছে দিন, এবং ব্যবহারকারীকে পুনরায় লগইন করতে বলুন।
EncryptedSharedPreferences: কখন যথেষ্ট
EncryptedSharedPreferences ছোট সংখ্যক কীগুলোর জন্য একটি ভালো ডিফল্ট। এটি "SharedPreferences, কিন্তু এনক্রিপ্টেড"—তাই কেউ শুধু ফাইল খুলে ভ্যালু পড়তে পারবে না।
আন্ডার দ্য হুড এটি একটি মাস্টার কি ব্যবহার করে মান গুলো এনক্রিপ্ট ও ডিক্রিপ্ট করে। সেই মাস্টার কি Android Keystore দ্বারা প্রোটেক্টেড থাকে, তাই আপনার অ্যাপ র কাঁচা এনক্রিপশন কি প্লেইন টেক্সটে রাখে না।
সাধারণভাবে এটি কিছু ছোট আইটেমের জন্য যথেষ্ট: অ্যাক্সেস ও রিফ্রেশ টোকেন, সেশন ID, ডিভাইস ID, এনভায়রনমেন্ট ফ্ল্যাগ, বা লাস্ট সিঙ্ক টাইম-এর মতো ছোট স্টেট। যদি সত্যিই সংরক্ষণ করার প্রয়োজন হয় কিছু ক্ষুদ্র ব্যবহারকারীর ডেটা, তখনও এটা ঠিক আছে, কিন্তু এটা PII-এর ডাম্পিং গ্রাউন্ড হওয়া উচিত নয়।
বড় বা স্ট্রাকচার্ড ডেটার জন্য এটি ভালো ফিট নয়। যদি আপনাকে অফলাইন লিস্ট, সার্চ, বা ফিল্ড দ্বারা কোয়েরি করতে হয় (কাস্টমার, টিকিট, অর্ডার), তাহলে EncryptedSharedPreferences ধীরে এবং অপ্রয়োজনীয় হয়ে যাবে। সেই পয়েন্টে আপনি এনক্রিপ্টেড ডাটাবেস চাইবেন।
একটি সহজ নিয়ম: যদি আপনি প্রতিটি স্টোরড কী এক স্ক্রিনে তালিকাভুক্ত করতে পারেন, তাহলে EncryptedSharedPreferences সম্ভবত ঠিক আছে। যদি রো এবং কোয়েরি দরকার হয়, তাহলে এগিয়ে যান।
ডাটাবেস এনক্রিপশন: কখন দরকার
ডাটাবেস এনক্রিপশন জরুরি যখন আপনি একটি ছোট সেটিং বা একটি টোকেনের চেয়ে বেশি সংরক্ষণ করেন। যদি আপনার অ্যাপ ডিভাইসে ব্যবসায়িক ডেটা রাখে, ধরে নিন এটি একটি হারানো ফোন থেকে এক্সট্র্যাক্ট করা যেতে পারে যদি না আপনি তা সুরক্ষিত করেন।
একটি ডাটাবেস তখনেই যুক্তিযুক্ত যখন আপনাকে রেকর্ডগুলো অফলাইনে অ্যাক্সেস করতে হবে, লোকাল ক্যাশিং প্রয়োজন পারফর্ম্যান্সের জন্য, ইতিহাস/অডিট ট্রেইল, অথবা লম্বা নোট ও অ্যাটাচমেন্ট রাখা দরকার।
দুটি সাধারণ এনক্রিপশন উপায়
ফুল ডাটাবেস এনক্রিপশন (অften SQLCipher-স্টাইল) পুরো ফাইলকে অ্যাট রেস্ট এনক্রিপ্ট করে। আপনার অ্যাপ এটিকে একটি কী দিয়ে খুলে। এটা সহজ কারণ আপনাকে কোন কলাম সুরক্ষিত তা ট্র্যাক করতে হয় না।
অ্যাপ-লেয়ার ফিল্ড এনক্রিপশন কেবল নির্দিষ্ট ফিল্ডগুলো লেখার আগে এনক্রিপ্ট করে, তারপর পড়ার সময় ডিক্রিপ্ট করে। এটি তখন কাজ করতে পারে যখন বেশিরভাগ রেকর্ড সংবেদনশীল না হয়, অথবা আপনি নির্দিষ্ট ডাটাবেস সেটআপ রাখতে চান ছাড়া ফাইল ফরম্যাট পরিবর্তন করা।
ট্রেডঅফ: গোপনীয়তা বনাম সার্চ ও সোর্ট
ফুল ডাটাবেস এনক্রিপশন ডিস্কে সবকিছু লুকায়, কিন্তু একবার ডাটাবেস আনলক হলে আপনার অ্যাপ সাধারাণভাবে কোয়েরি করতে পারে।
ফিল্ড এনক্রিপশন নির্দিষ্ট কলামগুলোকে রক্ষা করে, কিন্তু এনক্রিপ্টেড মানগুলোর উপর সহজ সার্চ ও সোর্ট চলে না। এনক্রিপ্টেড লাস্ট নাম দ্বারা সোর্ট করা নির্ভরযোগ্য হবে না, এবং সার্চ হবে বা তো ধীর (পরে ডিক্রিপ্ট করে সার্চ) বা অতিরিক্ত ইনডেক্স রাখা লাগবে (আরও জটিলতা ও সম্ভাব্য লিক)।
কী ম্যানেজমেন্ট বেসিক্স
ডাটাবেস কী কখনই হার্ডকোড করা বা অ্যাপের সাথে শিপ করা উচিত নয়। একটি সাধারণ প্যাটার্ন হল র্যান্ডম ডাটাবেস কী জেনারেট করা, তারপর সেটি একটি Keystore-রক্ষিত কী দিয়ে র্যাপ (এনক্রিপ্ট) করা। লগআউট হলে আপনি র্যাপড কী মুছে দিতে পারেন এবং লোকাল ডাটাবেসকে ডিসপোজেবল ভাবতে পারেন, অথবা যদি অ্যাপকে অফলাইন কাজ বজায় রাখতে হয় তবে তা রাখতে পারেন।
কিভাবে নির্বাচন করবেন: ব্যবহারিক তুলনা
আপনি সাধারণভাবে "সবচেয়ে নিরাপদ" অপশনই বেছে নেবেন না। আপনি বেছে নেবেন সবচেয়ে নিরাপদ অপশন যা আপনার অ্যাপের ডেটা ব্যবহারের উপযোগী।
যেই প্রশ্নগুলো প্রকৃতপক্ষে সঠিক সিদ্ধান্ত নেয়:
- ডেটা কত ঘনঘন পড়া হয় (প্রতি লঞ্চে না কি বিরলভাবে)?
- ডেটার পরিমাণ কত (কয়েক বাইট না কি হাজার রেকর্ড)?
- লিক হলে কী হবে (অস্বস্তিকর, ব্যয়বহুল, আইনি রিপোর্টযোগ্য)?
- অফলাইন অ্যাক্সেস, সার্চ বা সোর্ট দরকার কি?
- আপনার কমপ্লায়েন্স চাহিদা আছে কি (রিটেনশন, অডিট, এনক্রিপশন নিয়ম)?
একটি কাজ করা ম্যাপিং:
- টোকেন (OAuth access এবং refresh tokens) সাধারণত EncryptedSharedPreferences-এ রাখা উচিত কারণ এগুলো ছোট এবং প্রায়শই পড়া হয়।
- কী ম্যাটেরিয়াল সম্ভব হলে Android Keystore-এ থাকা উচিত যাতে ডিভাইস থেকে কপি হওয়ার সম্ভাবনা কমে।
- PII এবং অফলাইন ব্যবসায়িক ডেটা যখন আপনি কয়েকটি ফিল্ডের বেশি সংরক্ষণ করেন বা অফলাইন লিস্ট ও ফিল্টার দরকার তখন সাধারণত ডাটাবেস এনক্রিপশন দরকার।
মিশ্র ডেটা ব্যবসায়িক অ্যাপে স্বাভাবিক। একটি ব্যবহারিক প্যাটার্ন হলো লোকাল ডাটাবেস বা ফাইলের জন্য একটি র্যান্ডম ডেটা এনক্রিপশন কী (DEK) জেনারেট করা, কেবল সেই র্যাপড DEK-কে Keystore-ব্যাকড কী দিয়ে স্টোর করা, এবং প্রয়োজনে রোটেট করা।
নিশ্চিত না হলে, সহজ নিরাপদ পথ বেছে নিন: কমই স্টোর করুন। অফলাইন PII এড়ান যতক্ষণ না সত্যিই প্রয়োজন, এবং কীগুলো Keystore-এ রাখুন।
ধাপে ধাপে: Kotlin অ্যাপে নিরাপদ স্টোরেজ বাস্তবায়ন
শুরুতে লেখুন প্রতিটি ভ্যালু যা আপনি ডিভাইসে রাখার পরিকল্পনা করেছেন এবং ঠিক কেন তা থাকা দরকার। এটা "যদি কখনও দরকার" ধাঁচের স্টোরেজ প্রতিরোধ করার দ্রুততম উপায়।
কোড লেখার আগে আপনার নিয়ম নির্ধারণ করুন: প্রতিটি আইটেম কতক্ষণ থাকবে, কখন বদলানো হবে, এবং "লগআউট" মানে আসলে কী। একটি অ্যাক্সেস টোকেন ১৫ মিনিটে এক্সপায়ার হতে পারে, রিফ্রেশ টোকেন দীর্ঘ সময়ের জন্য থাকতে পারে, এবং অফলাইন PII-র জন্য কঠোর "৩০ দিনের পরে ডিলিট" নিয়ম থাকতে পারে।
পরিচালনাযোগ্য ইমপ্লিমেন্টেশন:
- একটি একক "SecureStorage" র্যাপার তৈরি করুন যাতে অ্যাপের বাকি অংশ কখনই সরাসরি SharedPreferences, Keystore বা ডাটাবেস এ না যায়।
- প্রতিটি আইটেম সঠিক স্থানে রাখুন: টোকেন EncryptedSharedPreferences-এ, এনক্রিপশন কীগুলো Android Keystore-এ, এবং বড় অফলাইন ডেটাসেট এনক্রিপ্টেড ডাটাবেসে।
- ব্যর্থতাগুলো উদ্দেশ্যবশত হ্যান্ডেল করুন। সিকিউর স্টোরেজ ব্যর্থ হলে, closed ব্যর্থ করুন। চুপ করে plain স্টোরেজে fallback করবেন না।
- ডায়াগনস্টিক যোগ করুন কিন্তু ডেটা লিক করবেন না: ইভেন্ট টাইপ ও এরর কোড লগ করুন, কভর টোকেন, কীগুলি বা ইউজার ডিটেইলস না।
- ডিলিশন পাথগুলো সংযুক্ত করুন: লগআউট, অ্যাকাউন্ট মুছে ফেলা, এবং "clear app data" একই ওয়াইপ রুটিনে ফেলুন।
তারপর বিরক্তিকর কেসগুলো পরীক্ষা করুন যা প্রোডাকশনে সিকিউর স্টোরেজ ভাঙ্গে: ব্যাকআপ থেকে রিস্টোর, পুরোনো ভার্সন থেকে আপগ্রেড, ডিভাইস লক সেটিংস পরিবর্তন, নতুন ফোনে মাইগ্রেট করা। ব্যবহারকারীরা যেন এমন লুপে আটকে না পড়ে যেখানে সংরক্ষিত ডেটা ডিক্রিপ্ট করা যাচ্ছে না কিন্তু অ্যাপ বারবার চেষ্টা করছে।
অবশেষে, দলটি অনুসরণ করতে পারে এমন এক পাতার সিদ্ধান্তগুলো লিখে রাখুন: কি কোথায় সংরক্ষণ করা হয়, রিটেনশান পিরিয়ড, এবং ডিক্রিপশন ব্যর্থ হলে কী হবে।
সাধারণ ভুলভ্রান্তি যা সিকিউর স্টোরেজ ভেঙে দেয়
অধিকাংশ ব্যর্থতা লাইব্রেরি বাছাই সম্পর্কে নয়। সেগুলো ঘটে যখন একটি ছোট শর্টকাট অনিচ্ছায় সিক্রেটগুলিকে এমন জায়গায় নকল করে যেখানে আপনি রাখার কথা ভাবেননি।
সবচেয়ে বড় রেড ফ্ল্যাগ হলো একটি রিফ্রেশ টোকেন (বা দীর্ঘ-জীবন সম্পন্ন সেশন টোকেন) প্লেইনটেক্সটে কোথাও সংরক্ষণ করা: SharedPreferences, একটি ফাইল, একটি "টেম্পোরারি" ক্যাশ, বা লোকাল ডাটাবেস কলামে। যদি কেউ ব্যাকআপ পায়, রুটেড ডিভাইস ডাম্প, বা ডিবাগ বিল্ড আর্টিফ্যাক্ট পায়, সেই টোকেন পাসওয়ার্ডের চেয়েও স্থায়ী হতে পারে।
সিক্রেটগুলো দৃশ্যমানতার কারণে লিকও করে, শুধুমাত্র স্টোরেজের কারণে নয়। সম্পূর্ণ রিকোয়েস্ট হেডার লগ করা, ডিবাগিং সময় টোকেন প্রিন্ট করা, বা ক্র্যাশ রিপোর্ট/অ্যানালিটিক্স ইভেন্টে "হেল্পফুল" কনটেক্সট যুক্ত করা ক্রেডেনশিয়ালগুলো ডিভাইসের বাইরে উন্মুক্ত করে দিতে পারে। লগগুলোকে পাবলিক ভাবুন।
কী হ্যান্ডলিং আরেকটি সাধারণ গ্যাপ। সবকিছুর জন্য একটি কী ব্যবহার করলে ব্লাস্ট রেডিয়াস বাড়ে। কী রোটেশন না করলে পুরোনো কমপ্রোমাইজেশন কার্যকর থাকে। কী ভার্সনিং, রোটেশন, এবং পুরোনো এনক্রিপ্টেড ডেটার সাথে কি হয় তা নিয়ে প্ল্যান করুন।
"ভল্টের বাইরে" পথগুলো ভুলে যাবেন না
এনক্রিপশন ক্লাউড ব্যাকআপকে লোকাল অ্যাপ ডেটা কপিয় করা থামায় না। এটি স্ক্রিনশট বা স্ক্রিন রেকর্ডিংকে থামায় না। এটি ডিবাগ বিল্ড যেখানে সেটিংস শিথিল করা আছে থামায় না, কিংবা এক্সপোর্ট ফিচার (CSV/share sheets) সংবেদনশীল ফিল্ড লিক করানো থামায় না। ক্লিপবোর্ড ব্যবহার এক-টাইম কোড বা অ্যাকাউন্ট নাম্বর লিক করাতে পারে।
এছাড়াও, এনক্রিপশন অথরাইজেশন সমস্যা ঠিক করে না। যদি আপনার অ্যাপ লগআউটের পরও PII দেখায়, বা ক্যাশ করা ডেটা পুনরায় যাচাই না করে প্রদর্শন করে, সেটা অ্যাক্সেস কন্ট্রোল বাগ। UI লক করুন, লগআউট-এ সংবেদনশীল ক্যাশ মুছুন, এবং সুরক্ষিত ডেটা দেখানোর আগে অনুমতি পুনঃপরীক্ষা করুন।
অপারেশনাল বিবরণ: লাইফসাইকেল, লগআউট, এবং এজ কেস
নিরাপদ স্টোরেজ কেবল কোথায় সিক্রেট রাখা নয়; এটা কীভাবে সময়ের সাথে আচরণ করে: অ্যাপ যখন স্লিপ করে, যখন ব্যবহারকারী লগআউট করে, এবং যখন ডিভাইস লক থাকে।
টোকেনের জন্য পূর্ণ লাইফসাইকেল পরিকল্পনা করুন। অ্যাক্সেস টোকেন হওয়া উচিত শর্ট-লিভড। রিফ্রেশ টোকেন পাসওয়ার্ডের মতো আচরণ করা উচিত। যদি টোকেন মেয়াদ উত্তীর্ণ হয়, চুপিচুপি রিফ্রেশ করুন। যদি রিফ্রেশ ব্যর্থ হয় (রিভোক করা, পাসওয়ার্ড পরিবর্তিত, ডিভাইস রিমুভ করা), তখন রিট্রাই লুপ বন্ধ করে ক্লিন সাইন-ইন বাধ্য করুন। সার্ভার-সাইড রিভোকেশনও সমর্থন করুন। স্থানীয় সঠিক স্টোরেজ অনেকক্ষণ চলবে না যদি আপনি চুরি হওয়া ক্রেডেনশিয়ালগুলো কখনই বাতিল না করেন।
বায়োমেট্রিককে রি-অথেনটিকেশনের জন্য ব্যবহার করুন, সবকিছুর জন্য নয়। যেসব অ্যাকশন বাস্তব ঝুঁকি রাখে (PII দেখা, ডেটা এক্সপোর্ট করা, পেআউট ডিটেইল পরিবর্তন, এক-টाइम কী দেখা) সেগুলোতে প্রম্পট দিন। প্রতিটি অ্যাপ ওপেন-এ প্রম্পট দেবেন না।
লগআউট-এ কঠোর এবং পূর্বানুমানযোগ্য হন:
- প্রথমে ইন-মেমরি কপি মুছুন (সিঙ্গলটন, ইন্টারসেপ্টর বা ViewModel-এ ক্যাশ করা টোকেন)।
- স্টোর করা টোকেন ও সেশন স্টেট মুছুন (রিফ্রেশ টোকেন সহ)।
- যদি আপনার ডিজাইন সাপোর্ট করে, লোকাল এনক্রিপশন কীগুলো মুছুন বা ইনভ্যালিডেট করুন।
- অফলাইন PII এবং ক্যাশ করা API রেসপন্স ডিলিট করুন।
- ব্যাকগ্রাউন্ড জবগুলো নিষ্ক্রিয় করুন যা ডেটা আবার ফেচ করতে পারে।
বিজনেস অ্যাপে এজ কেসগুলো গুরুত্বপূর্ণ: এক ডিভাইসে একাধিক অ্যাকাউন্ট, ওয়ার্ক প্রোফাইল, ব্যাকআপ/রিস্টোর, ডিভাইস-টু-ডিভাইস ট্রান্সফার, এবং পারশিয়াল লগআউট (কোম্পানি/ওয়ার্কস্পেস স্যুইচ করা)। ফোর্স স্টপ, OS আপগ্রেড, এবং ঘড়ির সময় পরিবর্তন পরীক্ষা করুন কারণ টাইম ড্রিফট এক্সপায়ারি লজিককে ভেঙে দিতে পারে।
টেম্পারিং ডিটেকশন একটি ট্রেডঅফ। বেসিক চেকগুলো (ডিবাগেবল বিল্ড, এমুলেটর ফ্ল্যাগ, সিম্পল রুট সিগন্যাল, Play Integrity ভেরডিক্ট) সহজ অপব্যবহার কমাতে পারে, কিন্তু স্থির আক্রমণকারী সেগুলো বাইপাস করতে পারে। টেমপার সিগন্যালগুলোকে ঝুঁকি ইনপুট হিসেবে নিন: অফলাইন অ্যাক্সেস সীমিত করুন, রি-অথোরি দাবি করুন, এবং ইভেন্ট লগ করুন।
রিলিজের আগে দ্রুত চেকলিস্ট
রিলিজের আগে এটা ব্যবহার করুন। এটি সেই জায়গাগুলোকে টার্গেট করে যেখানে বাস্তব ব্যবসায়িক অ্যাপে সিকিউর স্টোরেজ ব্যর্থ হয়।
- ধরা নিন ডিভাইস শত্রুতাপূর্ণ হতে পারে। যদি আক্রমণকারী একটি রুটেড ডিভাইস বা পুরো ডিভাইস ইমেজ পায়, তারা কি অ্যাপ ফাইল, প্রেফারেন্স, লগ বা স্ক্রিনশট থেকে টোকেন, কী বা PII পড়তে পারবে? যদি উত্তর "হয়তো" হয়, তাহলে কীগুলো Keystore-ব্যাকড প্রোটেকশনে নিয়ে যান এবং পেপলোড এনক্রিপ্টেড রাখুন।
- ব্যাকআপ ও ডিভাইস ট্রান্সফারের পরীক্ষা করুন। সংবেদনশীল ফাইলগুলো Android Auto Backup, ক্লাউড ব্যাকআপ, এবং ডিভাইস-টু-ডিভাইস ট্রান্সফারে রাখবেন না। যদি রিস্টোরে কী হারানো ডিক্রিপশন ভাঙে, তাহলে recovery flow পরিকল্পনা করুন (রি-অথ ও পুনরায় ডাউনলোড), ডিক্রিপ্ট করার চেষ্টা না করে।
- অ্যাক্সিডেন্টাল প্লেইনটেক্সট শিকার করুন। টেম্প ফাইল, HTTP ক্যাশ, ক্র্যাশ রিপোর্ট, অ্যানালিটিক্স ইভেন্ট, এবং ইমেজ ক্যাশ খুঁজুন যেগুলোতে PII বা টোকেন থাকতে পারে। ডিবাগ লগ এবং JSON ডাম্প চেক করুন।
- এক্সপায়ার ও রোটেট করুন। অ্যাক্সেস টোকেন শর্ট-লিভড হওয়া উচিত, রিফ্রেশ টোকেন রক্ষণ করুন, এবং সার্ভার-সাইড সেশন রিভোকে যোগ করুন। কী রোটেশন ডিফাইন করুন এবং যখন টোকেন রিজেক্ট হয় তখন অ্যাপ কী করবে তা নির্ধারণ করুন (মুছা, রি-অথ, একবার রিট্রাই)।
- রিইনস্টল ও ডিভাইস-চেঞ্জ আচরণ। আনইনস্টল ও পুনরায় ইনস্টল করে অফলাইনে খুলে পরীক্ষা করুন। যদি Keystore কীগুলো চলে গেছে, অ্যাপ নিরাপদভাবে ব্যর্থ করা উচিত (এনক্রিপ্টেড ডেটা মুছে ফেলুন, সাইন-ইন দেখান, আংশিক পড়ে স্টেট করাপ্ট করা এড়ান)।
একটি দ্রুত ভেরিফিকেশন হলো একটি "খারাপ দিন" টেস্ট: একজন ব্যবহারকারী লগআউট করে, পাসওয়ার্ড পরিবর্তন করে, ব্যাকআপ রিস্টোর করে নতুন ফোনে এবং প্লেনে অ্যাপ খোলে। ফলাফলটি পূর্বানুমানযোগ্য হওয়া উচিত: বা তো ডেটা সঠিক ব্যবহারকারীর জন্য ডিক্রিপ্ট হবে, বা এটি মুছে ফেলা হবে এবং সাইন-ইন করার পর পুনরায় ফেট করা হবে।
উদাহরণ দৃশ্য: অফলাইনে PII রাখে এমন একটি বিজনেস অ্যাপ
ধরে নিন একটি ফিল্ড সেলস অ্যাপ যেটি দুর্বল সিগন্যালযুক্ত এলাকায় ব্যবহৃত হয়। রেপরা সকালে একবার লগইন করে, নিযুক্ত কাস্টমারদের অফলাইনে দেখেন, মিটিং নোট যোগ করেন, পরে সিঙ্ক করেন। এখানে স্টোরেজ চেকলিস্ট থিওরি নয়, বাস্তবে রিয়েল লিক আটকানোর কাজে লাগে।
একটি ব্যবহারিক বিভাজন:
- অ্যাক্সেস টোকেন: শর্ট-লিভড রাখুন এবং
EncryptedSharedPreferences-এ সংরক্ষণ করুন। - রিফ্রেশ টোকেন: আরও শক্তভাবে রক্ষা করুন এবং Android Keystore দিয়ে গেট করুন।
- কাস্টমার PII (নাম, ফোন, ঠিকানা): এনক্রিপ্টেড লোকাল ডাটাবেসে রাখুন।
- অফলাইন নোট ও অ্যাটাচমেন্ট: এনক্রিপ্টেড ডাটাবেসে রাখুন, এক্সপোর্ট ও শেয়ারিং-এ অতিরিক্ত সতর্কতা নিন।
এখন দুটি ফিচার যোগ করুন এবং ঝুঁকি বদলে যায়।
আপনি যদি "remember me" যোগ করেন, রিফ্রেশ টোকেন হয়ে যায় প্রধান দরজা অ্যাকাউন্টে ফিরে যাওয়ার। এটাকে পাসওয়ার্ডের মত বিবেচনা করুন। আপনার ব্যবহারকারীদের উপর নির্ভর করে, ডিক্রিপ্ট করার আগে ডিভাইস আনলক (PIN/pattern/biometric) প্রয়োজন হতে পারে।
আপনি যদি অফলাইন মোড যোগ করেন, তখন আপনি কেবল একটি সেশন রক্ষা করছেন না; পুরো কাস্টমার লিস্ট রক্ষা করছেন যা নিজে মূল্যবান। সাধারণত এটি আপনাকে ডাটাবেস এনক্রিপশন ও স্পষ্ট লগআউট নিয়মের দিকে ঠেলে দেয়: লোকাল PII মুছুন, কেবল পরবর্তী লগইনের জন্য যা দরকার রাখুন, এবং ব্যাকগ্রাউন্ড সিঙ্ক বাতিল করুন।
রিয়েল ডিভাইসে পরীক্ষা করুন, কেবল এমুলেটর নয়। ন্যূনতমভাবে লক/আনলক, পুনরায় ইনস্টল আচরণ, ব্যাকআপ/রিস্টোর, এবং মাল্টি-ইউজার বা ওয়ার্ক প্রোফাইল আলাদা হওয়া যাচাই করুন।
পরবর্তী ধাপ: এটিকে টিম হ্যাবিট বানান
নিরাপদ স্টোরেজ তখনই কাজ করে যখন এটা একটি অভ্যাস। একটি সংক্ষিপ্ত স্টোরেজ পলিসি লিখে রাখুন যা দল অনুসরণ করতে পারবে: কী কোথায় যায় (Keystore, EncryptedSharedPreferences, এনক্রিপ্টেড ডাটাবেস), কখন কিছু কখনই সংরক্ষণ করা হবে না, এবং কি লগআউট-এ মুছে ফেলতে হবে।
এটাকে দৈনন্দিন ডেলিভারির অংশ বানান: definition of done, কোড রিভিউ, এবং রিলিজ চেক।
একটি হালকা রিভিউয়ার চেকলিস্ট:
- প্রতিটি স্টোরড আইটেম লেবেল করা আছে (token, key material, বা PII)।
- স্টোরেজ পছন্দ কোড মন্তব্যে justified।
- লগআউট ও অ্যাকাউন্ট সুইচ সঠিক ডেটা মুছে ফেলে (এবং কেবল সেই ডেটা)।
- এরর ও লগগুলো কখনই সিক্রেট বা পুরো PII প্রিন্ট করে না।
- কেউ পলিসির মালিক এবং এটিকে আপটুট রাখে।
যদি আপনার দল AppMaster (appmaster.io) ব্যবহার করে বিজনেস অ্যাপ বানায় এবং Android ক্লায়েন্টের জন্য Kotlin সোর্স এক্সপোর্ট করে, একই SecureStorage র্যাপার পদ্ধতি রাখুন যাতে জেনারেটেড ও কাস্টম কোড একই নীতিগুলো মেনে চলে।
একটি ছোট প্রুফ-অফ-কনসেপ্ট দিয়ে শুরু করুন
একটি ছোট POC বানান যা একটি অথ টোকেন এবং একটি PII রেকর্ড (উদাহরণস্বরূপ, অফলাইনে দরকার একটি কাস্টমারের ফোন নম্বর) সংরক্ষণ করে। তারপর ফ্রেশ ইনস্টল, আপগ্রেড, লগআউট, লক স্ক্রিন পরিবর্তন, এবং ক্লিয়ার অ্যাপ ডাটা টেস্ট করুন। যখন ওয়াইপ আচরণ সঠিক ও পুনরাবৃত্তি যোগ্য হয় তখনই বাড়ান।
প্রশ্নোত্তর
Start by listing exactly what you store and why. Put small session secrets like access and refresh tokens in EncryptedSharedPreferences, keep cryptographic keys in Android Keystore, and use an encrypted database for offline business records and PII once you have more than a couple of fields or need queries.
Plain SharedPreferences stores values in a file that can often be read from device backups, rooted device file access, or debugging artifacts. If the value is a token or any PII, treating it like a normal setting makes it much easier to copy and reuse outside the app.
Use Android Keystore to generate and hold cryptographic keys that should not be extractable. You typically use those keys to encrypt other data (tokens, database keys, files), and optionally require user authentication (biometric or device credential) before the key can be used.
It means key operations can happen in protected hardware so the key material is harder to extract, even if an attacker can read app files. Don’t assume it’s always available or always behaves the same; design for failures and have a recovery flow when keys are unavailable or invalidated.
It’s usually enough for a small set of frequently read key-value secrets like access/refresh tokens, session IDs, and small pieces of state. It’s not a good fit for large data, structured offline records, or anything you need to query and filter like customers, tickets, or orders.
Choose an encrypted database when you store offline business data or PII at scale, need querying/searching/sorting, or keep history for offline use. It reduces the risk of a lost device exposing entire customer lists or notes, while still letting the app work offline with a clear key strategy.
Full database encryption protects the whole file at rest and is easier to reason about because you don’t have to track which columns are sensitive. Field encryption can work for a few columns but makes search and sort hard, and it’s easy to accidentally leak data through indexes or derived fields.
Generate a random database key, then store it only in wrapped form (encrypted) using a Keystore-backed key. Never hardcode keys or ship them in the app, and decide what happens on logout or key invalidation (often: delete the wrapped key and treat local data as disposable).
Keys can be invalidated by lock screen or biometric changes, OS security events, or restore/migration scenarios. Handle it explicitly: detect decryption failures, wipe the encrypted blobs or local database safely, and prompt the user to sign in again rather than looping or falling back to plaintext storage.
Most leaks happen “outside the vault”: logs, crash reports, analytics events, debug prints, HTTP caches, screenshots, clipboard use, and backup/restore paths. Treat logs as public, never record tokens or full PII, disable accidental export paths, and make logout wipe both stored data and in-memory copies.


