เจาะลึก: วิธีที่เราใช้กล่องจดหมาย SQLite ที่เข้ารหัสควอนตัมปลอดภัยสำหรับบริการอีเมลที่เน้นความเป็นส่วนตัวและปลอดภัยของเรา

ไม่เหมือนกับบริการอีเมลอื่น ๆ เรารับรองว่า มีเพียงคุณเท่านั้นที่สามารถเข้าถึงกล่องจดหมายของคุณ ได้ตลอดเวลา

คำนำ

ทีแอลอาร์; บริการอีเมล์ของเราคือ โอเพ่นซอร์ส 100% และเน้นความเป็นส่วนตัวผ่านกล่องจดหมาย SQLite ที่ปลอดภัยและเข้ารหัส

จนกระทั่งเราเปิดตัว การสนับสนุน IMAPเราใช้ MongoDB สำหรับความต้องการพื้นที่จัดเก็บข้อมูลถาวรของเรา

เทคโนโลยีนี้น่าทึ่งมากและเรายังคงใช้มันอยู่ในปัจจุบัน แต่เพื่อที่จะมีการเข้ารหัสเมื่อไม่มีการใช้งานกับ MongoDB คุณต้องใช้ผู้ให้บริการที่ให้บริการ MongoDB Enterprise เช่น Digital Ocean หรือ Mongo Atlas – หรือชำระค่าลิขสิทธิ์ระดับองค์กร (และ ต่อมาต้องทำงานร่วมกับทีมขายที่มีความหน่วงแฝง)

ทีมงานของเราที่ ส่งต่ออีเมล ต้องการโซลูชันพื้นที่จัดเก็บข้อมูลที่เข้ารหัสที่เป็นมิตรต่อนักพัฒนา ปรับขนาดได้ เชื่อถือได้ และเข้ารหัสสำหรับกล่องจดหมาย IMAP ในฐานะนักพัฒนาโอเพ่นซอร์ส การใช้เทคโนโลยีที่คุณต้องจ่ายค่าธรรมเนียมใบอนุญาตเพื่อรับคุณสมบัติการเข้ารหัสเมื่อไม่มีการใช้งานนั้นขัดต่อ หลักการของเรา – ดังนั้นเราจึงทดลอง วิจัย และพัฒนาโซลูชันใหม่ตั้งแต่ต้นเพื่อแก้ปัญหาความต้องการเหล่านี้

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

อ่านต่อในขณะที่เราดำดิ่งลงด้านล่างด้วย การเปรียบเทียบผู้ให้บริการอีเมล, บริการของเราทำงานอย่างไร, กองเทคโนโลยีของเรา, และอื่น ๆ.

การเปรียบเทียบผู้ให้บริการอีเมล

เราเป็นผู้ให้บริการอีเมลแบบโอเพ่นซอร์สและเน้นความเป็นส่วนตัวเพียงรายเดียว 100% ที่เก็บกล่องจดหมาย SQLite ที่เข้ารหัสแยกกัน ให้บริการโดเมน นามแฝง และผู้ใช้ไม่จำกัด และรองรับ SMTP, IMAP และ POP3 ขาออก:

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

อ่านการเปรียบเทียบบริการอีเมล

