The Definitive Guide to Network Privacy

ช่วงนี้มีคนเขียนถึงเรื่อง DNS Privacy เยอะ เลยควรจะเขียนบล็อคสักหน่อยว่าจริงๆ ควรจะดูอะไรบ้าง

tl;dr

  1. ถ้ากลัวทุกอย่าง ใช้ VPN ที่ไว้ใจได้ตลอดเวลา (แต่จะแน่ใจได้ยังไงว่า VPN ไว้ใจได้?)
  2. ถ้ากลัวผู้ให้บริการอินเทอร์เน็ตรู้ว่าเข้าเว็บชื่ออะไร เทคโนโลยีปัจจุบันดีสุดคือใช้ VPN แต่เร็วๆ นี้เราอาจจะใช้ DNS over HTTPS/TLS คู่กับเข้าเว็บเฉพาะ HTTPS ก็อาจจะพอแล้ว
  3. ถ้าใช้เน็ตแล้วพอใจอยู่แล้วปิดหน้านี้ไปก็ได้ไม่ต้องอ่านหรอก

What we Send

เวลาเราจะอ่านเว็บหนึ่ง สิ่งที่เราส่งออกจาก network ภายในบ้าน ได้แก่

  1. DNS Lookup คือถามว่า Web นี้ IP อะไร
  2. IP Connection คือเชื่อมต่อไปยัง IP นั้นๆ
  3. Data คือข้อมูลที่ส่งไปยังเว็บนั้น

ถ้าต้องการ Privacy มากขึ้น เราก็ควรจะหาวิธีซ่อน 1-3 ไม่ให้ผู้ดักฟังกลางทาง (man in the middle) แอบอ่านข้อมูลได้ ผู้ดักฟังตรงนี้อาจจะเป็นคนที่ดัก WiFi เราอยู่, เจ้าของร้านกาแฟ, ค่ายอินเทอร์เน็ต, Single Gateway ก็ได้

DNS Lookup

เมื่อเราเชื่อมต่อไปยังเว็บหนึ่งเราจะต้องถามว่าเว็บนี้ IP อะไร ยกตัวอย่างเช่น ถ้าจะเข้าบล็อค blog.whs.in.th. สิ่งที่เราจะต้องทำคือถาม server ไล่มาจากขวา (ใหญ่ที่สุด) ไปซ้าย

เริ่มจากขวาสุดคือ . ซึ่งปกติเราละไว้ จุดตัวแรกนี้เราจะไปถาม Root Server ที่เก็บข้อมูลเฉพาะโดเมนที่อยู่หน้า . ไปหนึ่งลำดับเท่านั้น (เช่น th, com, org แต่ไม่รวมถึง *.th)

เนื่องจากจะเป็นปัญหาไก่กับไข่ว่าเราจะไปหา IP ของ Root Server มาจากไหน server ในชุดนี้เลยกำหนดเป็น fix IP ทั้งหมด ซึ่งเราสามารถ Download รายชื่อได้ที่ https://www.iana.org/domains/root/servers ปัจจุบันมีอยู่ 13 IP ตั้งชื่อว่า a-m ซึ่งแต่ละ IP ก็จะมี server จำนวนมากรับอยู่ด้านหลัง

เราจะต้องติดต่อไปหา Root สักตัวหนึ่งเพื่อถามว่า th. ใช้ IP อะไร จากนั้นก็ถาม th. ว่า in.th. ใช้ IP อะไร วนไปเรื่อยๆ จนได้ครบ blog.whs.in.th.

ปัญหาก็คือ การทำแบบนี้เสียเวลามากเพราะต้องทำหลายทอด และทุกคนที่เข้าเว็บก็ต้องทำหมด จึงมีผู้ให้บริการ Recursive Resolver ก็คือเราส่ง blog.whs.in.th. ไปปุ๊บเค้าก็ทำขั้นตอนด้านบนให้หมด แล้วให้ IP สุดท้ายเรามาเลย ez

ที่เยี่ยมไปกว่านั้นคือ Recursive Resolver จะ cache ผลลัพท์ไว้ด้วย ทำให้ถ้ามีผู้ใช้งาน Resolver เดียวกันจำนวนมากก็ยิ่งทำให้เน็ตของทุกคนที่ใช้เร็วขึ้น เพราะไม่ต้องเสียเวลาไล่ใหม่หมดทุกครั้งแต่ตอบจาก cache ได้ทันที

ผู้ให้บริการ Recursive Resolver ที่เป็นที่รู้จักก็เช่น

  • ปกติแล้ว ISP จะมี Recursive Resolver ให้ เช่น True ใช้ 203.144.207.29 และ 203.144.207.49 หรือบน AWS ก็ใช้ 169.254.169.253
  • Google Public DNS ที่ 8.8.8.8 และ 8.8.4.4
  • Cloudflare Resolver ที่ 1.1.1.1 และ 1.0.0.1
  • OpenDNS ที่ 208.67.222.222 และ 208.67.220.220
  • AdGuard DNS ที่ 176.103.130.130 และ 176.103.130.131

