Phân Tích Bảo Mật PlainApp

PlainApp bảo vệ dữ liệu của bạn trên mạng Wi-Fi nội bộ như thế nào — kèm bằng chứng từ mã nguồn mở.

Tại Sao Bảo Mật Mạng Nội Bộ Lại Quan Trọng?

Khi bạn dùng ứng dụng để quản lý điện thoại Android từ trình duyệt trên máy tính, tin nhắn SMS, ảnh, danh bạ và tập tin của bạn sẽ được truyền qua mạng Wi-Fi. Hầu hết ứng dụng gửi toàn bộ dữ liệu này dưới dạng văn bản thuần không mã hóa. Bất kỳ ai trên cùng mạng đều có thể đọc được.

Bạn có thể nghĩ: "Đây là Wi-Fi nhà mình, ai mà nghe lén?" Nhưng hãy cân nhắc:

  • Wi-Fi công cộng — Quán cà phê, sân bay, khách sạn — bất kỳ ai gần đó đều có thể bắt lưu lượng mạng
  • Mạng dùng chung — Bạn cùng phòng, khách, hoặc thiết bị IoT bị xâm nhập
  • Lỗ hổng router — Firmware lỗi thời với các lỗ hổng đã biết

Nếu một ứng dụng gửi tin nhắn SMS dưới dạng văn bản thuần qua HTTP, bất kỳ ai có công cụ miễn phí như Wireshark đều có thể đọc được. Đây không phải lý thuyết — việc này cực kỳ dễ thực hiện.

Hầu hết ứng dụng quản lý điện thoại đều làm vậy. Mở Chrome DevTools (F12 → tab Network) khi đang dùng giao diện web của chúng, bạn sẽ đọc được mọi lệnh API dưới dạng JSON thuần — nội dung SMS, đường dẫn tập tin, tên liên hệ, mọi thứ.

PlainApp Khác Biệt Như Thế Nào

PlainApp áp dụng nhiều lớp mã hóa và xác thực. Dưới đây là chức năng của từng lớp, giải thích bằng ngôn ngữ dễ hiểu.

Security Architecture Comparison
1

GraphQL API — Chỉ Lấy Dữ Liệu Cần Thiết

Hầu hết ứng dụng dùng REST API kiểu cũ: mỗi tài nguyên một URL, trả về mọi thứ dù bạn có cần hay không. PlainApp sử dụng GraphQL — cách tiếp cận hiện đại cho phép trình duyệt chỉ yêu cầu chính xác dữ liệu cần thiết, không hơn.

Tại sao điều này quan trọng:

  • Ít dữ liệu bị lộ hơn — Nếu bạn chỉ cần tên tập tin, chỉ tên tập tin được gửi đi
  • Một endpoint duy nhất — Chỉ có một URL /graphql thay vì hàng chục, giúp giảm bề mặt tấn công
  • Phân quyền theo truy vấn — Mỗi truy vấn đều kiểm tra quyền riêng (ví dụ: đọc SMS yêu cầu quyền READ_SMS ngay cả sau khi bạn đã đăng nhập)
2

Mã Hóa Lệnh API (XChaCha20-Poly1305)

Đây là điểm khác biệt lớn nhất giữa PlainApp và hầu hết đối thủ.

Mọi yêu cầu và phản hồi API — bao gồm cả lưu lượng HTTP và WebSocket — đều được mã hóa bằng XChaCha20-Poly1305, ở cả chế độ HTTP lẫn HTTPS. Đây là thuật toán mã hóa AEAD hiện đại được sử dụng bởi WireGuard VPN, Cloudflare và thư viện Tink của Google.

Nói đơn giản:

  1. 1Trình duyệt tạo yêu cầu (ví dụ: "hiển thị tin nhắn SMS")
  2. 2Thêm dấu thời gian và nonce ngẫu nhiên để bảo vệ chống phát lại
  3. 3Mã hóa toàn bộ payload thành dữ liệu nhị phân không đọc được bằng XChaCha20-Poly1305
  4. 4Dữ liệu nhị phân đã mã hóa được gửi qua mạng — không base64, không JSON, nhị phân thuần túy
  5. 5Chỉ điện thoại của bạn mới giải mã và xác thực được

Ngay cả khi ai đó chặn bắt lưu lượng mạng, họ chỉ thấy dữ liệu nhị phân vô nghĩa — không phải JSON đọc được.

Encrypted API Flow