มันทำงานอย่างไร

  1. การใช้โปรแกรมรับส่งอีเมลของคุณ เช่น Apple Mail, Thunderbird, Gmail หรือ Outlook - คุณเชื่อมต่อกับระบบรักษาความปลอดภัยของเรา IMAP เซิร์ฟเวอร์ที่ใช้ชื่อผู้ใช้และรหัสผ่านของคุณ:

    • ชื่อผู้ใช้ของคุณคือนามแฝงเต็มของคุณกับโดเมนของคุณเช่น hello@example.com.
    • รหัสผ่านของคุณถูกสร้างขึ้นแบบสุ่มและแสดงให้คุณเห็นเพียง 30 วินาทีเมื่อคุณคลิก สร้างรหัสผ่าน จาก บัญชีของฉัน โดเมน นามแฝง
  2. เมื่อเชื่อมต่อแล้ว ไคลเอนต์อีเมลของคุณจะส่ง คำสั่งโปรโตคอล IMAP ไปยังเซิร์ฟเวอร์ IMAP ของเราเพื่อให้กล่องจดหมายของคุณซิงค์กัน ซึ่งรวมถึงการเขียนและจัดเก็บอีเมลฉบับร่างและการดำเนินการอื่นๆ ที่คุณอาจทำ (เช่น ติดป้ายกำกับอีเมลว่าสำคัญหรือตั้งค่าสถานะอีเมลว่าเป็นสแปม/เมลขยะ)

  3. เซิร์ฟเวอร์ Exchange Mail (หรือที่รู้จักกันทั่วไปในชื่อเซิร์ฟเวอร์ "MX") จะได้รับอีเมลขาเข้าใหม่และจัดเก็บไว้ในกล่องจดหมายของคุณ เมื่อสิ่งนี้เกิดขึ้น ไคลเอนต์อีเมลของคุณจะได้รับการแจ้งเตือนและซิงค์กล่องจดหมายของคุณ เซิร์ฟเวอร์แลกเปลี่ยนจดหมายของเราสามารถส่งต่ออีเมลของคุณไปยังผู้รับตั้งแต่หนึ่งรายขึ้นไป (รวมถึง เว็บฮุค) จัดเก็บอีเมลของคุณไว้ในที่เก็บข้อมูล IMAP ที่เข้ารหัสกับเรา หรือทั้งคู่!

    สนใจที่จะเรียนรู้เพิ่มเติมหรือไม่? อ่าน วิธีการตั้งค่าการส่งต่ออีเมล, บริการแลกเปลี่ยนจดหมายของเราทำงานอย่างไรหรือดู คำแนะนำของเรา.

  4. เบื้องหลัง การออกแบบพื้นที่จัดเก็บอีเมลที่ปลอดภัยของเราทำงานในสองวิธีเพื่อให้กล่องจดหมายของคุณได้รับการเข้ารหัสและมีเพียงคุณเท่านั้นที่สามารถเข้าถึงได้:

    • เมื่อได้รับจดหมายใหม่ถึงคุณจากผู้ส่ง เซิร์ฟเวอร์แลกเปลี่ยนจดหมายของเราจะเขียนไปยังกล่องจดหมายส่วนบุคคล ชั่วคราว และเข้ารหัสสำหรับคุณ

      sequenceDiagram
          autonumber
          actor Sender
          Sender->>MX: Inbound message received for your alias (e.g. you@yourdomain.com).
          MX->>SQLite: Message is stored in a temporary mailbox.
          Note over MX,SQLite: Forwards to other recipients and webhooks configured.
          MX->>Sender: Success!
      
    • เมื่อคุณเชื่อมต่อกับเซิร์ฟเวอร์ IMAP ของเราด้วยไคลเอนต์อีเมลของคุณ รหัสผ่านของคุณจะถูกเข้ารหัสในหน่วยความจำและใช้ในการอ่านและเขียนไปยังกล่องจดหมายของคุณ กล่องจดหมายของคุณสามารถอ่านและเขียนด้วยรหัสผ่านนี้เท่านั้น โปรดทราบว่าเนื่องจากคุณเป็นคนเดียวที่มีรหัสผ่านนี้ เพียงคุณเท่านั้น สามารถอ่านและเขียนไปยังกล่องจดหมายของคุณเมื่อคุณเข้าถึงได้ ครั้งถัดไปที่โปรแกรมรับส่งเมลของคุณพยายามสำรวจหาเมลหรือการซิงค์ ข้อความใหม่ของคุณจะถูกโอนจากกล่องจดหมายชั่วคราวนี้และจัดเก็บไว้ในไฟล์กล่องจดหมายจริงของคุณโดยใช้รหัสผ่านที่คุณให้มา โปรดทราบว่ากล่องจดหมายชั่วคราวนี้จะถูกล้างข้อมูลและลบหลังจากนั้น เพื่อให้มีเพียงกล่องจดหมายที่ป้องกันด้วยรหัสผ่านของคุณเท่านั้นที่มีข้อความ

    • หากคุณเชื่อมต่อกับ IMAP (เช่น ใช้โปรแกรมรับส่งเมล เช่น Apple Mail หรือ Thunderbird) เราไม่จำเป็นต้องเขียนลงพื้นที่จัดเก็บดิสก์ชั่วคราว รหัสผ่าน IMAP ที่เข้ารหัสในหน่วยความจำของคุณจะถูกดึงและใช้งานแทน แบบเรียลไทม์ เมื่อมีการพยายามส่งข้อความถึงคุณ เราจะส่งคำขอ WebSocket ไปยังเซิร์ฟเวอร์ IMAP ทั้งหมดเพื่อสอบถามว่าพวกเขามีเซสชันที่ใช้งานอยู่สำหรับคุณหรือไม่ (นี่คือส่วนที่ดึงข้อมูล) จากนั้นจะส่งต่อไปตามนั้น รหัสผ่านในหน่วยความจำที่เข้ารหัส – ดังนั้นเราจึงไม่จำเป็นต้องเขียนลงในกล่องจดหมายชั่วคราว เราสามารถเขียนไปยังกล่องจดหมายที่เข้ารหัสจริงของคุณได้โดยใช้รหัสผ่านที่เข้ารหัสของคุณ

      sequenceDiagram
          autonumber
          actor You
          You->>IMAP: You connect to IMAP server using an email client.
          IMAP->>SQLite: Transfer message from temporary mailbox to your alias' mailbox.
          Note over IMAP,SQLite: Your alias' mailbox is only available in-memory using IMAP password.
          SQLite->>IMAP: Retrieves messages as requested by email client.
          IMAP->>You: Success!
      
  5. การสำรองข้อมูลกล่องจดหมายที่เข้ารหัสของคุณ จะทำทุกวัน คุณยังสามารถขอข้อมูลสำรองใหม่ได้ตลอดเวลาหรือดาวน์โหลดข้อมูลสำรองล่าสุดได้จาก บัญชีของฉัน โดเมน นามแฝง หากคุณตัดสินใจเปลี่ยนไปใช้บริการอีเมลอื่น คุณสามารถย้าย ดาวน์โหลด ส่งออก และล้างกล่องจดหมายและการสำรองข้อมูลของคุณได้อย่างง่ายดายทุกเมื่อ

เทคโนโลยี

ฐานข้อมูล

เราสำรวจเลเยอร์พื้นที่จัดเก็บฐานข้อมูลอื่นๆ ที่เป็นไปได้ แต่ไม่มีสิ่งใดที่ตอบสนองความต้องการของเราได้มากเท่ากับ SQLite:

ฐานข้อมูลการเข้ารหัสที่เหลือแซนด์บ็อกซ์ กล่องจดหมายการอนุญาตใช้ทุกที่
SQLite✅ใช่กับ SQLite3MultipleCiphers✅โดเมนสาธารณะ
MongoDB"มีเฉพาะใน MongoDB Enterprise เท่านั้น"❌ฐานข้อมูลเชิงสัมพันธ์❌AGPL และ SSPL-1.0
rqliteเครือข่ายเท่านั้น❌ฐานข้อมูลเชิงสัมพันธ์MIT
ดีคิวไลท์ยังไม่ได้ทดสอบและยังไม่รองรับใช่ไหมยังไม่ได้ทดสอบและยังไม่รองรับใช่ไหมLGPL-3.0-only
PostgreSQLใช่❌ฐานข้อมูลเชิงสัมพันธ์PostgreSQL (คล้ายกับ BSD หรือ MIT)
มาเรียดีบีสำหรับ InnoDB เท่านั้น❌ฐานข้อมูลเชิงสัมพันธ์GPLv2 และ BUSL-1.1
แมลงสาบDBคุณลักษณะเฉพาะสำหรับองค์กรเท่านั้น❌ฐานข้อมูลเชิงสัมพันธ์BUSL-1.1 และคนอื่น ๆ