ทีนี้ถ้าเราต้องการ Privacy มากขึ้น เราควรจะมอง Threat Model ที่เกิดขึ้นก่อนว่าเราจะป้องกันจากใครบ้าง?


คนแรกที่เราต้องการป้องกันคือป้องกันจาก ISP ของเราที่ดักฟังอยู่บนเส้นทางของเรา เพราะ ISP สามารถทำได้ทั้งเก็บข้อมูล และแก้ไขข้อมูล (เช่นการ Block เว็บ)

ในอดีตยังไม่มีเทคโนโลยีป้องกัน DNS เท่าไรนัก แต่หลังจากความพยายามหลายครั้งแล้วเราก็มีมาตรฐาน DNS over TLS และ DNS over HTTPS ออกมา

DNS over TLS แปลว่า เอา DNS protocol วิ่งอยู่บน TLS ซึ่งเป็นระบบเข้ารหัสเช่นเดียวกับที่ HTTPS ใช้อยู่ (HTTPS ก็คือ HTTP protocol วิ่งอยู่บน TLS)

DNS over HTTPS แปลว่าเอา DNS protocol แปลงเป็น web request แล้วยิงไปหา server HTTPS (ที่อยู่บน TLS อีกที)

ฟังดูแล้ว DNS over TLS จะดูดีกว่าเพราะจำนวนชั้นน้อยกว่า แต่การกระจายโหลดบน HTTPS เป็นปัญหาที่ถูกศึกษามานานหลายปีมาก (เพราะเว็บไซต์ก็อยู่บน HTTPS ทั้งนั้น) ทำให้ผู้ให้บริการบางเจ้ายังคิดว่า DNS over HTTPS นั้นให้บริการง่ายกว่า

ปัจจุบันผู้ให้บริการทั้ง Google Public DNS, Cloudflare DNS, OpenDNS, Adguard ก็มีบริการ DNS over TLS หรือ HTTPS กันหมดแล้ว ย้ำเพื่อความชัดเจนว่าเปลี่ยน DNS ในระบบเป็นผู้ให้บริการเหล่านี้ไม่ได้แปลว่าเข้ารหัส DNS แล้ว ต้องใช้โปรแกรม client เฉพาะทางเท่านั้น

ใส่ 8.8.8.8/1.1.1.1 ในหน้านี้ไม่ได้ทำให้เน็ตคุณปลอดภัยขึ้น

ทั้งนี้ถึงแม้ในฝั่ง Recursive Resolver จะเริ่มเห็นการเข้ารหัสแล้วก็ตาม แต่ขั้นตอนการ Resolve ที่ไปถามต้นทางยังไม่มีการเข้ารหัส ก็เลยจะไม่แนะนำให้ตั้ง Recursive Resolver เองเท่าไรถ้าไม่มั่นใจว่าเน็ตขาออกที่ Resolver ของเรามีการ log หรือไม่


คนที่สองที่เราต้องการป้องกันคือป้องกันจาก Recursive Resolver ที่เราใช้อยู่ เนื่องจากเค้าจะเห็น Query ทั้งหมดของเรา สิ่งที่จะเกิดขึ้นมีสองอย่างคือ

หนึ่ง ดัก Query เราไปใช้วิเคราะห์ข้อมูล ซึ่งผมมักจะเห็นคนใช้ Google DNS กลัวข้อนี้แล้วไปใช้ Cloudflare Resolver แทน ซึ่ง Google เองก็แจ้งว่ามีการสุ่ม Log โดเมนที่มีการ Query ไว้แต่ไม่เก็บถึง IP Address ไว้ถาวร (มากที่สุดคือเมืองและ ISP)

ส่วน Cloudflare ก็มีการเก็บชื่อโดเมนทั้งหมดไว้เช่นกัน แต่ไม่มีข้อมูล Demographics หรือจำนวนครั้งที่เข้า

สอง ปลอมแปลงผลลัพท์ ซึ่งมีทั้งข้อดีและข้อเสีย ข้อเสียที่เห็นชัดๆ คือถ้าใครเคยใช้ OpenDNS จะเห็นว่าเวลาเข้าเว็บที่ไม่มีอยู่จริงจะแสดงเป็นหน้าโฆษณาแทน เนื่องจาก OpenDNS จะเปลี่ยนผลการค้นหาของเว็บไม่มีจริงไปเป็นเว็บ OpenDNS (ปัจจุบันเลิกแล้ว)

Image result for opendns guide
ภาพยังเก่าเลย

ข้อดีคือเค้าอาจจะมีบริการเสริมให้เราได้ เช่น OpenDNS มีบริการแก้โดเมนสะกดผิดให้ หรือ AdGuard ก็จะบล็อคโดเมนโฆษณาให้ (คือเว็บมีจริงแต่ AdGuard จะคืนว่าไม่มีเว็บนั้นแทน)

ตรงนี้ก็คงต้องพิจารณาเลือก Recursive Resolver ที่ไว้ใจได้ให้ดี