Về phương pháp mã hóa:

  • Khóa 256-bit (cực kỳ mạnh)
  • Nonce 192-bit (ngăn chặn một số kiểu tấn công ảnh hưởng tới các thuật toán khác)
  • Tích hợp phát hiện giả mạo — nếu ai đó sửa đổi dữ liệu khi truyền, giải mã sẽ thất bại
  • Phía Android: sử dụng Google Tink
  • Phía Web: sử dụng @noble/ciphers (thư viện mã hóa JavaScript đã được kiểm định kỹ lưỡng)
3

Chữ ký số (Ed25519) — Thiết bị đến thiết bị

Khi hai thiết bị PlainApp giao tiếp với nhau (ví dụ: trò chuyện điện thoại với điện thoại), chỉ mã hóa thôi chưa đủ — mỗi thiết bị cần xác minh rằng tin nhắn thực sự đến từ thiết bị kia và không bị giả mạo.

dấu thời gian

Thiết bị nhận xác minh chữ ký bằng khóa công khai của người gửi và từ chối yêu cầu có dấu thời gian vượt quá 5 phút. Điều này ngăn chặn cả giả mạo và tấn công phát lại.

4

Ghép Nối Thiết Bị An Toàn (Trao Đổi Khóa ECDH)

Khi hai thiết bị PlainApp ghép nối với nhau (ví dụ: hai điện thoại), chúng cần một khóa mã hóa chung. Nhưng gửi khóa qua mạng thì mất ý nghĩa.

PlainApp giải quyết bằng trao đổi khóa ECDH (Elliptic Curve Diffie-Hellman) — cùng nguyên lý toán học dùng trong TLS, Secure Enclave của Apple và WebAuthn:

  1. 1Mỗi thiết bị tạo một cặp khóa (công khai + riêng tư)
  2. 2Chúng chỉ trao đổi khóa công khai
  3. 3Mỗi thiết bị kết hợp khóa riêng tư của mình với khóa công khai của thiết bị kia
  4. 4Cả hai đạt được cùng một bí mật chung — mà nó không bao giờ được truyền qua mạng
ECDH Pairing Flow
5

Mã Hóa URL — Ẩn Đường Dẫn Tập Tin

Đây là chi tiết hầu hết mọi người không để ý: đường dẫn URL cũng tiết lộ thông tin.

Khi bạn tải tập tin, URL cho máy chủ biết bạn muốn tập tin nào. Trong nhiều ứng dụng, URL trông như thế này:

/fs?path=/sdcard/DCIM/Camera/photo_2024.jpg

Bất kỳ ai đánh hơi lưu lượng mạng (hoặc xem lịch sử trình duyệt) đều thấy chính xác tập tin bạn truy cập và cấu trúc thư mục trên điện thoại.

PlainApp mã hóa đường dẫn tập tin trong URL:

/fs?id=AxK9f2mQ7vR3xP8nWz...

Tham số id là đường dẫn tập tin được mã hóa bằng XChaCha20-Poly1305 với một khóa ngẫu nhiên gọi là URL Token. Theo mặc định, khóa này là vĩnh viễn và không thay đổi khi khởi động lại ứng dụng, vì vậy các liên kết đã chia sẻ vẫn tiếp tục hoạt động. Không có khóa, không ai có thể đoán đường dẫn thật, liệt kê tập tin của bạn, hay tạo URL tải về.

URL Encryption Comparison
6

HTTPS với Chứng Chỉ Tự Ký

PlainApp tạo chứng chỉ TLS tự ký trên điện thoại. Điều này thiết lập kênh HTTPS được mã hóa — cùng công nghệ mà ngân hàng và website sử dụng.

Chứng chỉ sử dụng:

  • ECDSA với đường cong P-256 (giống các website lớn)
  • Chữ ký SHA256
  • Lưu trong thư mục riêng tư của ứng dụng

Kết hợp với mã hóa XChaCha20 ở tầng ứng dụng, bạn có hai lớp mã hóa độc lập. Phá vỡ một lớp cũng không giúp ích nếu không phá được lớp còn lại.

7

Bảo Vệ Đăng Nhập

PlainApp giới hạn số lần đăng nhập để ngăn dò mật khẩu:

  • 5 lần thử trong 60 giây cho mỗi địa chỉ IP
  • Sau đó, kết nối sẽ bị từ chối
  • Các bản ghi giới hạn tốc độ quá hạn sẽ được tự động dọn dẹp

HTTP so với HTTPS: Lời Nói Thật

PlainApp cung cấp cả chế độ HTTP và HTTPS. Đây là sự khác biệt thực tế:

Chế độ HTTPChế độ HTTPS
URL đường dẫn tập tinMã hóa (XChaCha20)Mã hóa (XChaCha20)
Lệnh APIMã hóa (XChaCha20)Mã hóa (XChaCha20 + TLS)
Tải tập tinKhông mã hóa khi truyềnMã hóa bởi TLS
Dành cho aiNgười mới (không có cảnh báo SSL)Người dùng quan tâm đến quyền riêng tư