นี่คือก โพสต์ในบล็อกที่เปรียบเทียบตัวเลือกการจัดเก็บฐานข้อมูล SQLite หลายตัว ในตารางด้านบน

ความปลอดภัย

ตลอดเวลาที่เราใช้ การเข้ารหัสที่เหลือ (AES-256), การเข้ารหัสระหว่างทาง (TLS), DNS ผ่าน HTTPS ("DoH") โดยใช้ 🍊 ส้มเขียวหวาน, และ ตาราง (ชาช่า20-โพลี1305) การเข้ารหัสบนกล่องจดหมาย นอกจากนี้ เรายังใช้การตรวจสอบสิทธิ์แบบสองปัจจัยที่ใช้โทเค็น (ซึ่งตรงข้ามกับ SMS ที่น่าสงสัย) การโจมตีจากคนกลาง) คีย์ SSH ที่หมุนเวียนโดยปิดใช้งานการเข้าถึงรูท การเข้าถึงเซิร์ฟเวอร์แบบเอกสิทธิ์เฉพาะบุคคลผ่านที่อยู่ IP ที่จำกัด และอื่นๆ

ในกรณีที่มี การโจมตีของสาวใช้ชั่วร้าย หรือพนักงานหลอกลวงจากผู้ขายบุคคลที่สาม กล่องจดหมายของคุณยังคงสามารถเปิดได้ด้วยรหัสผ่านที่คุณสร้างขึ้นเท่านั้น. วางใจได้เลย เราไม่พึ่งพาผู้จำหน่ายบุคคลที่สามใดๆ นอกเหนือจากผู้ให้บริการเซิร์ฟเวอร์ร้องเรียน SOC Type 2 ของ Cloudflare, Digital Ocean และ Vultr

เป้าหมายของเราคือการมีให้น้อย จุดเดียวของความล้มเหลว เป็นไปได้.

กล่องจดหมาย

ทีแอลอาร์; เซิร์ฟเวอร์ IMAP ของเราใช้ฐานข้อมูล SQLite ที่เข้ารหัสแยกกันสำหรับกล่องจดหมายแต่ละกล่องของคุณ

SQLite เป็นที่นิยมอย่างมาก ฐานข้อมูลแบบฝัง – ขณะนี้มันทำงานบนโทรศัพท์และคอมพิวเตอร์ของคุณ – และใช้โดยเทคโนโลยีหลักเกือบทั้งหมด.

ตัวอย่างเช่น บนเซิร์ฟเวอร์ที่เข้ารหัสของเรา จะมีเมลบ็อกซ์ฐานข้อมูล SQLite linux@example.com, info@example.com, hello@example.com และอื่นๆ – หนึ่งอันสำหรับแต่ละอันเป็น .sqlite ไฟล์ฐานข้อมูล เราไม่ตั้งชื่อไฟล์ฐานข้อมูลด้วยที่อยู่อีเมล แต่เราใช้ BSON ObjectID และ UUID ที่ไม่ซ้ำกันที่สร้างขึ้นซึ่งไม่เปิดเผยว่ากล่องจดหมายเป็นของใครหรือที่อยู่อีเมลใดอยู่ภายใต้ (เช่น 353a03f21e534321f5d6e267.sqlite).

แต่ละฐานข้อมูลเหล่านี้ได้รับการเข้ารหัสด้วยตนเองโดยใช้รหัสผ่านของคุณ (ซึ่งมีเพียงคุณเท่านั้น) โดยใช้ ตาราง (ชาช่า20-โพลี1305). ซึ่งหมายความว่ากล่องจดหมายของคุณได้รับการเข้ารหัสแยกกัน มีอยู่ในตัวเอง แซนด์บ็อกซ์และแบบพกพา

เราได้ปรับแต่ง SQLite ดังต่อไปนี้ PRAGMA:

PRAGMAวัตถุประสงค์
cipher=chacha20การเข้ารหัสฐานข้อมูล ChaCha20-Poly1305 SQLite. อ้างอิง better-sqlite3-multiple-ciphers ภายใต้ โครงการ เพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้น
key="****************"นี่เป็นรหัสผ่านเฉพาะในหน่วยความจำที่ถอดรหัสแล้วของคุณ ซึ่งจะถูกส่งผ่านการเชื่อมต่อ IMAP ของโปรแกรมรับส่งอีเมลของคุณไปยังเซิร์ฟเวอร์ของเรา อินสแตนซ์ฐานข้อมูลใหม่จะถูกสร้างและปิดสำหรับแต่ละเซสชันการอ่านและเขียน (เพื่อให้แน่ใจว่ามีแซนด์บ็อกซ์และการแยกตัว)
journal_model=WALบันทึกการเขียนล่วงหน้า ("WAL") ซึ่งช่วยเพิ่มประสิทธิภาพและช่วยให้เข้าถึงการอ่านได้พร้อมกัน.
busy_timeout=5000ป้องกันข้อผิดพลาดในการล็อคการเขียน ในขณะที่มีการเขียนอื่นเกิดขึ้น.
synchronous=NORMALเพิ่มความคงทนในการทำธุรกรรม โดยไม่มีความเสี่ยงต่อความเสียหายของข้อมูล.
foreign_keys=ONบังคับใช้การอ้างอิงคีย์ต่างประเทศ (เช่น ความสัมพันธ์จากตารางหนึ่งไปอีกตารางหนึ่ง) ตามค่าเริ่มต้น สิ่งนี้จะไม่ถูกเปิดใช้งานใน SQLiteแต่สำหรับการตรวจสอบความถูกต้องและความสมบูรณ์ของข้อมูล ควรเปิดใช้งาน
encoding='UTF-8'การเข้ารหัสเริ่มต้น เพื่อใช้เพื่อให้แน่ใจว่านักพัฒนามีสติ

ค่าเริ่มต้นอื่น ๆ ทั้งหมดมาจาก SQLite ตามที่ระบุจาก เอกสารอย่างเป็นทางการของ PRAGMA.