คนที่สามที่เราต้องการป้องกันคือผู้ให้บริการ DNS สำหรับเว็บไซต์นั้นๆ เช่นบล็อคนี้ผม Host บน server ผมเองก็จริง แต่ DNS Server ใช้ของ Google Cloud DNS แปลว่าเวลามีคนเข้าบล็อคนี้ Google จะรับรู้ด้วย

จุดที่น่าสนใจคือ Recursive Resolver จะมีการส่ง IP ของเราบางส่วนไปยังผู้ให้บริการ DNS ด้วย (EDNS Client Subnet) คือถึงแม้ว่าคนที่เข้าเว็บนี้จะใช้ OpenDNS เข้า แล้ว Server Google Cloud DNS เห็นว่า OpenDNS ติดต่อเข้ามาก็จริง แต่ OpenDNS จะให้ IP เราบางส่วนไปด้วย (อาจจะปิดหลักสุดท้ายให้ เช่น 171.232.31.xxx)

เหตุผลที่ต้องทำแบบนี้เพราะบางครั้ง IP ของ server ที่เราจะเข้านั้นขึ้นอยู่กับ IP ของเราด้วย เช่น ถ้าเราเข้าจากประเทศไทยอาจจะเอา server ภายในประเทศให้ ถ้าเข้าจากอเมริกาก็จะได้ IP ที่อเมริกา ไปจนถึงบางครั้งเป็นระดับ ISP เลยทีเดียว ซึ่งถ้าหากไม่ส่งไปแล้วเค้าจะอ้างอิงตาม IP ของ Recursive Resolver แทนซึ่งอาจจะอยู่ห่างไกลกับผู้ใช้งานมากเลย (เช่น Google Public DNS อาจจะให้ server สิงคโปร์มา)

จากรายการด้านบนที่ให้ จะมีแค่ Cloudflare DNS และ AdGuard ที่ไม่ส่งข้อมูลนี้ ก็เป็นผลดีต่อ Privacy แต่ข้อเสียคืออาจจะทำให้เข้าเว็บได้ช้าลงเพราะเค้าจะให้ server ที่อยู่ใกล้ขึ้น

โดยส่วนตัวแล้ว ผมไม่ได้ใส่ใจเรื่องนี้มากเพราะถือว่าถ้าเราไว้ใจเจ้าของเว็บเราก็ต้องไว้ใจผู้ให้บริการที่เค้าเลือกด้วย ก็เลยจะไม่แนะนำผู้ให้บริการด้านบนเพราะทำให้เน็ตช้าลงนั่นเอง

IP Connection

หลังจากเราทราบ IP ของเว็บแล้ว เราก็จะติดต่อไปยังเว็บนั้นๆ ซึ่งแน่นอนว่าเราต้องบอก IP ไปให้ ISP ของเราทราบเพื่อเชื่อมต่อ (เหมือนจะโทรหาเพื่อนแต่ไม่กดเบอร์ก็ไม่ได้นะ…)

ตรงนี้แน่นอน ISP จะทราบ IP ที่เราจะเชื่อมต่อด้วย ไม่มีทางเลี่ยงได้

วิธีที่จะป้องกันได้ก็คือการใช้ VPN หรือ Proxy ซึ่งจะทำให้ ISP เราเห็น IP เป็น IP ของ VPN เพียงอย่างเดียว แต่ปัญหาที่ตามมาก็คือผู้ให้บริการ VPN ก็จะเห็น IP ของเว็บที่เราจะเชื่อมต่อด้วย

ตรงนี้ก็แล้วแต่จะตัดสินใจครับว่าจะยอมให้ใครเห็นดี แล้วต้องตัดสินใจให้กับทุกที่ที่เราจะใช้อินเทอร์เน็ตเลยด้วย

  • เน็ตที่บ้านเราจะยอมให้ ISP เราเห็นมั้ย?
  • เน็ตที่ร้านอาหาร เราจะยอมให้เจ้าของร้านและ ISP เค้าเห็นมั้ย?
  • เน็ตที่ออฟฟิศเราจะยอมให้ system admin เราเห็นมั้ย? (แล้วถ้าเราไม่ยอม system admin จะโวยวายเรามั้ย?)

นอกเหนือไปจากนี้แล้วการเชื่อมต่อบางประเภทยังถูกดักฟังได้อีกด้วย เช่น WiFi ที่ถึงแม้จะล็อครหัสแต่ถ้าทราบรหัส (เช่นร้านอาหารที่ติดรหัสไว้ข้างฝา) ก็สามารถถอดรหัสข้อมูลที่วิ่งอยู่ในอากาศได้

Data

เมื่อเชื่อมต่อแล้ว เราก็จะส่งข้อมูลทุกอย่างที่เราเชื่อมต่อไปให้ปลายทาง ตรงนี้เช่นเคย ISP มองเห็นและแก้ไขข้อมูลได้ทุกอย่าง

