နားလည်ထားရမယ့် အချက်
လုံခြုံရေး Audit ဆိုတာ စမ်းသပ်မှုကြီးတစ်ခုတည်း မဟုတ်ပါဘူး - မိုဘိုင်းအက်ပ် setup တိုင်းကို မေးခွန်းတစ်စုတည်းနဲ့ ထပ်ခါထပ်ခါ စစ်ဆေးတဲ့ အလေ့အထတစ်ခုပါ။ ဒီမေးခွန်းတွေဟာ cryptography အနက်နက်ရှိုင်းရှိုင်း သိစရာမလိုပါဘူး။ လက်တွေ့အက်ပ်တွေမှာ ထပ်ခါထပ်ခါ ဖြစ်ပေါ်နေတဲ့ ပုံစံတွေကို သတိထားမိဖို့သာ လိုအပ်ပါတယ်၊ ဘာလို့ဆိုတော့ hack ခံရတဲ့ အက်ပ်တွေမှာ အမှားအနည်းငယ်ပဲ ထပ်ခါထပ်ခါ ပေါ်လာလေ့ရှိလို့ပါ။
- Secrets နဲ့ API key တွေ ဘယ်မှာ တကယ်သိမ်းထားလဲ။
- ဘယ် permission တွေကို ဘယ်အချိန်မှာ တောင်းလဲ။
- Sensitive data ကို device ပေါ်မှာ ဘယ်လိုသိမ်းထားလဲ။
- Log ထဲမှာ ဘာတွေ ပါသွားလဲ။
- Server က client ကို ရိုးသားစွာ လုပ်ဆောင်လိမ့်မယ်လို့ ဘယ်ဆုံးဖြတ်ချက်တွေကို ယုံကြည်ထားသေးလဲ။
ဒီလေ့ကျင့်ခန်းမှာ QuickCart ဆိုတဲ့ စိတ်ကူးဖန်တီးထားတဲ့ ဈေးဝယ်အက်ပ်တစ်ခုနဲ့ သူ့ရဲ့တည်ဆောက်ပုံ ဖော်ပြချက်ကို ပေးထားပါတယ်။ အဲဒီဖော်ပြချက်ထဲမှာ ဒီကုန်သင်ရိုးက အမည်ပေးထားပြီးသား အမှားတွေရဲ့ ပြောင်းလဲပုံ ပြဿနာငါးခု ဝှက်ထားပါတယ်။ သင့်တာဝန်က အားလုံးကို ရှာတွေ့ပြီး ဘယ်လို fix လုပ်ရမလဲဆိုတာကို "ဒါဆိုးတယ်" လို့ label တစ်ခုတည်းမတပ်ဘဲ ရှင်းပြရမှာပါ။
Audit လုပ်ပါ၊ Attack မလုပ်ပါနဲ့
ဒီလေ့ကျင့်ခန်းဟာ defensive ဖက်ကသာ ဖြစ်ပါတယ် - system ရဲ့ ဖော်ပြချက်ကို ဖတ်ပြီး trust ကို မလုံခြုံစွာ ထားရှိနေတဲ့နေရာကို ထောက်ပြခြင်းသာ ဖြစ်ပါတယ်။ တကယ့် audit report က fix တွေကို အကြံပြုတာပါ - အလုပ်လုပ်တဲ့ exploit ကို ဘယ်တော့မှ ထုတ်ပေးမှာ မဟုတ်ပါဘူး။
QUICKCART: THE FLAWED SETUP (AUDIT TARGET)
------------------------------------------
QUICKCART: THE FLAWED SETUP (AUDIT TARGET)
--------------------------------------------
QuickCart Mobile App (installed on user's phone)
[1] ANALYTICS_KEY (privileged, elevated access)
... hardcoded directly in the app's source
[2] First launch permission screen asks for:
Camera + Contacts + Precise Location (all 3)
before any feature actually needs them
[3] access_token stored in plain local storage
(not Keychain / Keystore-backed secure storage)
[4] Debug build logs: console.log(authResponse)
-> prints the full response, tokens included
[5] Checkout: discount price computed ONLY
on-device, then sent as-is to the server
|
v
Backend / Payment API
(bills whatever price the app tells it to)လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
QuickCart ကို တကယ်အလုပ်ဖြစ်တဲ့ audit တစ်ခု ဘယ်လိုလုပ်မလဲဆိုတာ ပြဿနာတစ်ခုချင်းစီကို setup မှာ ဖော်ပြထားသလို အစဉ်အတိုင်း ကြည့်ကြပါစို့။
Bundled analytics key
Privileged, elevated-access ရှိတဲ့ key တစ်ခုဟာ ဘယ်သူမဆို decompile လုပ်ပြီး ဖတ်နိုင်တဲ့ app binary ထဲမှာ ပါသင့်တာ မဟုတ်ပါဘူး။ Fix ကတော့ အဲဒီ key လိုအပ်တဲ့ call တိုင်းကို app ကိုယ်ပိုင် backend နောက်ကွယ်ကို ရွှေ့ပေးလိုက်တာပါ၊ ဒါဆိုရင် privileged credential က server ကနေ ဘယ်တော့မှ ထွက်မသွားတော့ပါဘူး။
First launch မှာ permission အားလုံး
Camera, contacts, precise location အားလုံးကို user က ဘာမှမလုပ်ရသေးခင်ကတည်း တောင်းထားပါတယ်။ Fix ကတော့ permission တစ်ခုချင်းစီကို လိုအပ်တဲ့ feature ကို တကယ်သုံးမယ့်အချိန်မှာပဲ ဘာအတွက်လိုလဲဆိုတာ အတိုချုပ် ရှင်းပြပြီး တောင်းတာပါ။
Plain storage ထဲက Token
Plain local storage ထဲမှာ ထားရှိတဲ့ access token ကို device ပေါ်က file access ရှိတဲ့ ဘာမဆို ဖတ်နိုင်ပါတယ်။ Fix ကတော့ platform ရဲ့ secure storage - iOS ပေါ်က Keychain (သို့) Android ပေါ်က Keystore-backed storage - ထဲကို ရွှေ့ပေးတာပါ၊ ဒါဆိုရင် operating system ကိုယ်တိုင်က ဖတ်ခွင့်ကို ထိန်းချုပ်ပေးပါလိမ့်မယ်။
Log ထဲသို့ Auth Response
Auth response အပြည့်အစုံကို ဖော်ပြတဲ့ debug log line တစ်ကြောင်းတည်းက token တွေကို crash report နဲ့ log aggregator တွေဆီ တိုက်ရိုက်ပို့ပေးလိုက်တာပါ။ Fix ကတော့ log ထုတ်ခင်မှာ sensitive field တွေကို redact လုပ်တာပါ၊ production build မှာသာမက build အားလုံးမှာပါ။
Client-only ဈေးနှုန်းစစ်ဆေးမှု
ပြင်ဆင်ထားတဲ့ app (သို့) ကြားဖြတ်ဖမ်းယူထားတဲ့ request တစ်ခုက ဈေးနှုန်းကို client-side မှာသာ စစ်ရင် ဘယ်လိုလျှော့စျေးမှမဆို ပို့နိုင်ပါတယ်။ Fix ကတော့ ဈေးနှုန်းနဲ့ အရည်အချင်းကို ကုန်ကျစရိတ်မဖြတ်ခင် server ပေါ်မှာ အမြဲပြန်စစ်ဆေးတာပါ။
အတူတူ စမ်းရေးကြည့်မယ်
function auditMobileAppSetup(setup) {
const issues = [];
if (setup.hasPrivilegedSecretBundled) {
issues.push({
area: "secrets",
problem: "A privileged secret is bundled inside the app binary.",
fix: "Move any call needing this secret to your backend; never ship privileged keys client-side."
});
}
if (setup.requestsAllPermissionsAtLaunch) {
issues.push({
area: "permissions",
problem: "Sensitive permissions are requested all at once at first launch.",
fix: "Request each permission just-in-time, when the feature that needs it is used."
});
}
if (setup.tokensInPlainStorage) {
issues.push({
area: "storage",
problem: "Access tokens are stored in plain, unencrypted local storage.",
fix: "Store tokens in platform secure storage (Keychain on iOS, Keystore-backed storage on Android)."
});
}
if (setup.logsAuthTokens) {
issues.push({
area: "logging",
problem: "Debug logs print the full authentication response, including tokens.",
fix: "Redact sensitive fields before logging, in every build, not just production."
});
}
if (!setup.priceValidatedServerSide) {
issues.push({
area: "trust boundary",
problem: "Price/discount is only checked in the client, with no server re-validation.",
fix: "Always re-validate price and eligibility on the server before charging."
});
}
return {
appName: setup.appName || "unnamed app",
issueCount: issues.length,
issues,
verdict: issues.length === 0 ? "PASS - no flagged issues" : "FAIL - see issues"
};
}
// The flawed QuickCart setup described in this lesson:
const quickCartFlawed = {
appName: "QuickCart",
hasPrivilegedSecretBundled: true,
requestsAllPermissionsAtLaunch: true,
tokensInPlainStorage: true,
logsAuthTokens: true,
priceValidatedServerSide: false
};
// A properly configured app, for contrast:
const quickCartFixed = {
appName: "QuickCart (fixed)",
hasPrivilegedSecretBundled: false,
requestsAllPermissionsAtLaunch: false,
tokensInPlainStorage: false,
logsAuthTokens: false,
priceValidatedServerSide: true
};
console.log(JSON.stringify(auditMobileAppSetup(quickCartFlawed), null, 2));
console.log(JSON.stringify(auditMobileAppSetup(quickCartFixed), null, 2));QuickCart ရဲ့ flawed setup ပေါ်မှာ auditMobileAppSetup ကို run ရင် issueCount: 5 နဲ့ verdict: "FAIL - see issues" ကို ပြန်ပေးပြီး၊ ပြဿနာငါးခုလုံးကို area, problem, fix နဲ့အတူ issues array ထဲမှာ list လုပ်ပေးပါတယ်။ Fixed setup ပေါ်မှာ run ရင်တော့ - priceValidatedServerSide ကလွဲရင် flag အားလုံး false ဖြစ်နေတဲ့အခါ - issueCount: 0၊ issues: [] (အလွတ်)၊ verdict: "PASS - no flagged issues" ကို ပြန်ပေးပါတယ်၊ ဘာလို့ဆိုတော့ စစ်ဆေးမှုငါးခုထဲက တစ်ခုမှ trigger မဖြစ်လို့ပါ။၅ မိနစ် စမ်းကြည့်
အထက်က အဖြေလွှာကို မဖတ်မီ ကိုယ်တိုင် audit ကို စမ်းကြည့်ပါ။ ဒီ lesson ရဲ့ diagram မှာ ဖော်ပြထားတဲ့ QuickCart setup ကို ပြန်ဖတ်ပါ - အစိတ်အပိုင်းငါးခု ဖော်ပြထားပါတယ်: analytics key, permission request screen, access token သိမ်းဆည်းပုံ, debug log ဖော်ပြချက်, ပြီးတော့ checkout မှာ ဈေးနှုန်း စစ်ဆေးပုံ။ ဒီငါးခုစလုံးအတွက် ဒါနှစ်ခုကို ရေးချပါ - (၁) ဘာမှားနေလဲ၊ (၂) ဒါကို ဘယ်လိုပြောင်းလဲပစ်မလဲ (ဘာလို့ အန္တရာယ်ရှိတယ်ဆိုတာသာ မဟုတ်ဘဲ)။ ပြီးရင် Practical အပိုင်းက အဖြေလွှာနဲ့ နှိုင်းယှဉ်ကြည့်ပါ - ငါးခုစလုံး ရှာတွေ့ပါသလား၊ သင်အကြံပြုတဲ့ fix တွေက တကယ့် fix ရဲ့ ဦးတည်ချက်နဲ့ ကိုက်ညီပါသလား၊ (သို့) symptom ကိုသာ ဖော်ပြမိသလား။
သတိလေးတစ်ချက်
'ဒါလုံခြုံမှုမရှိဘူးထင်တယ်' ဆိုပြီး ရပ်ထားခြင်း၊ တိကျတဲ့ fix ကို မဖော်ပြခြင်း - ဘာပြောင်းရမလဲ မပြောသေးတဲ့ audit ဟာ မပြီးသေးပါဘူး။
Audit ကို တစ်ကြိမ်တည်းလုပ်ရမယ့် task အဖြစ် သတ်မှတ်ခြင်း - အမှန်က app setup ပြောင်းတိုင်း ထပ်ပြီး run ရမယ့် checklist တစ်ခုပါ။
OWASP Mobile Application Security — How Mobile Apps Work