เห็นพ้องต้องกัน

ทีแอลอาร์; เราใช้ rclone และ WebSocket สำหรับการอ่านและเขียนไปยังกล่องจดหมาย SQLite ที่เข้ารหัสของคุณพร้อมกัน

อ่าน

ไคลเอนต์อีเมลของคุณบนโทรศัพท์ของคุณอาจแก้ไขได้ imap.forwardemail.net ไปยังหนึ่งในที่อยู่ IP ของ Digital Ocean ของเรา และไคลเอนต์เดสก์ท็อปของคุณอาจแก้ไข IP ที่แยกจากที่อื่น ผู้ให้บริการ โดยสิ้นเชิง

ไม่ว่าไคลเอนต์อีเมลของคุณจะเชื่อมต่อเซิร์ฟเวอร์ IMAP ใด เราต้องการให้การเชื่อมต่ออ่านจากฐานข้อมูลของคุณแบบเรียลไทม์ด้วยความแม่นยำ 100%:

  • ทำได้โดยใช้ rclone กับ --vfs-cache-mode off (ค่าเริ่มต้น)

  • แทนที่จะใช้ดิสก์แคชในเครื่อง แคชจะถูกอ่านโดยตรงจากการเมาท์ระยะไกล (ฐานข้อมูลของคุณ) ในแบบเรียลไทม์

  • ในกรณีที่ไม่พบไฟล์ในเครื่องแสดงว่าเป็นเช่นนั้น rclone ไม่สามารถเมานต์หรือมีปัญหา ในกรณีนี้เราใช้ a WebSocket ทางเลือกสำรองสำหรับการอ่าน (ซึ่งลดประสิทธิภาพเล็กน้อย แต่ยังคงรักษาความสมบูรณ์ของบริการ)

  • เซิร์ฟเวอร์ของเราแต่ละเครื่องได้รับการกำหนดค่าให้ติดตั้งด้วยความสอดคล้องและแจ้งเตือนเราแบบเรียลไทม์หากมีข้อผิดพลาดใดๆ

เขียน

การเขียนไปยังฐานข้อมูลของคุณแตกต่างออกไปเล็กน้อย เนื่องจาก SQLite เป็นฐานข้อมูลแบบฝัง และกล่องจดหมายของคุณอยู่ในไฟล์เดียวตามค่าเริ่มต้น

เราได้สำรวจตัวเลือกต่างๆ เช่น litestream, rqlite, และ dqlite ด้านล่าง – อย่างไรก็ตาม สิ่งเหล่านี้ไม่สามารถตอบสนองความต้องการของเราได้

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

ตัวหลักกำลังทำงานบนเซิร์ฟเวอร์ข้อมูลโดยมีไดรฟ์ข้อมูลที่ติดตั้งซึ่งมีกล่องจดหมายที่เข้ารหัส จากมุมมองของการเผยแพร่ คุณสามารถพิจารณาเซิร์ฟเวอร์ IMAP ทั้งหมดที่อยู่เบื้องหลังได้ imap.forwardemail.net ให้เป็นเซิร์ฟเวอร์รอง ("รอง")

เราบรรลุการสื่อสารสองทางด้วย เว็บซ็อกเก็ต:

  • เซิร์ฟเวอร์หลักใช้อินสแตนซ์ของ ของ WebSocketServer เซิร์ฟเวอร์
  • เซิร์ฟเวอร์รองใช้อินสแตนซ์ของ ของ WebSocket ลูกค้าที่ห่อด้วย websocket ตามที่สัญญาไว้ และ เชื่อมต่อใหม่-websocket. กระดาษห่อทั้งสองนี้ช่วยให้มั่นใจได้ว่า WebSocket เชื่อมต่อใหม่และสามารถส่งและรับข้อมูลสำหรับการเขียนฐานข้อมูลเฉพาะได้

การสำรองข้อมูล

ทีแอลอาร์; มีการสำรองข้อมูลกล่องจดหมายที่เข้ารหัสของคุณทุกวัน คุณยังสามารถขอข้อมูลสำรองใหม่ได้ทันทีหรือดาวน์โหลดข้อมูลสำรองล่าสุดได้ตลอดเวลาจาก บัญชีของฉัน โดเมน นามแฝง

สำหรับการสำรองข้อมูล เราเพียงเรียกใช้ SQLite VACUUM INTO คำสั่งทุกวันระหว่างการประมวลผลคำสั่ง IMAP ซึ่งใช้ประโยชน์จากรหัสผ่านที่เข้ารหัสของคุณจากการเชื่อมต่อ IMAP ในหน่วยความจำ ข้อมูลสำรองจะถูกจัดเก็บหากตรวจไม่พบข้อมูลสำรองที่มีอยู่หรือหาก SHA-256 แฮชมีการเปลี่ยนแปลงในไฟล์เมื่อเปรียบเทียบกับการสำรองข้อมูลล่าสุด

โปรดทราบว่าเราใช้ VACUUM INTO คำสั่งตรงข้ามกับในตัว backup คำสั่งเพราะหากเพจถูกแก้ไขระหว่าง backup การดำเนินการตามคำสั่งแล้วจะต้องเริ่มต้นใหม่ ที่ VACUUM INTO คำสั่งจะจับภาพ ดูความคิดเห็นเหล่านี้ได้ที่ GitHub และ ข่าวแฮ็กเกอร์ เพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้น

นอกจากนี้เรายังใช้ VACUUM INTO ตรงข้ามกับ backup, เพราะว่า backup คำสั่งจะปล่อยให้ฐานข้อมูลไม่ได้เข้ารหัสในช่วงเวลาสั้น ๆ จนกระทั่ง rekey ถูกเรียกใช้ (ดู GitHub นี้ ความคิดเห็น เพื่อความเข้าใจ)