แต่หลังจากยุค Snowden แล้ว เว็บไซต์ต่างๆ เริ่มมีการเข้ารหัสข้อมูลมากขึ้นโดยใช้ HTTPS ทำให้ ISP มองเห็นข้อมูลน้อยลง แต่ก็ไม่ใช่ว่ามองไม่เห็นเลย

ถึงแม้จะใช้ HTTPS แล้ว ข้อมูลหนึ่งที่ผมค่อนข้างกังวลมากคือ Server Name Indication (SNI) ซึ่งที่มาที่ไปมันเป็นแบบนี้ครับ

สัก 15 ปีที่แล้วการที่เว็บเว็บหนึ่งจะมี HTTPS ใช้ค่าใช้จ่ายสูงมาก เพราะต้องขอ IP แยกของแต่ละเว็บไป ไม่อย่างนั้นเวลาเชื่อมต่อมาแล้ว เว็บจะไม่รู้ว่าต้องใช้ใบรับรอง HTTPS ของเว็บไหน (เพราะ IP หนึ่งอาจจะมีหลายร้อยเว็บอยู่ก็ได้)

ต่อมาก็เลยมี SNI เกิดขึ้น โดยเมื่อเราเชื่อมต่อไปที่ IP แล้วเราก็บอกก่อนว่าจะเข้าเว็บไหน (บอกเฉพาะชื่อเว็บ ไม่รวมถึง Path นะ) ฝั่งเว็บก็จะเอาใบรับรองของเว็บที่ถูกต้องมาให้ ทำให้ไม่จำเป็นต้องใช้ IP แยกแล้ว แค่ฝั่ง client ต้องรองรับ SNI ด้วย ซึ่งก็ประมาณยุค Windows Vista

ปัญหาคือตอนที่เราจะบอกชื่อเว็บนั้นเรายังไม่รู้เลยว่าจะเข้ารหัสให้เว็บไหนอ่าน เราก็เลยส่งชื่อเว็บไปเป็น plain text ธรรมดา !! เท่านี้ก็เสร็จโจร

ในปัจจุบันมีความพยายามเข้ารหัส SNI เรียกว่า ESNI แต่ก็ยังเพิ่งเริ่ม ตอนนี้ยังไม่มี Browser เวอร์ชั่น stable ตัวไหนเลยที่รองรับ และเช่นกัน เว็บปลายทางที่จะเชื่อมต่อก็ต้องรองรับ ESNI ด้วย


เช่นเดียวกับ IP ถ้าเราต้องการป้องกันไม่ให้เห็นข้อมูล SNI หรือข้อมูลทั้งหมด (กรณีเว็บไม่มี HTTPS) วิธีเดียวที่ทำได้ในตอนนี้คือใช้ VPN หรือ Proxy

Choosing a VPN

อย่างที่บอกไปว่าการใช้ VPN ไม่ได้ช่วยให้เราปลอดภัยขึ้นทันที แต่เพียงแค่ย้ายความเชื่อใจจาก ISP ของเราไปอยู่บน VPN (และผู้ให้บริการอินเทอร์เน็ตของ VPN) อีกที ดังนั้นจึงควรจะให้ความสำคัญกับการเลือก VPN มากๆ

Free VPN

ปัจจุบันมีผู้ให้บริการฟรีหลายเจ้า ทั้งที่ขายว่าเป็น VPN เลยและไม่ใช่ เช่น Chrome Data Saver

แต่ VPN ไม่ได้ฟรี มีต้นทุน แล้วเค้าจะคืนทุนได้อย่างไร?

กรณีดังที่เคยเกิดขึ้นคือ Onavo VPN ซึ่งให้บริการฟรี และถูก Facebook ซื้อไป แล้ว Facebook ก็ใช้ข้อมูลที่วิ่งผ่าน VPN สำรวจตลาดแอพมือถือและต่อมาก็ซื้อ WhatApps ไปโดยใช้ข้อมูลตรงนี้

ดังนั้นผมคิดว่าการใช้ VPN ฟรีนั้นแย่ยิ่งกว่าไม่ใช้ VPN เสียอีก

Tor

Tor จะจัดกลุ่มพิเศษหน่อยถึงแม้จะเป็น Free VPN เช่นกัน

Tor เป็นผลงานของกองทัพเรือสหรัฐ แต่ปัจจุบันถูกพัฒนาโดยนักพัฒนา open source ผมเข้าใจว่ากองทัพสหรัฐใช้ส่งข้อมูลของสายลับ และเพื่อให้แนบเนียนเลยต้องเปิดให้คนทั่วไปใช้ด้วยเพื่อไม่ให้คนที่ใช้ Tor ถูกจับตามองเป็นพิเศษ

ิวิธีการทำงานของ Tor เปรียบเสมือน Proxy ต่อกันเป็นทอดๆ คือเมื่อเราจะติดต่อกับ Jane (ในภาพ) เราจะสุ่มเลือก Tor node มาจำนวนหนึ่ง (สมมุติว่าคือ A, B, C) และ Exit node อีกหนึ่งเครื่อง (สมมุติว่าเป็น E)

