Securing Data (การรักษาความปลอดภัยของข้อมูล)
เมื่อ เราแยกซอฟต์แวร์แบบ monolithic ของเราออกเป็น microservice ข้อมูลของเราจะเคลื่อนที่ไปมาในระบบของเรามากขึ้นกว่าเดิม มันไม่ได้แค่ไหลผ่านเครือข่ายเท่านั้น แต่ยังพักอยู่บนดิสก์ด้วย การมีข้อมูลที่มีค่ากระจายอยู่หลายที่มากขึ้นอาจกลายเป็นฝันร้ายเมื่อพูดถึงการรักษาความปลอดภัยแอปพลิเคชันของเรา หากเราไม่ระมัดระวัง ลองมาดูรายละเอียดว่าเราจะปกป้องข้อมูลของเราได้อย่างไรทั้งขณะเคลื่อนที่ผ่านเครือข่าย และขณะที่มันพักอยู่นิ่งๆ
Data in Transit (ข้อมูลขณะเดินทาง)
ลักษณะของการป้องกันที่คุณมีจะขึ้นอยู่กับ communication protocol ที่คุณเลือกใช้เป็นหลัก ถ้าคุณใช้ HTTP ยกตัวอย่างเช่น มันก็เป็นเรื่องธรรมดาที่จะใช้ HTTP ร่วมกับ Transport Layer Security (TLS) ซึ่งเป็นหัวข้อที่เราจะขยายความในส่วนถัดไป แต่ถ้าคุณใช้ protocol อื่นๆ เช่นการสื่อสารผ่าน message broker คุณอาจต้องดูว่าเทคโนโลยีนั้นๆ รองรับการปกป้องข้อมูลขณะเดินทางอย่างไร แทนที่จะดูรายละเอียดของเทคโนโลยีที่หลากหลายในพื้นที่นี้ ผมคิดว่าการพิจารณาสี่ประเด็นหลักที่เกี่ยวข้องกับการรักษาความปลอดภัยข้อมูลขณะเดินทางในเชิงทั่วไปมากกว่านั้นสำคัญกว่า และมาดูว่าประเด็นเหล่านี้สามารถได้รับการแก้ไขด้วย HTTP เป็นตัวอย่างได้อย่างไร หวังว่ามันคงไม่ยากเกินไปสำหรับคุณที่จะเชื่อมโยงแนวคิดเหล่านี้เข้ากับ communication protocol ใดก็ตามที่คุณเลือกใช้
ใน Figure 11-6 เราสามารถเห็นสี่ประเด็นหลักของข้อมูลขณะเดินทาง
Figure 11-6. สี่ประเด็นหลักเมื่อพูดถึงข้อมูลขณะเดินทาง
ลองมาดูแต่ละประเด็นให้ละเอียดขึ้นอีกนิด
Server identity (ตัวตนของ Server)
หนึ่ง ในสิ่งที่ง่ายที่สุดที่ควรตรวจสอบคือ server ที่คุณกำลังคุยด้วยเป็นตัวจริงตามที่มันอ้างหรือไม่ นี่สำคัญเพราะฝ่ายไม่หวังดีในทางทฤษฎีสามารถปลอมตัวเป็น endpoint ได้—แล้วดูดข้อมูลที่มีประโยชน์ใดๆ ก็ตามที่คุณส่งไปได้ การตรวจสอบตัวตนของ server เป็นข้อกังวลบนอินเทอร์เน็ตสาธารณะมานานแล้ว ซึ่งนำไปสู่การผลักดันการใช้ HTTPS อย่างแพร่หลายมากขึ้น และในระดับหนึ่ง เราสามารถได้รับประโยชน์จากงานที่ทำเพื่อรักษาความปลอดภัยของอินเทอร์เน็ตสาธารณะเมื่อพูดถึงการจัดการ internal HTTP endpoint
เมื่อคนพูดถึง “HTTPS” พวกเขามักหมายถึงการใช้ HTTP ร่วมกับ TLS 12 สำหรับการสื่อสารส่วนใหญ่ผ่านอินเทอร์เน็ตสาธารณะ เนื่องจากมี attack vector ที่อาจเกิดขึ้นได้หลากหลาย (WiFi ที่ไม่ปลอดภัย, DNS poisoning และอื่นๆ) จึงสำคัญมากที่จะต้องมั่นใจว่าเมื่อเราเข้าเว็บไซต์หนึ่ง มันเป็นเว็บไซต์ที่มันอ้างจริงๆ ด้วย HTTPS browser ของเราสามารถตรวจสอบใบรับรอง (certificate) ของเว็บไซต์นั้นและมั่นใจว่ามันถูกต้อง มันเป็นกลไกความปลอดภัยที่สมเหตุสมผลมาก—“HTTPS Everywhere” ได้กลายเป็นคำขวัญของอินเทอร์เน็ตสาธารณะ และด้วยเหตุผลที่ดี
ควรทราบไว้ว่า communication protocol บางตัวที่ใช้ HTTP อยู่เบื้องหลังสามารถใช้ประโยชน์จาก HTTPS ได้—ดังนั้นเราสามารถรัน SOAP หรือ gRPC บน HTTPS ได้อย่างไม่มีปัญหา HTTPS ยังให้การป้องกันเพิ่มเติมนอกเหนือจากการยืนยันว่าเรากำลังคุยกับคนที่เราคาดหวังไว้เท่านั้น เราจะพูดถึงเรื่องนั้นในอีกไม่ช้า
Client identity (ตัวตนของ Client)
เมื่อ เราพูดถึง client identity ในบริบทนี้ เรากำลังหมายถึง microservice ที่กำลังเรียก call—ดังนั้นเรากำลังพยายามยืนยันและ authenticate ตัวตนของ upstream microservice เราจะดูวิธี authenticate มนุษย์ (ผู้ใช้!) ในภายหลัง
เราสามารถยืนยันตัวตนของ client ได้หลายวิธี เราอาจขอให้ client ส่งข้อมูลบางอย่างในคำขอที่บอกว่าพวกเขาเป็นใคร ตัวอย่างอาจเป็นการใช้ shared secret บางรูปแบบหรือ client-side certificate เพื่อ sign คำขอนั้น เมื่อ server ต้องยืนยันตัวตนของ client เราต้องการให้มันมีประสิทธิภาพที่สุดเท่าที่จะเป็นไปได้—ผมเคยเห็นบางโซลูชัน (รวมถึงที่ถูกผลักดันโดยผู้ให้บริการ API gateway) ที่ทำให้ server ต้องเรียก call ไปยัง central service เพื่อตรวจสอบตัวตนของ client ซึ่งค่อนข้างบ้ามากเมื่อพิจารณาถึงผลกระทบด้าน latency
ผม พยายามนึกถึงสถานการณ์ที่ผมจะยืนยันตัวตนของ client โดยไม่ยืนยันตัวตนของ server ด้วยไม่ค่อยออก—การยืนยันทั้งสองอย่างมักลงเอยด้วยการนำ mutual authentication รูปแบบใดรูปแบบหนึ่งมาใช้ ด้วย mutual authentication ทั้งสองฝ่ายจะ authenticate ซึ่งกันและกัน ดังนั้นใน Figure 11-6 microservice Order Processor จะ authenticate microservice Payment และ microservice Payment ก็จะ authenticate Order Processor ด้วยเช่นกัน
เรา สามารถทำแบบนี้ได้ผ่านการใช้ mutual TLS ซึ่งทั้ง client และ server จะใช้ certificate ร่วมกัน บนอินเทอร์เน็ตสาธารณะ การยืนยันตัวตนของ client device มักสำคัญน้อยกว่าการยืนยันตัวตนของมนุษย์ที่ใช้ device นั้น ดังนั้น mutual TLS จึงถูกใช้ไม่บ่อยนัก ในสถาปัตยกรรม microservice ของเรา โดยเฉพาะเมื่อเราอาจกำลังทำงานในสภาพแวดล้อมแบบ zero trust นี่เป็นเรื่องที่พบได้บ่อยกว่ามาก
ความท้าทายในการนำโครงร่างอย่าง mutual TLS มาใช้ในอดีตคือเรื่อง tooling ปัจจุบันนี้ปัญหานี้น้อยลง เครื่องมืออย่าง Vault สามารถทำให้การกระจาย certificate ง่ายขึ้นมาก และความต้องการทำให้การใช้ mutual TLS ง่ายขึ้นก็เป็นหนึ่งในเหตุผลหลักที่ผู้คนนำ service mesh มาใช้ ซึ่งเราได้สำรวจไปแล้วใน “Service Meshes and API Gateways” .
Visibility of data (การมองเห็นข้อมูล)
เมื่อเราส่งข้อมูลจาก microservice หนึ่งไปยังอีกตัวหนึ่ง มีใครสามารถมองเห็นข้อมูลได้หรือไม่? สำหรับข้อมูลบางอย่าง เช่นราคาของอัลบั้ม Peter Andre เราอาจไม่ค่อยกังวลมากนักเพราะข้อมูลนั้นอยู่ในโดเมนสาธารณะอยู่แล้ว ในทางกลับกัน ข้อมูลบางอย่างอาจรวมถึง PII ซึ่งเราต้องมั่นใจว่าได้รับการปกป้อง
เมื่อคุณใช้ HTTPS ธรรมดาหรือ mutual TLS ข้อมูลจะไม่สามารถมองเห็นได้โดยฝ่ายที่อยู่ตรงกลาง—นี่เพราะ TLS เข้ารหัสข้อมูลที่ถูกส่ง ซึ่งอาจเป็นปัญหาได้หากคุณต้องการให้ข้อมูลถูกส่งแบบเปิดเผยโดยตั้งใจ—ตัวอย่างเช่น reverse proxy อย่าง Squid หรือ Varnish สามารถ cache HTTP response ได้ แต่ทำแบบนั้นไม่ได้กับ HTTPS
Manipulation of data (การปลอมแปลงข้อมูล)
เราสามารถนึกภาพสถานการณ์หลายอย่างที่การปลอมแปลงข้อมูลที่ถูกส่งอาจก่อให้เกิดผลเสีย—เช่น การเปลี่ยนจำนวนเงินที่ถูกส่งไป ดังนั้นใน Figure 11-6 เราต้องมั่นใจว่าผู้โจมตีที่อาจเกิดขึ้นไม่สามารถเปลี่ยนคำขอที่ถูกส่งไปยัง Payment จาก Order Processor ได้
โดยทั่วไปแล้ว ประเภทของการป้องกันที่ทำให้ข้อมูลมองไม่เห็นก็มักจะทำให้ข้อมูลไม่สามารถถูกปลอมแปลงได้ด้วย (HTTPS ทำแบบนั้น ยกตัวอย่างเช่น) แต่เราอาจตัดสินใจส่งข้อมูลแบบเปิดเผยแต่ยังต้องการมั่นใจว่ามันไม่สามารถถูกปลอมแปลงได้ สำหรับ HTTP วิธีหนึ่งคือใช้ hash-based message authentication code (HMAC) เพื่อ sign ข้อมูลที่ถูกส่ง ด้วย HMAC hash จะถูกสร้างขึ้นและส่งไปพร้อมกับข้อมูล และผู้รับสามารถตรวจสอบ hash เทียบกับข้อมูลเพื่อยืนยันว่าข้อมูลไม่ได้ถูกเปลี่ยนแปลง
Data at Rest (ข้อมูลขณะพักนิ่ง)
ข้อมูลที่วางอยู่เฉยๆ ก็เป็นภาระ โดยเฉพาะถ้ามันอ่อนไหว หวังว่าเราจะได้ทำทุกอย่างที่ทำได้เพื่อมั่นใจว่าผู้โจมตีไม่สามารถเจาะเข้าเครือข่ายของเราได้ และพวกเขาไม่สามารถเจาะแอปพลิเคชันหรือระบบปฏิบัติการของเราเพื่อเข้าถึงข้อมูลที่อยู่เบื้องล่างได้ อย่างไรก็ตาม เราจำเป็นต้องเตรียมพร้อมในกรณีที่พวกเขาทำได้—defense in depth คือกุญแจสำคัญ
การรั่วไหลของข้อมูล security ระดับสูงหลายๆ ครั้งที่เราได้ยินเกี่ยวข้องกับข้อมูลขณะพักนิ่งที่ถูกผู้โจมตีเข้าถึง และข้อมูลนั้นสามารถถูกอ่านได้โดยผู้โจมตี สิ่งนี้เกิดขึ้นได้ทั้งเพราะข้อมูลถูกเก็บในรูปแบบที่ไม่ได้เข้ารหัส หรือเพราะกลไกที่ใช้ปกป้องข้อมูลมีข้อบกพร่องพื้นฐาน
กลไกที่ใช้ปกป้องข้อมูลขณะพักนิ่งมีอยู่มากมายหลากหลาย แต่มีบางสิ่งทั่วไปที่ควรคำนึงถึง
Go with the well known (เลือกใช้สิ่งที่เป็นที่รู้จักดี)
ในบางกรณี คุณสามารถโยนงานเข้ารหัสข้อมูลให้กับซอฟต์แวร์ที่มีอยู่แล้วได้—ยกตัวอย่างเช่น ใช้ประโยชน์จาก support สำหรับการเข้ารหัสที่มีในตัวฐานข้อมูลของคุณ อย่างไรก็ตาม หากคุณพบว่าจำเป็นต้องเข้ารหัสและถอดรหัสข้อมูลในระบบของคุณเอง ให้มั่นใจว่าคุณกำลังใช้ implementation ที่เป็นที่รู้จักดีและผ่านการทดสอบแล้ว วิธีที่ง่ายที่สุดที่คุณอาจทำการเข้ารหัสข้อมูลพลาดคือการพยายามสร้าง encryption algorithm ของตัวเองขึ้นมา หรือแม้แต่พยายาม implement algorithm ของคนอื่น ไม่ว่าคุณจะใช้ภาษาโปรแกรมอะไร คุณจะมี implementation ที่ได้รับการ review และ patch เป็นประจำของ encryption algorithm ที่ได้รับการยอมรับอย่างกว้างขวางให้ใช้อยู่แล้ว ใช้พวกมันซะ! และสมัครรับ mailing list/advisory list สำหรับเทคโนโลยีที่คุณเลือกใช้ เพื่อให้แน่ใจว่าคุณรับรู้ถึงช่องโหว่ต่างๆ ทันทีที่มันถูกพบ เพื่อให้คุณสามารถ patch และอัปเดตให้ทันสมัยอยู่เสมอได้
สำหรับ การรักษาความปลอดภัยรหัสผ่าน คุณควรใช้เทคนิคที่เรียกว่า salted password hashing อย่างเด็ดขาด สิ่งนี้ทำให้แน่ใจว่ารหัสผ่านจะไม่ถูกเก็บเป็น plain text เลย และแม้ผู้โจมตีจะ brute-force hash รหัสผ่านหนึ่งได้สำเร็จ พวกเขาก็ไม่สามารถอ่านรหัสผ่านตัวอื่นๆ ได้โดยอัตโนมัติ 13
การเข้ารหัสที่ implement ได้ไม่ดีอาจแย่ยิ่งกว่าการไม่มีการเข้ารหัสเลยเสียอีก เพราะความรู้สึกปลอดภัยที่ผิดพลาด (ขออภัยที่เล่นคำ) อาจทำให้คุณละสายตาจากสิ่งสำคัญไปได้
Pick your targets (เลือกเป้าหมายให้ถูกต้อง)
การสมมติว่าทุกอย่างควรถูกเข้ารหัสสามารถทำให้เรื่องต่างๆ ง่ายขึ้นได้ในระดับหนึ่ง ไม่ต้องเดาว่าอะไรควรหรือไม่ควรได้รับการปกป้อง อย่างไรก็ตาม คุณยังต้องคิดว่าข้อมูลอะไรสามารถใส่ลงใน logfile ได้เพื่อช่วยในการระบุปัญหา และ overhead ในการคำนวณของการเข้ารหัสทุกอย่างอาจกลายเป็นภาระหนักมาก และต้องการฮาร์ดแวร์ที่ทรงพลังขึ้นเป็นผล สิ่งนี้ยิ่งท้าทายมากขึ้นเมื่อคุณใช้ database migration เป็นส่วนหนึ่งของการ refactor schema ขึ้นอยู่กับการเปลี่ยนแปลงที่กำลังทำ ข้อมูลอาจต้องถูกถอดรหัส ย้าย และ เข้ารหัสใหม่
ด้วยการแบ่งระบบของคุณให้ละเอียดขึ้นเป็น service ต่างๆ คุณอาจระบุ data store ทั้งหมดที่สามารถเข้ารหัสได้ทั้งก้อนได้ แต่นั่นไม่น่าจะเกิดขึ้นบ่อยนัก การจำกัดการเข้ารหัสให้อยู่ในชุดตารางที่รู้จักแน่ชัดถือเป็นแนวทางที่สมเหตุสมผล
Be frugal (ประหยัดเข้าไว้)
เมื่อพื้นที่ดิสก์มีราคาถูกลง และความสามารถของฐานข้อมูลพัฒนาขึ้น ความง่ายในการเก็บข้อมูลจำนวนมากก็เพิ่มขึ้นอย่างรวดเร็ว ข้อมูลนี้มีค่า—ไม่ใช่แค่กับตัวธุรกิจเองที่มองว่าข้อมูลเป็นสินทรัพย์ที่มีค่ามากขึ้นเรื่อยๆ เท่านั้น แต่ยังมีค่าพอๆ กันกับผู้ใช้ที่ให้คุณค่ากับความเป็นส่วนตัวของตัวเองด้วย ข้อมูลที่เกี่ยวข้องกับตัวบุคคล หรือที่สามารถใช้อนุมานข้อมูลเกี่ยวกับบุคคลได้ ต้องเป็นข้อมูลที่เราระมัดระวังมากที่สุด
แต่ถ้าเราทำให้ชีวิตเราง่ายขึ้นสักหน่อยล่ะ? ทำไมไม่ลบข้อมูลที่สามารถระบุตัวตนของบุคคลได้ให้มากที่สุดเท่าที่จะทำได้ และทำมันให้เร็วที่สุด? เมื่อบันทึกคำขอจากผู้ใช้ เราจำเป็นต้องเก็บ IP address ทั้งหมดไว้ตลอดไปหรือไม่ หรือเราสามารถแทนที่ตัวเลขไม่กี่หลักท้ายด้วย x ได้ไหม? เราจำเป็นต้องเก็บชื่อ อายุ เพศ และวันเกิดของใครสักคนเพื่อเสนอโปรโมชั่นสินค้าให้พวกเขาหรือไม่ หรือแค่ช่วงอายุและรหัสไปรษณีย์ก็เพียงพอแล้ว?
ข้อดีของการประหยัดในการเก็บรวบรวมข้อมูลมีหลายด้าน อย่างแรก ถ้าคุณไม่เก็บมันไว้ ก็ไม่มีใครขโมยมันไปได้ อย่างที่สอง ถ้าคุณไม่เก็บมันไว้ ก็ไม่มีใคร (เช่น หน่วยงานราชการ) สามารถขอมันไปได้ด้วยเช่นกัน!
คำภาษาเยอรมัน Datensparsamkeit แสดงถึงแนวคิดนี้ มันมาจากกฎหมาย privacy ของเยอรมนี และสรุปแนวคิดของการเก็บข้อมูลเท่าที่ จำเป็นอย่างแท้จริง เท่านั้นเพื่อทำให้การดำเนินธุรกิจสำเร็จหรือเพื่อให้เป็นไปตามกฎหมายท้องถิ่น
แน่นอนว่านี่ขัดแย้งโดยตรงกับแนวโน้มที่มุ่งเก็บข้อมูลมากขึ้นเรื่อยๆ แต่การตระหนักว่าความขัดแย้งนี้มีอยู่จริงก็ถือเป็นจุดเริ่มต้นที่ดีแล้ว!
It’s all about the keys (ทุกอย่างขึ้นอยู่กับ Key)
การเข้ารหัส ส่วนใหญ่เกี่ยวข้องกับการใช้ key บางอย่างร่วมกับ algorithm ที่เหมาะสมเพื่อสร้างข้อมูลที่เข้ารหัสแล้ว ในการถอดรหัสข้อมูลเพื่อให้อ่านได้ ฝ่ายที่ได้รับอนุญาตจะต้องเข้าถึง key—ไม่ว่าจะเป็น key เดียวกันหรือ key ที่แตกต่างกัน (ในกรณีของ public-key encryption) ดังนั้น key ของคุณถูกเก็บไว้ที่ไหน? ทีนี้ ถ้าผมเข้ารหัสข้อมูลเพราะกังวลว่าใครสักคนจะขโมยฐานข้อมูลทั้งหมดของผมไป แต่ผมเก็บ key ที่ใช้ไว้ในฐานข้อมูลเดียวกัน ผมก็แทบจะไม่ได้ทำอะไรสำเร็จเลย! ดังนั้นเราจำเป็นต้องเก็บ key ไว้ที่อื่น แต่ที่ไหนล่ะ?
ทางออกหนึ่งคือใช้ security appliance แยกต่างหากเพื่อเข้ารหัสและถอดรหัสข้อมูล อีกทางหนึ่งคือใช้ key vault แยกต่างหากที่ service ของคุณสามารถเข้าถึงได้เมื่อต้องการ key การจัดการ life cycle ของ key (และการเข้าถึงเพื่อเปลี่ยนแปลงมัน) อาจเป็นการทำงานที่สำคัญมาก และระบบเหล่านี้สามารถจัดการเรื่องนี้ให้คุณได้ นี่คือจุดที่ HashiCorp’s Vault สามารถเข้ามาช่วยได้อย่างมากเช่นกัน
ฐานข้อมูลบางตัวมี support สำหรับการเข้ารหัสในตัวด้วยซ้ำ เช่น Transparent Data Encryption ของ SQL Server ซึ่งมุ่งจัดการเรื่องนี้ในลักษณะที่โปร่งใส แม้ว่าฐานข้อมูลที่คุณเลือกใช้จะมี support แบบนี้ ก็ควรศึกษาว่า key ถูก จัดการ อย่างไร และทำความเข้าใจว่าภัยคุกคามที่คุณกำลังป้องกันอยู่นั้นได้รับการ บรรเทา จริงๆ หรือไม่
อีกครั้ง เรื่องนี้ซับซ้อน หลีกเลี่ยงการสร้างระบบเข้ารหัสของตัวเอง และศึกษาให้ดีก่อน!
Tip
เข้ารหัสข้อมูลตั้งแต่ครั้งแรกที่คุณเห็นมัน ถอดรหัสเฉพาะเมื่อจำเป็นเท่านั้น และมั่นใจว่าข้อมูล (ที่ถอดรหัสแล้ว) ไม่เคยถูกเก็บไว้ที่ใดเลย
Encrypt backups (เข้ารหัส Backup)
Backup เป็นสิ่งที่ดี เราต้องการสำรองข้อมูลสำคัญของเรา และแม้จะดูเป็นเรื่องชัดเจน แต่ถ้าข้อมูลอ่อนไหวมากพอที่เราต้องการให้มันถูกเข้ารหัสในระบบ production ที่กำลังทำงานอยู่ เราก็คงต้องการมั่นใจด้วยว่า backup ใดๆ ของข้อมูลชุดเดียวกันนั้นก็ถูกเข้ารหัสด้วยเช่นกัน!