มัธยมศึกษาจะสั่งสอนประถมศึกษาเกี่ยวกับ WebSocket การเชื่อมต่อเพื่อดำเนินการสำรองข้อมูล - จากนั้นตัวหลักจะได้รับคำสั่งให้ดำเนินการดังกล่าวและจะดำเนินการในภายหลัง:

  1. เชื่อมต่อกับกล่องจดหมายที่เข้ารหัสของคุณ
  2. รับล็อคการเขียน
  3. ดำเนินการจุดตรวจ WAL ผ่าน wal_checkpoint(PASSIVE).
  4. เรียกใช้ VACUUM INTO คำสั่ง SQLite
  5. ตรวจสอบให้แน่ใจว่าไฟล์ที่คัดลอกสามารถเปิดได้ด้วยรหัสผ่านที่เข้ารหัส (การป้องกัน/การป้องกันจำลอง)
  6. อัปโหลดไปยัง Cloudflare R2 เพื่อจัดเก็บข้อมูล (หรือผู้ให้บริการของคุณเอง หากระบุ)
  7. บีบอัดไฟล์สำรองข้อมูลผลลัพธ์ด้วย gzip.
  8. อัปโหลดไปยัง Cloudflare R2 เพื่อจัดเก็บข้อมูล (หรือผู้ให้บริการของคุณเอง หากระบุ)

โปรดจำไว้ว่ากล่องจดหมายของคุณได้รับการเข้ารหัส และแม้ว่าเราจะมีข้อจำกัด IP และมาตรการตรวจสอบสิทธิ์อื่นๆ สำหรับการสื่อสาร WebSocket ในกรณีที่มีผู้ไม่ประสงค์ดี คุณสามารถมั่นใจได้ว่า เว้นแต่เพย์โหลด WebSocket จะมีรหัสผ่าน IMAP ของคุณ จะไม่สามารถเปิดฐานข้อมูลของคุณได้ .

ในขณะนี้ จะมีการจัดเก็บข้อมูลสำรองไว้เพียงรายการเดียวต่อกล่องจดหมาย แต่ในอนาคต เราอาจเสนอการกู้คืน ณ เวลาใดเวลาหนึ่ง ("PITR").

เซิร์ฟเวอร์ IMAP ของเรารองรับ SEARCH คำสั่งที่มีการสืบค้นที่ซับซ้อน นิพจน์ทั่วไป และอื่นๆ

ประสิทธิภาพการค้นหาที่รวดเร็วนั้นต้องขอบคุณ FTS5 และ sqlite-regex.

เราจัดเก็บ Date ค่าในกล่องจดหมาย SQLite เป็น ISO 8601 สตริงผ่าน Date.prototype.toISOString (พร้อมเขตเวลา UTC เพื่อให้การเปรียบเทียบความเท่าเทียมกันทำงานได้อย่างถูกต้อง)

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

โครงการ

นี่คือตารางสรุปโปรเจ็กต์ที่เราใช้ในซอร์สโค้ดและกระบวนการพัฒนาของเรา (เรียงตามตัวอักษร):