จากนั้นเราเข้ารหัสข้อมูลเป็นชั้นๆ ดังภาพแล้วส่งทั้งหมดให้ A, A จะถอดรหัสแล้วทราบว่าต้องส่งให้ B พอ B ถอดรหัสจะรู้ว่าส่งให้ C ไปเรื่อยๆ จนกระทั่งถึง E ก็จะทราบ IP ของเว็บไซต์ปลายทางที่ต้องส่งให้

วิธีนี้ทำให้ A, B, C ที่เป็น Relay node ระหว่างทางไม่สามารถทราบเส้นทางหรือเนื้อหาได้ ทราบเพียงแค่ว่าใครส่งมาให้ และใครเป็นคนถัดไป ส่วน E จะมองเห็นเนื้อหาด้วยเพราะต้องส่งข้อมูลนี้ออกจากเครือข่าย Tor

เว็บไซต์ปลายทางเมื่อได้รับข้อมูลจาก E ก็จะทราบ IP ต้นทางเพียงว่ามาจาก E เท่านั้น ดังนั้นการรัน Exit node จะมีความเสี่ยงเพราะถ้าหากเป็นข้อมูลที่ประสงค์ร้ายแล้วเว็บไซต์ก็ต้องดำเนินการกับ Exit node เท่านั้น


สำหรับผู้ใช้งาน Tor นั้น ในทางเทคนิคแล้ว Tor ค่อนข้างมีความปลอดภัยสูง เพราะไม่มีใครสามารถทราบต้นทางได้ว่าข้อความมาจากใคร (แม้แต่ E ก็ไม่ทราบ) มีเพียงเฉพาะคนที่เราเชื่อมต่อตรงไปเท่านั้น (คือ A) ที่ทราบ แต่ก็จะไม่ทราบเนื้อหาและปลายทาง

ข้อเสียของ Tor คือเนื่องจากเชื่อมต่อหลายทอด และผู้ให้บริการเป็นอาสาสมัครก็จะไม่ได้มีความเร็วสูงเท่าไรนักจึงไม่เหมาะกับการใช้ในชีวิตประจำวันเท่าไร (นอกจากต้องการความเป็นส่วนตัวสูงมากและยอมรับความเร็วที่ลดลงมากได้) และมีโอกาสที่ Exit node จะดักฟังข้อมูลของเราอยู่

นอกไปจากนี้ ยังมีความเป็นไปได้ว่ามีหน่วยงานของรัฐรัน node อยู่เป็นจำนวนมากจนอาจทำให้ทั้ง A, B, C, E เป็นเจ้าหน้าที่รัฐทั้งหมด กรณีนี้ก็ทำให้สามารถทราบต้นทางของข้อมูลได้ (และเชื่อว่ามีการใช้เทคนิคนี้นำไปสู่การจับกุมแล้ว)

1.1.1.1 Warp

Cloudflare เพิ่งออก Warp มาได้ไม่นาน มีทั้งแบบฟรีและเสียเงิน ราคาไม่แพงอีกด้วย

ข้อเสียของ Warp ในตอนนี้คือยังต่อผ่านคอมไม่ได้ ในอนาคตคาดว่าน่าจะมี

ประเด็นที่ควรทราบคือ Warp ไม่กัน IP เราจากเว็บไซต์ต้นทาง ถ้าเว็บต้นทางใช้ Cloudflare แล้ว Cloudflare จะส่ง IP เราให้เว็บไซต์ต้นทาง (ส่วนถ้าเว็บต้นทางไม่ได้ใช้ ยังเป็นข้อจำกัดทางเทคนิคอยู่ที่ทำไม่ได้ แต่เค้าอยากจะส่งให้นะ) เนื่องจาก Warp ตั้งใจจะให้เราป้องกันตัวจาก ISP ที่ไม่ปลอดภัย แต่ไม่ได้ป้องกันจากเว็บไซต์ปลายทาง

ถ้าไม่เชื่อ ลองต่อ Warp แล้วเข้า whatismyipaddress.com จะเห็นว่า IP ยังเป็น IP เราอยู่เหมือนเดิม (เว็บ check ip นี้ใช้ Cloudflare ถ้าจะลองเช็คกับเว็บอื่น อย่าลืมดูก่อนว่าเค้าใช้ Cloudflare หรือเปล่า)

บล็อคนี้เลยตั้งใจจะไม่ใส่ Affliate Link ของ Warp เพราะผมคิดว่าถ้าคุณกำลังมองหา Privacy ของดีกว่านี้มีเยอะ (แต่ถ้าอยากจะเข้าเว็บนอกเร็ว Warp+ อาจจะตอบโจทย์ก็ได้นะ?)

Self hosted

บางคนเชื่อว่าวิธีที่ดีที่สุดในการทำ VPN คือเช่า VPS มาโฮสต์ด้วยตัวเอง อาจจะใช้ DigitalOcean ที่ Bandwidth ถูก หรือใช้ AWS/Google Cloud ก็สุดแท้แต่จะมีงบประมาณ