Cả hai chế độ đều mã hóa lệnh API bằng XChaCha20-Poly1305 — tin nhắn SMS, danh bạ và dữ liệu khác của bạn luôn được mã hóa bất kể HTTP hay HTTPS.

Chế độ HTTP tồn tại vì chứng chỉ tự ký sẽ kích hoạt cảnh báo trình duyệt ("Kết nối của bạn không riêng tư"). Với người dùng ít hiểu biết kỹ thuật, cảnh báo này gây hoang mang. HTTP giúp tránh phiền toái này.

Tuy nhiên, chế độ HTTP không mã hóa việc truyền tập tin. Nếu bạn đang dùng mạng chung hoặc công cộng, hãy luôn dùng HTTPS.

Khuyến nghị: Dùng HTTPS bất cứ khi nào có thể. Chấp nhận cảnh báo chứng chỉ tự ký của trình duyệt — điều này là bình thường với ứng dụng mạng nội bộ.

8

Bảo Mật Chuỗi Cung Ứng — Ít Phụ Thuộc, Ít Rủi Ro

Một mối đe dọa bảo mật mà nhiều người dùng không nghĩ tới: tấn công chuỗi cung ứng. Khi ứng dụng sử dụng hàng trăm thư viện bên thứ ba, bất kỳ thư viện nào cũng có thể bị xâm nhập — tiêm mã độc đánh cắp dữ liệu, đào tiền mã hóa, hoặc mở cửa hậu.

Điều này đặc biệt nguy hiểm trong hệ sinh thái JavaScript. Những năm gần đây, các gói npm phổ biến như event-stream, ua-parser-js và colors đã bị chiếm quyền để tiêm mã độc vào hàng triệu dự án. Nếu giao diện web của ứng dụng quản lý điện thoại sử dụng hàng trăm gói JS, mỗi gói đều là vector tấn công tiềm tàng.

PlainApp chọn cách tiếp cận có chủ đích: dùng càng ít thư viện phụ thuộc càng tốt, và tự viết mã khi hợp lý.

Ứng dụng Android (plain-app)

  • Không dùng framework dependency injection (không Hilt, không Dagger) — sử dụng singleton đơn giản
  • Mã hóa chỉ do 3 thư viện nổi tiếng xử lý: Google Tink, Bouncy Castle và Java Cryptography Extension tích hợp sẵn
  • Server chạy trên Ktor (framework Kotlin chính thức của JetBrains) — không dùng thư viện server bên thứ ba kém tên tuổi

Giao diện Web (plain-desktop)

Chỉ 28 thư viện phụ thuộc runtime — ít hơn nhiều so với ứng dụng web thông thường. Nhiều tính năng lẽ ra cần gói npm lại được tự viết từ đầu:

Tính năngỨng dụng thông thườngPlainApp
Âm thanh thông báohowler.js / tone.jsTự viết bộ tổng hợp Web Audio API
Tạo UUIDgói npm uuidTự triển khai theo RFC 4122
Tải tập tin lênuppy / axiosTự viết tải phân mảnh có hàng đợi
Video WebRTCTwilio / Daily.co SDKTự viết mã PeerConnection
HTTP clientaxios / kyDùng fetch gốc của trình duyệt

Mã hóa phía web sử dụng @noble/ciphers — thư viện mã hóa JavaScript không phụ thuộc, được kiểm định kỹ — thay vì dùng các giải pháp cồng kềnh khác.

Tại sao điều này quan trọng

Mỗi thư viện bạn thêm vào là mã bạn không kiểm soát. Cách tiếp cận của PlainApp có nghĩa là:

  • Ít chỗ để mã độc ẩn náu hơn
  • Bề mặt tấn công nhỏ hơn
  • Dễ kiểm tra hơn (toàn bộ mã nguồn là mã nguồn mở)
  • Không có rủi ro từ các gói npm bị bỏ hoang hoặc bị chiếm quyền

Những Sai Lầm Phổ Biến Của Đối Thủ

Đây không nhằm chỉ đích danh ứng dụng nào. Đây là những vấn đề phổ biến trong cả danh mục:

Khía cạnh bảo mậtPlainAppPhổ biến ở đối thủ
Lưu lượng APIMã hóa (XChaCha20) ở cả HTTP và HTTPSJSON thuần qua HTTP
Lưu lượng WebSocketKhung nhị phân được mã hóa (XChaCha20)JSON văn bản thuần hoặc không có WebSocket
Xử lý token xác thựcDùng làm khóa mã hóa, không bao giờ trong headerGửi trong header HTTP (dễ bị lộ)
URL tập tinID đường dẫn được mã hóaĐường dẫn văn bản thuần bị lộ
Trao đổi khóaECDH (P-256)Không có
Ký yêu cầuEd25519 (chỉ thiết bị đến thiết bị)Không
Bảo vệ chống phát lại30 giây + nonce (Web); 5 phút + chữ ký (thiết bị)Không
Bảo vệ đăng nhậpGiới hạn tần suất + xác nhận hai yếu tốKhông giới hạn
Định tuyến dữ liệu100% nội bộ, không qua đám mâyMột số định tuyến qua đám mây
Thư viện phụ thuộcTối thiểu, thư viện nổi tiếngHàng trăm gói npm
Mã nguồnMã nguồn mở (GPL-3.0)Hầu hết mã nguồn đóng

Cách kiểm tra đơn giản nhất: mở Chrome DevTools (F12) → tab Network khi đang dùng ứng dụng. Nếu bạn đọc được phản hồi API dưới dạng JSON, ứng dụng đó không có mã hóa.

Tự Kiểm Chứng

PlainApp hoàn toàn mã nguồn mở. Mọi tuyên bố trong bài viết này đều có thể kiểm chứng trong mã nguồn.

github.com/plainhub/plain-app (GPL-3.0)
Tính toàn vẹn bản phát hành có thể xác minh

Quy trình phát hành tự động, truy vết được và chống can thiệp

Tất cả gói cài đặt đều được xây dựng tự động bởi hạ tầng GitHub và F-Droid. Bản build có thể truy vết, an toàn và không có dấu vết can thiệp thủ công. PlainApp là một trong số ít ứng dụng Android cung cấp cả build có thể xác minh (SLSA) và bản phát hành được quét VirusTotal.

Build tự động trên GitHub và F-Droid

Các artifact phát hành được tạo bởi pipeline CI thay vì đóng gói thủ công cục bộ. Mỗi artifact đều có thể truy ngược tới commit mã nguồn và workflow build tái lập.

SLSA Provenance (Cấp 3) + quét VirusTotal

Mỗi bản phát hành đều có chứng thực SLSA provenance và kết quả quét VirusTotal, giúp chuỗi cung ứng có thể kiểm toán và giúp người dùng xác minh tính toàn vẹn trước khi cài đặt.

Câu hỏi thường gặp

PlainApp có thực sự mã hóa khi dùng chế độ HTTP không?

Có. Tất cả lệnh API (SMS, danh bạ, danh sách tập tin, v.v.) đều được mã hóa bằng XChaCha20-Poly1305 ở cả chế độ HTTP và HTTPS. Chế độ HTTP chỉ không mã hóa việc tải tập tin. Để bảo vệ toàn diện, hãy dùng HTTPS.

Tại sao trình duyệt hiển thị cảnh báo bảo mật?

PlainApp sử dụng chứng chỉ TLS tự ký để mã hóa. Vì chứng chỉ này không được cấp bởi Tổ chức Chứng nhận công cộng, trình duyệt sẽ hiển thị cảnh báo. Điều này là bình thường với ứng dụng mạng nội bộ. Nhấn 'Nâng cao' và 'Tiếp tục' để sử dụng.

Người khác trên cùng Wi-Fi có thể xem dữ liệu của tôi không?

Với PlainApp thì không. Lệnh API được mã hóa bằng XChaCha20-Poly1305, và ở chế độ HTTPS, việc truyền tập tin cũng được mã hóa bởi TLS. Với hầu hết ứng dụng đối thủ thì có — lệnh API của chúng được gửi dưới dạng JSON văn bản thuần.

PlainApp so với VPN thì sao?

VPN mã hóa lưu lượng giữa thiết bị và máy chủ VPN. PlainApp mã hóa lưu lượng giữa điện thoại và trình duyệt trên mạng nội bộ. Chúng phục vụ mục đích khác nhau — PlainApp bảo mật việc quản lý thiết bị nội bộ, trong khi VPN bảo mật lưu lượng internet.

Mã nguồn có thực sự mở không?

Có. PlainApp được cấp phép theo GPL-3.0. Toàn bộ mã nguồn có sẵn tại github.com/plainhub/plain-app. Bạn có thể kiểm tra mọi triển khai mã hóa, tự build từ mã nguồn, hoặc đóng góp.

Lấy lại quyền kiểm soát điện thoại của bạn.

Không có người trung gian trên đám mây. Không có phí hàng tháng. Chỉ cần điện thoại và trình duyệt của bạn.