โครงการวัตถุประสงค์
เข้าใจได้แพลตฟอร์มอัตโนมัติ DevOps สำหรับการบำรุงรักษา ปรับขนาด และจัดการเซิร์ฟเวอร์ทั้งหมดของเราได้อย่างง่ายดาย
บรีตัวกำหนดเวลางานสำหรับ Node.js และ JavaScript พร้อม cron, วันที่, ms, เวอร์ชันใหม่กว่า และการสนับสนุนที่เป็นมิตรต่อมนุษย์
ห้องโดยสารไลบรารีการบันทึก JavaScript และ Node.js ที่เป็นมิตรกับนักพัฒนาโดยคำนึงถึงความปลอดภัยและความเป็นส่วนตัว
ปล่อยเฟรมเวิร์ก Node.js ซึ่งขับเคลื่อนสถาปัตยกรรมและการออกแบบทางวิศวกรรมทั้งหมดของเราด้วย MVC และอื่นๆ
MongoDBโซลูชันฐานข้อมูล NoSQL ที่เราใช้สำหรับจัดเก็บข้อมูลอื่นๆ ทั้งหมดนอกกล่องจดหมาย (เช่น บัญชี การตั้งค่า โดเมน และการกำหนดค่านามแฝงของคุณ)
พังพอนการสร้างแบบจำลองเอกสารวัตถุ MongoDB ("ODM") ซึ่งเราใช้ทั่วทั้งสแต็กของเรา เราเขียนตัวช่วยพิเศษที่ช่วยให้เราใช้ต่อไปได้ พังพอนกับ SQLite 🎉
โหนด jsNode.js คือสภาพแวดล้อมรันไทม์ JavaScript แบบโอเพ่นซอร์สข้ามแพลตฟอร์มซึ่งรันกระบวนการเซิร์ฟเวอร์ทั้งหมดของเรา
หมายเหตุจดหมายแพ็คเกจ Node.js สำหรับการส่งอีเมล การสร้างการเชื่อมต่อ และอื่นๆ เราเป็นผู้สนับสนุนอย่างเป็นทางการของโครงการนี้
เรดิสฐานข้อมูลในหน่วยความจำสำหรับการแคช เผยแพร่/ติดตามช่อง และ DNS ผ่านคำขอ HTTPS
SQLite3MultipleCiphersส่วนขยายการเข้ารหัสสำหรับ SQLite เพื่ออนุญาตให้ไฟล์ฐานข้อมูลทั้งหมดถูกเข้ารหัส (รวมถึงบันทึกการเขียนล่วงหน้า ("WAL"), บันทึกประจำวัน, การย้อนกลับ, …)
SQLiteStudioโปรแกรมแก้ไข Visual SQLite (ซึ่งคุณสามารถใช้ได้) เพื่อทดสอบ ดาวน์โหลด และดูกล่องจดหมายสำหรับการพัฒนา
SQLiteเลเยอร์ฐานข้อมูลแบบฝังสำหรับพื้นที่จัดเก็บ IMAP ที่ปรับขนาดได้ ครบถ้วนในตัวเอง รวดเร็ว และยืดหยุ่น
เครื่องสแกนสแปมเครื่องมือป้องกันสแปม การกรองอีเมล และการป้องกันฟิชชิ่งของ Node.js (ทางเลือกของเราคือ นักฆ่าสแปม และ ตอบกลับ).
ส้มเขียวหวานDNS ผ่านคำขอ HTTPS ด้วย Node.js และการแคชโดยใช้ Redis ซึ่งรับประกันความสอดคล้องทั่วโลกและอีกมากมาย
ธันเดอร์เบิร์ดทีมพัฒนาของเราใช้สิ่งนี้ (และแนะนำสิ่งนี้ด้วย) เป็น ไคลเอนต์อีเมลที่ต้องการใช้กับส่งต่ออีเมล.
UTMทีมพัฒนาของเราใช้สิ่งนี้เพื่อสร้างเครื่องเสมือนสำหรับ iOS และ macOS เพื่อทดสอบไคลเอนต์อีเมลที่แตกต่างกัน (พร้อมกัน) กับเซิร์ฟเวอร์ IMAP และ SMTP ของเรา
อูบุนตูระบบปฏิบัติการเซิร์ฟเวอร์บน Linux แบบโอเพ่นซอร์สสมัยใหม่ซึ่งขับเคลื่อนโครงสร้างพื้นฐานทั้งหมดของเรา
ไวลด์ดั๊กไลบรารีเซิร์ฟเวอร์ IMAP – ดูหมายเหตุใน การขจัดไฟล์แนบที่ซ้ำกัน และ รองรับโปรโตคอล IMAP.
ดีกว่า-sqlite3-หลายรหัสไลบรารี API ที่รวดเร็วและง่ายดายสำหรับ Node.js เพื่อโต้ตอบกับ SQLite3 โดยทางโปรแกรม
เทมเพลตอีเมลกรอบงานอีเมลที่เป็นมิตรต่อนักพัฒนาเพื่อสร้าง ดูตัวอย่าง และส่งอีเมลที่กำหนดเอง (เช่น การแจ้งเตือนบัญชี และอื่นๆ)
json-sqlตัวสร้างแบบสอบถาม SQL โดยใช้ไวยากรณ์สไตล์ Mongo สิ่งนี้ช่วยประหยัดเวลาของทีมพัฒนาของเราเนื่องจากเราสามารถเขียนต่อไปในสไตล์ Mongo ทั่วทั้งสแต็กด้วยวิธีไม่เชื่อเรื่องฐานข้อมูล นอกจากนี้ยังช่วยหลีกเลี่ยงการโจมตีแบบฉีด SQL โดยใช้พารามิเตอร์แบบสอบถาม
knex-schema-inspectorยูทิลิตี้ SQL เพื่อดึงข้อมูลเกี่ยวกับสคีมาฐานข้อมูลที่มีอยู่ สิ่งนี้ช่วยให้เราตรวจสอบได้อย่างง่ายดายว่าดัชนี ตาราง คอลัมน์ ข้อจำกัด และอื่นๆ ทั้งหมดนั้นถูกต้องและ 1:1 ด้วยวิธีที่ควรจะเป็น เรายังเขียนตัวช่วยอัตโนมัติเพื่อเพิ่มคอลัมน์และดัชนีใหม่หากมีการเปลี่ยนแปลงกับสคีมาฐานข้อมูล (พร้อมการแจ้งเตือนข้อผิดพลาดโดยละเอียดอย่างยิ่งด้วย)
คุกเข่าตัวสร้างแบบสอบถาม SQL ซึ่งเราใช้เฉพาะสำหรับการย้ายฐานข้อมูลและการตรวจสอบสคีมาเท่านั้น knex-schema-inspector.
ส้มแมนดารินอัตโนมัติ i18n การแปลวลีพร้อมรองรับการใช้ Markdown API การแปลของ Google Cloud.
mx-เชื่อมต่อแพ็คเกจ Node.js เพื่อแก้ไขและสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ MX และจัดการข้อผิดพลาด
pm2ผู้จัดการกระบวนการผลิต Node.js พร้อมโหลดบาลานเซอร์ในตัว (ปรับแต่งอย่างละเอียด เพื่อประสิทธิภาพ)
เซิร์ฟเวอร์ smtpไลบรารีเซิร์ฟเวอร์ SMTP – เราใช้สิ่งนี้สำหรับการแลกเปลี่ยนอีเมล ("MX") และเซิร์ฟเวอร์ SMTP ขาออก
ImapTestเครื่องมือที่มีประโยชน์สำหรับการทดสอบเซิร์ฟเวอร์ IMAP เทียบกับเกณฑ์มาตรฐานและความเข้ากันได้ของโปรโตคอล IMAP ตามข้อกำหนด RFC โครงการนี้ถูกสร้างขึ้นโดย โดฟคอต ทีม (เซิร์ฟเวอร์ IMAP และ POP3 แบบโอเพ่นซอร์สที่ใช้งานตั้งแต่เดือนกรกฎาคม 2545) เราได้ทดสอบเซิร์ฟเวอร์ IMAP ของเราอย่างกว้างขวางด้วยเครื่องมือนี้

คุณสามารถค้นหาโครงการอื่น ๆ ที่เราใช้อยู่ ซอร์สโค้ดของเราบน GitHub.

ผู้ให้บริการ

ผู้ให้บริการวัตถุประสงค์
คลาวด์แฟลร์ผู้ให้บริการ DNS, การตรวจสอบสภาพ, โหลดบาลานเซอร์ และพื้นที่เก็บข้อมูลสำรองที่ใช้ คลาวด์แฟลร์ R2.
มหาสมุทรดิจิตอลโฮสติ้งเซิร์ฟเวอร์เฉพาะ พื้นที่เก็บข้อมูลบล็อก SSD และฐานข้อมูลที่ได้รับการจัดการ
วัลเตอร์โฮสติ้งเซิร์ฟเวอร์เฉพาะและพื้นที่เก็บข้อมูลบล็อก SSD

ความคิด