ข้อเสียคือผู้ให้บริการ VPS จะมีข้อมูลของเราจากการชำระเงิน และ IP นั้นจะมีแต่เราใช้เพียงคนเดียว ซึ่งถ้าคิดจะป้องกันจาก ISP แล้วพวกนี้ไม่น่าจะเป็นปัญหาเท่าไรนัก

ถ้าต้องการติดตั้ง VPN บน VPS เอง วิธีที่ง่ายและแนะนำให้ใช้งานคือใช้ Algo VPN หรือ Streisand ซึ่งเป็นสคริปต์สำหรับติดตั้ง VPN สำเร็จรูป

Commercial VPN

มาถึงหัวข้อสุดท้ายแล้ว ก่อนจะเลือกผู้ให้บริการ VPN อยากจะย้ำประเด็นข้างบนเสียก่อน

  1. นึกภาพก่อนว่าเราต้องการป้องกันจากอะไร (Threat Model) แล้วจะได้เข้าใจว่าต้องสนใจอะไรบ้าง
  2. การใช้ VPN ไม่ได้แปลว่าปลอดภัย 100% แต่แปลว่าเรากำลังย้ายความเชื่อใจจากผู้ให้บริการอินเทอร์เน็ตมาที่ผู้ให้บริการ VPN
  3. ผู้ให้บริการอินเทอร์เน็ตยังคงเห็นว่าเราต่อ VPN

ถ้าอ่านแล้วคิดว่ายังจำเป็นต้องใช้ VPN อยู่ ก็สมัครใช้บริการได้ครับ

Edit: หัวข้อนี้เดิมทีมีรีวิวผู้ให้บริการ VPN หลายเจ้าที่ได้รับความนิยม แต่เพื่อให้บทความมันไม่เก่า (ผู้ให้บริการบางทีก็เปลี่ยนแปลงการให้บริการไป) และไม่ส่งเสริมการแนะนำผู้ให้บริการที่ไม่ดี แนะนำให้เลือกจาก PrivacyTools.io ครับ

Wall of Text #8: เวลา

จริงๆ ก็หมด content แล้ว เพราะน้องที่ทำให้ผมเริ่มซีรีส์นี้เค้าหนี 100 days of code ไปเที่ยวแล้ว แต่พอดีว่าเจอบั๊ก เลยอยากเล่าเรื่องเวลาสักหน่อยเพราะเป็นเรื่องที่น่าปวดหัวมาก

ถ้าขี้เกียจอ่าน ขอแนะนำให้ดูคลิปนี้ซึ่งคงจะเล่าได้สนุกกว่าที่ผมจะเขียนเยอะ

สมัยนึงผมคิดว่าเวลาเป็นเรื่องง่ายๆ โดยเฉพาะเมื่อมาเขียนโค้ดที่ต้องเก็บเวลาแล้วทุกคนน่าจะเคยคุ้นตากับ UNIX Time ซึ่งเก็บจำนวนวินาทีตั้งแต่ 1 มกราคม 1970

ข้อดีอย่างหนึ่งของ UNIX Timestamp คือเราสามารถหาผลต่างของ 2 เวลาได้ง่าย เพียงแค่เอามาลบกันก็จะได้จำนวนวินาทีในช่วงเวลานั้น

ปัญหามันอยู่ที่ว่า เวลาแต่ละที่ในโลกไม่เหมือนกัน…

Timezone

ครั้งหนึ่งผมก็เคยคิดว่า ลูกค้าเราอยู่ในประเทศไทยเท่านั้น ถ้าอย่างนั้นเราก็ตั้ง Timezone ทุกที่ในโค้ดเป็นบวก 7 ชั่วโมง หรือเขตเวลาของประเทศไทยก็น่าจะจบ

ปรากฏว่า ทำไปพักหนึ่งก็วุ่น เนื่องจากระบบหลายอย่างมักจะอ้างอิงจากเขตเวลาสากล (UTC) อยู่ดี เช่น UNIX Time ตามมาตรฐานนั้นกำหนดให้ใช้เวลาที่เขตเวลา UTC แล้ว Library มันก็จะไม่ถามเราเลยว่าเอาเขตเวลาอะไร

เนื่องจากเราเขียนโค้ดโดย assume เขตเวลาประเทศไทยแล้ว เมื่อ user กรอกข้อมูลมาว่าตั้งเวลาแจ้งเตือน 2019-07-06 14:00:00 เราเอาเข้า function convert เป็น UNIX Time มันก็คืนให้เราเป็น 1562421600 ซึ่งก็เป็นเวลาที่ถูกต้องแต่เขตเวลาเป็น UTC พอแปลงเป็นเวลาไทยคือ 3 ทุ่ม แทนที่จะเป็นบ่ายสองตามที่ตั้งใจไว้

