နားလည်ထားရမယ့် အချက်
TLS က အရာသုံးခု ပေးပါတယ်၊ ဒါပေမယ့် လူအများစုက နှစ်ခုပဲ မှတ်မိတတ်ကြတယ်။ Confidentiality ဆိုတာ လမ်းကြားမှာ ခိုးနားထောင်နေသူတစ်ယောက်က သင့် request ကို ciphertext အဖြစ်သာ မြင်ရမယ်လို့ ဆိုလိုတယ်။ Integrity ဆိုတာ သူတို့က bit တစ်ခုကို ပြောင်းလိုက်ရင် ဖမ်းမိမယ်လို့ ဆိုလိုတယ်။ Authenticity — မေ့လျော့ခံရဆုံးတစ်ခု — ကတော့ သင်ရိုက်ထည့်လိုက်တဲ့ domain name ကို တကယ်ပိုင်ဆိုင်တဲ့ server နဲ့သာ စကားပြောနေတာ ဖြစ်ကြောင်း အာမခံပေးခြင်း ဖြစ်တယ်။ Authenticity မပါရင် ကျန်နှစ်ခုက အဓိပ္ပာယ်မရှိတော့ဘူး — သင့် connection ကို ကြားဖြတ်ပြီး သူ့ကိုယ်ပိုင် key ကို တင်ပြလိုက်တဲ့ attacker တစ်ယောက်ဟာ သင့်ကို လုံခြုံပြီး မထိခိုက်ထားတဲ့ conversation တစ်ခုကို ပေးလိုက်တာပါပဲ — မှားနေတဲ့ လူနဲ့ ပြောနေတာသာ ဖြစ်တယ်။
Authenticity က certificate ကနေ လာတယ်။ Certificate တစ်ခုက public key တစ်ခုကို name တစ်ခုနဲ့ ချည်နှောင်ပေးပြီး Certificate Authority (CA) တစ်ခုက sign ထိုးပေးထားတယ်။ သင့် browser က အဲဒီ certificate ကို တိုက်ရိုက် မယုံကြည်ဘူး — operating system ဒါမှမဟုတ် browser နဲ့အတူ ပါလာတဲ့ root CA အနည်းငယ်ကိုသာ ယုံကြည်တယ်။ Server က သူ့ leaf certificate နဲ့ intermediate တစ်ခု (သို့) များစွာကို တင်ပြပြီး၊ client က chain ကို အပေါ်ဆီ လျှောက်တက်ကြည့်တယ် — certificate တစ်ခုစီရဲ့ issuer က နောက် certificate ရဲ့ subject နဲ့ ကိုက်လား၊ signature တစ်ခုစီ မှန်လား၊ တစ်ခုစီ validity window အတွင်း ရှိလား၊ ပြီးတော့ chain ရဲ့ ထိပ်ဆုံးက local trust store ထဲမှာ ရှိပြီးသား root တစ်ခုမှာ အဆုံးသတ်လား ဆိုတာတွေကို စစ်တယ်။ အဓိကအချက်ကတော့ root ကို server က ဘယ်တော့မှ မပို့ဘူး ဆိုတာပဲ။ ပို့ခွင့်ရှိရင် attacker တစ်ယောက်က သူ့ကိုယ်ပိုင် root ကို ပို့ပြီး သူ့ကိုယ်သူ trusted လို့ ကြေညာလိုက်လို့ ရနေမယ်။ Anchor ဆိုတာ server က လုံးဝ လွှမ်းမိုးလို့မရတဲ့ အရာ ဖြစ်ရမယ်။
ဒါကြောင့်ပဲ self-signed certificate တစ်ခုက warning ပြတာ ဖြစ်တယ်။ Cryptography အရ ဘာမှ မမှားဘူး — encryption က တကယ့် encryption ပါ။ ဒါပေမယ့် ဘာမှမရှိတဲ့ နေရာဆီ chain ဆက်နေတာမို့ browser အနေနဲ့ အဲဒီ name ကို ယုံဖို့ အခြေခံ လုံးဝ မရှိဘူး။
နောက်ဆုံးအနေနဲ့ HTTPS က လူတွေ ထင်ထားသလောက် များများ မဖုံးကွယ်ပေးဘူး။ Server က ဘယ် certificate ကို တင်ပြရမလဲ သိရဖို့ domain name သည် ClientHello ရဲ့ SNI field ထဲမှာ cleartext အဖြစ် သွားတယ်။ Packet size, timing နဲ့ သင် ဆက်သွယ်ခဲ့တဲ့ IP address တွေ အားလုံး မြင်နိုင်တယ်။ HTTPS က conversation ရဲ့ အကြောင်းအရာကို ကာကွယ်ပေးတာ ဖြစ်ပြီး conversation ဖြစ်ခဲ့တယ်ဆိုတဲ့ အချက်ကို ကာကွယ်ပေးတာ မဟုတ်ဘူး။
TLS HANDSHAKE AND THE CHAIN OF TRUST
------------------------------------
Client Server
| |
|--- ClientHello (SNI: shop.example.com) --------->|
| ^ the hostname travels in CLEARTEXT |
| |
|<-- ServerHello + certificate chain --------------|
|<-- key exchange parameters ----------------------|
| |
| [ validate: chain links, dates, hostname, |
| and a root that is already in MY trust store ] |
| |
|--- key exchange + Finished --------------------->|
|<-- Finished -------------------------------------|
|=== application data, encrypted from here ========|
CHAIN OF TRUST
+--------------------------+
| Root CA | <- pre-installed by the OS or
| "Example Root CA X1" | browser; NOT sent by server
+------------+-------------+
| signs
v
+--------------------------+
| Intermediate CA | <- sent by the server
| "Example TLS CA G2" |
+------------+-------------+
| signs
v
+--------------------------+
| Leaf certificate | <- sent by the server
| CN=shop.example.com |
+--------------------------+လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Tutorial Platform ကို domain အသစ်တစ်ခုနောက်မှာ တင်လိုက်တဲ့အခါ browser က 'NET::ERR_CERT_AUTHORITY_INVALID' ပြနေတယ် ဆိုပါစို့။ ပထမဆုံး ထင်တတ်တာက key ဒါမှမဟုတ် cipher ကို အပြစ်တင်တာ ဖြစ်ပေမယ့် တကယ့် အကြောင်းရင်းက chain ဖြစ်တာ များတယ်။ production မှာ အဖြစ်အများဆုံး version ကတော့ server မှာ leaf certificate တစ်ခုတည်းသာ ထားပြီး intermediate မထည့်ထားခြင်း ဖြစ်တယ်။ သင့် laptop မှာ အလုပ်လုပ်တယ် — ဘာကြောင့်လဲဆိုတော့ သင့် laptop က အရင် site တစ်ခုကနေ အဲဒီ intermediate ကို cache လုပ်ထားလို့ — ဒါပေမယ့် ဘယ်တုန်းကမှ မမြင်ဖူးတဲ့ phone အသစ် သို့မဟုတ် CI container မှာ ကျရှုံးတယ်။ ဖြေရှင်းနည်းက full chain file ကို serve လုပ်ဖို့ပဲ — leaf အရင်၊ ပြီးရင် intermediate များ၊ root ချန်ထား — certificate အသစ် ထုတ်စရာ မလိုဘူး။
ဒုတိယ အဖြစ်များဆုံးက ရက်စွဲ ဖြစ်တယ် — certificate သက်တမ်းကုန်သွားတာ၊ ဒါမှမဟုတ် server ရဲ့ clock မှားနေတာ။ Expiry date ရဲ့ သန်းခေါင်ကို နာရီအနည်းငယ် ကျော်သွားတဲ့ clock skew တစ်ခုက code တစ်လုံးမှ မပြောင်းဘဲ အလုပ်လုပ်နေတဲ့ site ကို ပျက်စေနိုင်တယ်။ တတိယကတော့ hostname mismatch — example.com အတွက် ထုတ်ထားတဲ့ certificate ကို www.example.com မှာ တင်ပြခြင်း၊ SAN list မှာ မထည့်ထားရင် ဒါက ကွဲပြားတဲ့ name တစ်ခု ဖြစ်တယ်။
ဒီအစီအစဉ်အတိုင်း လုပ်ပါ — chain ပြည့်စုံမှု၊ ပြီးရင် ရက်စွဲ၊ ပြီးမှ name။ အောက်က code က browser တစ်ခု လုပ်ဆောင်တဲ့ စစ်ဆေးမှု သုံးမျိုးအတိုင်း လျှောက်သွားပြထားတာမို့ failure message တစ်ခုစီဟာ သင် တွေ့ဖူးမယ့် တကယ့် browser error တစ်ခုစီနဲ့ တိုက်ရိုက် ကိုက်ညီနေတယ်။
အတူတူ စမ်းရေးကြည့်မယ်
from datetime import date
# A certificate chain as the server actually presents it: leaf first,
# then the intermediate that signed it. The ROOT is included here only
# so we can show the whole picture -- servers normally do NOT send it.
CHAIN = [
{"subject": "CN=shop.example.com", "issuer": "CN=Example TLS CA G2",
"not_before": date(2026, 1, 15), "not_after": date(2026, 4, 15),
"is_ca": False},
{"subject": "CN=Example TLS CA G2", "issuer": "CN=Example Root CA X1",
"not_before": date(2024, 3, 1), "not_after": date(2030, 3, 1),
"is_ca": True},
{"subject": "CN=Example Root CA X1", "issuer": "CN=Example Root CA X1",
"not_before": date(2020, 6, 1), "not_after": date(2040, 6, 1),
"is_ca": True},
]
# A self-signed certificate: it is its own issuer, and nothing above it.
SELF_SIGNED = [
{"subject": "CN=dev.internal", "issuer": "CN=dev.internal",
"not_before": date(2026, 2, 1), "not_after": date(2027, 2, 1),
"is_ca": False},
]
# The trust store ships with the OS or browser. The server cannot add
# to it -- this is the whole reason a chain means anything.
TRUST_STORE = {"CN=Example Root CA X1"}
TODAY = date(2026, 3, 1) # hardcoded so this example stays deterministic
def validate(chain, hostname, today):
problems = []
if chain[0]["subject"] != "CN=" + hostname:
problems.append("leaf subject does not match " + hostname)
for i, cert in enumerate(chain):
if not (cert["not_before"] <= today <= cert["not_after"]):
problems.append(cert["subject"] + " is outside its validity window")
if i > 0 and not cert["is_ca"]:
problems.append(cert["subject"] + " signed but is not a CA")
if i + 1 < len(chain):
if cert["issuer"] != chain[i + 1]["subject"]:
problems.append("chain break below " + cert["subject"])
anchor = chain[-1]["subject"]
if anchor not in TRUST_STORE:
problems.append("no trusted root: " + anchor + " is not in the store")
return problems
def report(name, chain, hostname):
print("chain: " + name + " (" + str(len(chain)) + " cert(s))")
for cert in chain:
print(" " + cert["subject"] + " <- signed by " + cert["issuer"])
problems = validate(chain, hostname, TODAY)
if problems:
print(" RESULT: REJECTED")
for p in problems:
print(" - " + p)
else:
print(" RESULT: TRUSTED")
print("")
print("validating as of " + TODAY.isoformat())
print("")
report("real CA chain", CHAIN, "shop.example.com")
report("self-signed", SELF_SIGNED, "dev.internal")
# Same good chain, but the clock has moved past the leaf's expiry.
print("same chain, but 'today' is 2026-06-01:")
for p in validate(CHAIN, "shop.example.com", date(2026, 6, 1)):
print(" - " + p)validating as of 2026-03-01
chain: real CA chain (3 cert(s))
CN=shop.example.com <- signed by CN=Example TLS CA G2
CN=Example TLS CA G2 <- signed by CN=Example Root CA X1
CN=Example Root CA X1 <- signed by CN=Example Root CA X1
RESULT: TRUSTED
chain: self-signed (1 cert(s))
CN=dev.internal <- signed by CN=dev.internal
RESULT: REJECTED
- no trusted root: CN=dev.internal is not in the store
same chain, but 'today' is 2026-06-01:
- CN=shop.example.com is outside its validity window၅ မိနစ် စမ်းကြည့်
CHAIN ထဲက intermediate certificate ကို ဖျက်လိုက်ပြီး leaf နဲ့ root နှစ်ခုတည်း ကျန်အောင် လုပ်ကြည့်ပါ၊ ပြီးရင် validator က ဘာ ပြောလဲ ကြည့်ပါ။ ပြီးရင် leaf ရဲ့ subject ကို 'CN=www.shop.example.com' လို့ ပြောင်းပြီး ပြန် run ကြည့်ပါ။ ဒီ failure နှစ်ခုဟာ တကယ့် browser မှာ ဘယ် error message နှစ်ခုနဲ့ ကိုက်ညီသလဲ ချရေးကြည့်ပါ။
သတိလေးတစ်ချက်
Leaf certificate တစ်ခုတည်းသာ serve လုပ်ပြီး intermediate မထည့်ခြင်း — သင့် browser က intermediate ကို အရင်က cache လုပ်ထားလို့ အလုပ်လုပ်နေပေမယ့် device အသစ် ဒါမှမဟုတ် CI container မှာ ကျရှုံးမယ်။
HTTPS က ဘယ် site သွားလဲ ဖုံးကွယ်ပေးတယ်လို့ ထင်ခြင်း — SNI က hostname ကို cleartext နဲ့ သယ်သွားပြီး destination IP ကတော့ ဘာဖြစ်ဖြစ် မြင်နေရတယ်။
RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3 — Computer Networking