หลักการ

ส่งต่ออีเมลได้รับการออกแบบตามหลักการเหล่านี้:

  1. เป็นมิตรกับนักพัฒนา ให้ความสำคัญกับความปลอดภัยและความเป็นส่วนตัว และโปร่งใสเสมอ
  2. เป็นไปตาม MVC, ยูนิกซ์, KISS, DRY, YAGNI, ปัจจัยสิบสอง, มีดโกนของ Occam, และ การลองใช้
  3. กำหนดเป้าหมายกระท่อนกระแท่น บูตสแตรป และ ราเมนมีกำไร นักพัฒนา

การทดลอง

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

เราได้ทำการทดลองเล็กน้อยซึ่งนำไปสู่โซลูชัน SQLite ขั้นสุดท้ายตามที่กล่าวไว้ข้างต้น

หนึ่งในนั้นคือการลองใช้ อาร์โคลน และ SQLite พร้อมกับเลเยอร์การจัดเก็บข้อมูลที่เข้ากันได้กับ S3

การทดลองนั้นทำให้เราเข้าใจเพิ่มเติมและค้นพบกรณี Edge ที่เกี่ยวข้องกับ rclone, SQLite และ VFS การใช้งาน:

  • หากคุณเปิดใช้งาน --vfs-cache-mode writes ตั้งค่าสถานะด้วย rclone จากนั้นการอ่านจะเป็นเรื่องปกติ แต่การเขียนจะถูกแคชไว้
    • หากคุณมีเซิร์ฟเวอร์ IMAP หลายตัวที่กระจายอยู่ทั่วโลก แคชจะถูกปิดทั่วทั้งเซิร์ฟเวอร์ เว้นแต่คุณจะมีตัวเขียนเพียงตัวเดียวและผู้ฟังหลายตัว (เช่น วิธีการแบบ pub/sub)
    • สิ่งนี้ซับซ้อนอย่างไม่น่าเชื่อ และการเพิ่มความซับซ้อนเพิ่มเติมเช่นนี้จะส่งผลให้เกิดความล้มเหลวจุดเดียวมากขึ้น
    • ผู้ให้บริการพื้นที่จัดเก็บข้อมูลที่เข้ากันได้กับ S3 ไม่รองรับการเปลี่ยนแปลงไฟล์บางส่วน ซึ่งหมายถึงการเปลี่ยนแปลงใด ๆ ของ .sqlite จะส่งผลให้มีการเปลี่ยนแปลงและอัพโหลดฐานข้อมูลใหม่ทั้งหมด
    • โซลูชั่นอื่น ๆ เช่น rsync มีอยู่ แต่ไม่ได้มุ่งเน้นไปที่การบันทึกล่วงหน้า ("WAL") การสนับสนุน – ดังนั้นเราจึงได้ตรวจสอบ Litestream โชคดีที่การใช้การเข้ารหัสของเราได้เข้ารหัสแล้ว WAL ไฟล์ให้เรา ดังนั้นเราจึงไม่จำเป็นต้องพึ่งพา Litestream สำหรับเรื่องนั้น อย่างไรก็ตาม เรายังไม่มั่นใจใน Litestream สำหรับการใช้งานจริง และมีหมายเหตุบางประการด้านล่างนี้
    • การใช้ตัวเลือกนี้ของ --vfs-cache-mode writes (ที่ เท่านั้น วิธีใช้ SQLite แทน rclone สำหรับการเขียน) จะพยายามคัดลอกฐานข้อมูลทั้งหมดตั้งแต่เริ่มต้นในหน่วยความจำ - การจัดการกล่องจดหมายขนาด 10 GB หนึ่งกล่องก็โอเค แต่การจัดการกล่องจดหมายหลายกล่องที่มีพื้นที่จัดเก็บสูงเกินไปจะทำให้เซิร์ฟเวอร์ IMAP ทำงานอยู่ในข้อจำกัดของหน่วยความจำและ ENOMEM ข้อผิดพลาด ข้อผิดพลาดในการแบ่งส่วน และความเสียหายของข้อมูล
  • หากคุณพยายามใช้ SQLite ตารางเสมือนจริง (เช่น การใช้ s3db) เพื่อให้มีข้อมูลอยู่บนเลเยอร์พื้นที่จัดเก็บข้อมูลที่เข้ากันได้กับ S3 คุณจะพบกับปัญหาอื่นๆ อีกหลายปัญหา:
    • การอ่านและเขียนจะช้ามากเนื่องจากตำแหน่งข้อมูล S3 API จะต้องถูกโจมตีด้วย HTTP GET, PUT, HEAD, และ POST วิธีการ
    • การทดสอบการพัฒนาแสดงให้เห็นว่าบันทึกที่เกิน 500K-1M+ บนอินเทอร์เน็ตไฟเบอร์ยังคงถูกจำกัดด้วยปริมาณงานในการเขียนและการอ่านไปยังผู้ให้บริการที่รองรับ S3 ตัวอย่างเช่น นักพัฒนาของเราทำงาน for วนซ้ำเพื่อทำ SQL ตามลำดับทั้งสอง INSERT ข้อความสั่งและข้อความที่เขียนข้อมูลจำนวนมาก ในทั้งสองกรณีประสิทธิภาพการทำงานช้ามาก
    • ตารางเสมือนจริง ไม่สามารถมีดัชนีได้, ALTER TABLE งบและ อื่น ข้อจำกัด – ซึ่งทำให้เกิดความล่าช้ามากกว่า 1-2 นาทีขึ้นไป ขึ้นอยู่กับปริมาณข้อมูล
    • ออบเจ็กต์ถูกจัดเก็บโดยไม่ได้เข้ารหัสและไม่มีการสนับสนุนการเข้ารหัสแบบเนทีฟพร้อมใช้งาน
  • เรายังสำรวจการใช้ sqlite-s3vfs ซึ่งมีแนวความคิดและทางเทคนิคคล้ายกับหัวข้อย่อยก่อนหน้า (ดังนั้นจึงมีปัญหาเดียวกัน) ความเป็นไปได้คือการใช้แบบกำหนดเอง sqlite3 สร้างด้วยการเข้ารหัสเช่น wxSQLite3 (ซึ่งปัจจุบันเราใช้ในโซลูชันของเราด้านบน) ผ่าน แก้ไขไฟล์ติดตั้ง.
  • อีกแนวทางหนึ่งที่เป็นไปได้คือการใช้ ส่วนขยายมัลติเพล็กซ์อย่างไรก็ตาม มีข้อจำกัดอยู่ที่ 32 GB และจะต้องปวดหัวกับการสร้างและการพัฒนาที่ซับซ้อน
  • ALTER TABLE จำเป็นต้องมีคำสั่ง (ดังนั้นสิ่งนี้จึงตัดการใช้ตารางเสมือนโดยสิ้นเชิง) พวกเราต้องการ ALTER TABLE งบเพื่อที่จะเบ็ดของเราด้วย knex-schema-inspector เพื่อให้ทำงานได้อย่างถูกต้อง ซึ่งรับประกันว่าข้อมูลจะไม่เสียหาย และแถวที่ดึงมาสามารถแปลงเป็นเอกสารที่ถูกต้องตามที่เรากำหนด mongoose คำจำกัดความของสคีมา (ซึ่งรวมถึงข้อจำกัด ประเภทตัวแปร และการตรวจสอบข้อมูลตามอำเภอใจ)
  • โปรเจ็กต์ที่เข้ากันได้กับ S3 เกือบทั้งหมดที่เกี่ยวข้องกับ SQLite ในชุมชนโอเพ่นซอร์สนั้นเป็น Python (และไม่ใช่ JavaScript ที่เราใช้สำหรับสแต็กของเรา 100%)
  • ไลบรารีการบีบอัดเช่น sqlite-zstd (ดู ความคิดเห็น) ดูมีแนวโน้ม แต่ อาจยังไม่พร้อมสำหรับการใช้งานการผลิต. แทนที่จะใช้การบีบอัดฝั่งแอปพลิเคชันกับประเภทข้อมูลเช่น String, Object, Map, Array, Set, และ Buffer จะเป็นแนวทางที่สะอาดกว่าและง่ายกว่า (และโยกย้ายได้ง่ายกว่าด้วย เนื่องจากเราสามารถจัดเก็บไฟล์ Boolean ธงหรือคอลัมน์ – หรือแม้แต่การใช้ PRAGMA user_version=1 สำหรับการบีบอัดหรือ user_version=0 โดยไม่มีการบีบอัดเป็นข้อมูลเมตาของฐานข้อมูล)
    • โชคดีที่เราได้นำไฟล์แนบที่ซ้ำกันไปใช้ในพื้นที่จัดเก็บข้อมูลเซิร์ฟเวอร์ IMAP ของเราแล้ว ดังนั้นทุกข้อความที่มีไฟล์แนบเดียวกันจะไม่เก็บสำเนาของไฟล์แนบ แทนที่จะเก็บไฟล์แนบไฟล์เดียวไว้สำหรับข้อความและเธรดหลายรายการในกล่องจดหมาย (และไฟล์แนบต่างประเทศ เพื่อใช้อ้างอิงในภายหลัง)
  • โปรเจ็กต์ Litestream ซึ่งเป็นโซลูชันการจำลองและสำรองข้อมูล SQLite มีแนวโน้มที่ดีและเราจะใช้มันในอนาคต
  • การกู้คืนข้อมูลสำรองจะต้องราบรื่นและไม่สำคัญ การใช้โซลูชันเช่น MongoDB ด้วย mongodump และ mongoexport ไม่เพียงแต่น่าเบื่อเท่านั้น แต่ยังใช้เวลานานและมีความซับซ้อนในการกำหนดค่าอีกด้วย
    • ฐานข้อมูล SQLite ทำให้มันง่าย (เป็นไฟล์เดียว)
    • เราต้องการออกแบบโซลูชันที่ผู้ใช้สามารถนำกล่องจดหมายและออกไปได้ทุกเมื่อ
      • คำสั่ง Node.js อย่างง่ายเพื่อ fs.unlink('mailbox.sqlite')) และจะถูกลบออกจากที่เก็บข้อมูลดิสก์อย่างถาวร
      • ในทำนองเดียวกัน เราสามารถใช้ API ที่เข้ากันได้กับ S3 กับ HTTP DELETE เพื่อลบสแน็ปช็อตและการสำรองข้อมูลสำหรับผู้ใช้ได้อย่างง่ายดาย
    • SQLite เป็นโซลูชันที่ง่ายที่สุด รวดเร็วที่สุด และคุ้มค่าที่สุด