สองคือการเก็บวันอย่างเดียวก็ยุ่งยากและมีปัญหา… เพราะถ้าเราเก็บเป็น UNIX Timestamp โดยกำหนดให้เวลาเป็น 0 หมด (เช่น 2019-07-16 00:00:00) ถ้าเราดันไปใช้ค่าเวลานั้นในฟังค์ชั่นที่รับข้อมูลเป็น Date + Time แล้ว มันอาจจะแปลงเขตเวลากลับเป็น UTC ทำให้กลายเป็นวันก่อนหน้าเวลา 17:00น. พอเราแปลงกลับเป็นวันที่อย่างเดียว ก็ผิดวันซะอย่างนั้น

Always use Timezone

Django สอนผมไว้ว่า เปิด Timezone เหอะ สมัยนึงมันเคยปิดได้ ตอนนี้ปิดไม่ได้แล้ว แล้วมันจะเตือนเสมอถ้าเราใส่เวลาไปโดยไม่บอกเขตเวลา

เสร็จแล้วจะทำอะไรๆ มันจะง่ายมาก คือเราไม่ต้องไปนั่งเช็คว่า function นี้ return ค่าเป็นเขตเวลาอะไร ขออย่างเดียวว่าบอกเขตเวลามาด้วย แล้วเราจะเลิกพะวงทันทีว่าเราใช้เขตเวลาที่ถูกอยู่หรือเปล่านะ

ทุกวันนี้ที่ไล่แก้บั๊กอยู่ ส่วนมากก็จะอยู่สองกรณีนี้แหละ คือ กำหนดเขตเวลาไม่ถูกต้อง หรือพยายามแปลงวันที่อย่างเดียวไปเข้าระบบวันที่ + เวลา

Birthday

ปัญหาถัดมาคือวันเกิด ซึ่งปวดหัวมาก เพราะคน Gen Y วันเกิดสามารถแทนด้วย UNIX Timestamp ได้เป็นเรื่องปกติ เราก็ออกแบบโปรแกรมไปอย่างนั้น พอไปใช้จริงเจอคนคนยุคก่อนหน้านี้ซึ่งเกิดก่อน 1 มกราคม 1970 แล้วจะแทนอย่างไร?

ผมก็ยังไม่เคยหาคำตอบ เพราะส่วนมากภาษาจะมีไลบรารีที่เกี่ยวข้องกับวันเวลาไว้ให้แล้ว เราก็ให้มันเก็บข้อมูลให้เลย ไม่ได้สนใจว่าด้านหลังจะทำงานอย่างไร

แต่ที่ร้ายไปกว่านั้นคือบางคนไม่ทราบวันเกิดตัวเอง ทราบเพียงแต่ปีเกิด (บางทีก็ไม่ทราบ ไปประมาณเอา) ยิ่งแล้วใหญ่ แทนในระบบไม่ได้เลย ส่วนมากผู้ใช้งานก็จะแก้ขัดโดยระบุวันที่เป็นวันที่ 1 มกราคมของปีนั้นๆ ไป แต่บางระบบก็อาจจะจำเป็นจะต้องเพิ่มช่องให้ระบุได้ว่าไม่ทราบวันที่

History is Hard

อันนี้เพิ่งเจอมาสดๆ ร้อนๆ คือเราก็คิดว่าระบุเวลา 2019-07-06 14:00:00 เขตเวลา Asia/Bangkok เราก็คิดว่ามั่นใจไม่มีทางหลุดหรอก

แต่ปรากฏว่าเวลาที่ได้จริงกลับใช้เขตเวลา +06:42 ไม่ใช่ +07:00 แล้วทำให้การประมวลผลข้อมูลที่เหลื่อมกันผิดพลาดไปซะอย่างนั้น

เอ๊ะ ยังไง เวลาประเทศไทยเป็น +07:00 ไม่ใช่หรอ ใครๆ ก็รู้??

ปรากฏว่าในประเทศไทยก่อนวันที่ 31 มีนาคม 2463 ใช้เขตเวลา +06:42 ส่วนตั้งแต่เวลา 1 เมษายนเป็นต้นไปจะใช้เขตเวลา +07:00

โอ้พระสงฆ์

ทีนี้พอเราระบุเขตเวลาเฉยๆ มันไม่ทราบว่าเราหมายถึงเขตเวลาตอนไหน เพราะถ้าเราระบุวันที่ก่อนปี 2463 จะต้องใช้เขตเวลาเดิม แต่ถ้าหลังจากนั้นต้องใช้เขตเวลาใหม่

วิธีแก้ใน Python ก็คือ ไลบรารี pytz จะมีฟังค์ชั่น localize ที่รับเวลาเข้าไปพร้อมเขตเวลา เสร็จแล้วมันจะไปคิดเอาเองว่าวันที่และเวลานี้ สถานที่นี้ควรจะใช้เขตเวลาอะไร

Astronomy is Hard

อันนี้ยังไม่เคยเจอ แต่อยากเล่าให้ฟัง

นักดาราศาสตร์ได้สังเกตว่าโลกเริ่มหมุนช้าลง จึงมีการกำหนดให้เพิ่มเวลาไปอีก 1 วินาทีตามเวลาที่กำหนด ก็คือในวันนั้น นาฬิกาจะเดิน

  • 23:59:58
  • 23:59:59
  • 23:59:60
  • 00:00:00

1 นาทีมี 61 วินาที!

ใน UNIX Time ก็จะใช้วิธีคือย้ำเวลาเดิม คือเวลาจะเดิน 1 2 3 3 4 5 .. ทำให้เวลา UNIX ไม่ตรงกับเวลาสากล

พอเวลาซ้ำแบบนี้ได้แล้ว ก็อาจเกิดปัญหาขึ้น เช่น ถ้ามีรายการหนึ่งที่ทำที่เวลา 3.98 แล้วอีกรายการทำทีหลังแต่วินาทีที่ 3 วนซ้ำ เลยได้ timestamp เป็น 3.14

เมื่อเราเอารายการมาเรียงกัน รายการทำทีหลังกลับ timestamp อยู่ก่อน และถ้าเอาเวลามาลบกันก็จะทำ leap second ตกหายไปอีกด้วย

วิธีที่ Google แก้ปัญหานี้คือ Leap Smear เนื่องจาก Google ต้องการให้รายการที่ทำทีก่อนอยู่ก่อนรายการที่ทำที่หลังเสมอ จึงกำหนดให้วันที่มีการแทรก Leap second นั้นเวลาบน Server จะเดินช้าลงเล็กน้อยตลอดทั้งวันแทน เมื่อ Leap second ผ่านไปแล้วเวลาก็จะกลับมาตรงกันอีกครั้ง วิธีนี้ทำให้เราไม่ต้องมีวินาทีซ้ำ 2 ครั้ง

ถ้าใครใช้เครื่อง Google Compute Engine เวลาบนเครื่องก็จะถูก Leap Smear อัตโนมัติ หรือถ้าอยู่ข้างนอกก็สามารถใช้ NTP Server ของ Google ได้

Monotonic Time

ปัญหานี้ใกล้ๆ กันกับปัญหาข้างบน แต่อันนี้อาจจะเจอได้ด้วยตัวเอง

คือเวลาเรา Benchmark โปรแกรม ท่าที่เราคิดก็คือ Read unix time ที่ละเอียดที่สุดเท่าที่เป็นไปได้มาเก็บไว้, ทำงานบางอย่าง แล้วเอา Unix time ตอนสุดท้ายมาลบออกกับเวลาแรกก็จะได้เวลาที่ใช้ทำงานนั้น

ฟังดูดีไม่มีปัญหา แต่ท่านี้ก็ไม่รอด…

เพราะนาฬิกาในคอมพิวเตอร์มันตั้งเวลาได้ ดังนั้นระหว่างการวัด 2 ครั้งนั้น NTP อาจจะทำงานแล้ว sync เวลาเครื่องถอยหลังกลับไป อาจจะมากถึง 1-2 วินาที พอเราอ่านค่าเวลาใหม่มันก็จะถอยหลังไปตามนั้นด้วย

ปัญหานี้อาจจะเห็นผลยิ่งชัดถ้าหาก operation นั้นใช้เวลานาน เช่น test เรื่อง Network call โปรแกรมบางตัวก็ไม่ชอบเท่าไรนักหากเวลาเดินย้อนหลัง เช่น Dovecot

วิธีแก้ไขคือ ระบบปฏิบัติการต่างๆ จะมีเวลาที่เรียกว่า Monotonic timer ซึ่งจะนับตลอดตั้งแต่เปิดเครื่องคอมพิวเตอร์ โดยการันตีว่าเดินไปข้างหน้าอย่างเดียว ตั้งเวลาถอยหลังไม่ได้

แต่มีข้อแม้คือ Monotonic timer ไม่ได้อ้างอิงกับเวลาใดๆ ทั้งสิ้น เราจึงไม่สามารถแปลงเป็นเวลาตามนาฬิกา (เรียกว่า Wallclock timer) หรือเอาไปเทียบกันระหว่างเครื่องคอมพิวเตอร์ 2 เครื่องได้ ทำได้อย่างเดียวคือใช้เปรียบเทียบระหว่าง 2 ช่วงเวลาบนคอมพิวเตอร์เครื่องนั้น

Use a Library

สุดท้ายนี้คงต้องใช้ประโยคคลาสสิค จำได้ว่าเคยพูดนานมากแล้วในเรื่อง Web Framework ซึ่งก็ยังใช้ได้กับเรื่องนี้เหมือนกัน

ถ้าจะทำ Date time manipulation เนี่ย ไปใช้ Library เถอะครับ ไปนั่งทำเองปวดหัวแน่นอน มันอาจจะเจอกับดักอื่นๆ ที่ผมยังไม่ได้เจอแล้วไม่ได้เล่าในบล็อคนี้ก็ได้

เท่าที่สังเกตดู ภาษายุคใหม่ๆ ก็จะเริ่มบังคับให้ใช้ Library มากขึ้น เช่น Rust หรือ Go ถ้าอยากทราบเวลาปัจจุบันต้องเรียกใช้ time.Now() และมันไม่ได้คืนค่าเป็น UNIX Time แล้ว ถ้ายังอยากใช้ต้องแปลงเอง