ขาดทางเลือกอื่น

ตามความรู้ของเรา ไม่มีบริการอีเมลอื่นใดที่ได้รับการออกแบบในลักษณะนี้หรือเป็นโอเพ่นซอร์ส

เรา คิดว่านี่อาจเป็นเพราะ ไปยังบริการอีเมลที่มีอยู่ซึ่งมีเทคโนโลยีเดิมในการผลิตด้วย รหัสสปาเก็ตตี้ 🍝.

ผู้ให้บริการอีเมลที่มีอยู่ส่วนใหญ่หากไม่ใช่ทั้งหมดนั้นเป็นแบบปิดหรือโฆษณาเป็นโอเพ่นซอร์ส แต่ในความเป็นจริงมีเพียงส่วนหน้าเท่านั้นที่เป็นโอเพ่นซอร์ส

ส่วนที่ละเอียดอ่อนที่สุดของอีเมล (การโต้ตอบที่เก็บข้อมูล/IMAP/SMTP จริง) เสร็จสิ้นทั้งหมดบนแบ็คเอนด์ (เซิร์ฟเวอร์) และ ไม่ ที่ส่วนหน้า (ไคลเอนต์).

ลองส่งต่ออีเมล

สมัครได้แล้ววันนี้ที่ https://forwardemail.net! 🚀