HomeOur Team
Bảo mật với Flutter - Best Practices [Phần 1]

Bảo mật với Flutter - Best Practices [Phần 1]

By Hai Son Tran
Published in Tips / Tricks
December 29, 2022
5 min read

Lời nói đầu

Trong thời đại 4.0 hiện nay, sự phát triển của công nghệ đã giúp con người rất nhiều trong cuộc sống. Tuy nhiên, đi cùng với sự phát triển là nỗi lo về mặt trái của công nghệ, đặc biệt là việc xâm phạm quyền riêng tư và lỗ hổng trong bảo mật thông tin. Ta thấy rằng, công nghệ càng phát triển, an toàn và bảo mật thông tin càng được chú trọng nhiều hơn. Chính vì vậy, trong bài viết hôm nay, ta sẽ cùng thảo luận về những quy tắc để tăng cường sự bảo mật và giảm thiểu rủi ro mà một lập trình viên Flutter có thể áp dụng khi phát triển ứng dụng của mình.

Trước khi bắt đầu, ta sẽ cùng nhìn lại một số triết lý về bảo mật mà team Flutter đã đưa ra và áp dụng xuyên suốt từ những ngày đầu tiên, bao gồm 5 “key point” sau:

  1. Identify (xác định): theo dõi và ưu tiên những rủi ro bảo mật bằng việc xác định những giá trị cốt lõi, các mối đe dọa và lỗ hổng chính.
  2. Detect (phát hiện): phát hiện và xác định các lỗ hổng bằng cách sử dụng các công cụ như quét lỗ hổng hay kỹ thuật fuzz testing cho ứng dụng.
  3. Protect (bảo vệ): loại bỏ rủi ro bằng cách giảm thiểu các lỗ hổng đã biết và bảo vệ các tài sản quan trọng chống lại các mối đe dọa.
  4. Respond (phản hồi): xác định các quy trình để báo cáo, xử lý và ứng phó với các lỗ hổng hoặc tấn công.
  5. Recover (khôi phục): xây dựng hệ thống có khả năng khôi phục sau sự cố và hạn chế tối đa sự ảnh hưởng.

Trên đây là 5 tiêu chí hàng đầu để xây dựng một ứng dụng Flutter có tính bảo mật cao. Để đáp ứng được 5 tiêu chí này, ta sẽ cùng tìm hiểu các bước cần làm để đạt được điều đó.

1. Cập nhật thường xuyên

Cách đơn giản nhất để tăng cường sự bảo mật và an toàn ứng dụng đó là cập nhật thường xuyên, từ Flutter SDK, plugin cho tới các thư viện được sử dụng, … Các bản cập nhật mới nhất sẽ vá các lỗ hổng tồn đọng và các lỗi có thể ảnh hưởng đến bảo mật của app.

2. Obfuscate code

Thông thường, mã nguồn sau khi được biên dịch thành dạng file binary hoàn toàn có thể sử dụng kỹ thuật dịch ngược (reversed engineering) để chuyển về mã nguồn gốc, qua đó rất dễ bị kẻ gian lợi dụng để đánh cắp các thông tin quan trọng. Chính vì vậy, obfuscate code là một bước quan trọng giúp thay đổi cấu trúc code (thay đổi tên hàm, tên biến, mã hóa chuỗi, thêm các file dummy, …) mà không làm ảnh hưởng đến output của chương trình, từ đó gây ra nhiều khó khăn khi muốn đánh cắp mã nguồn hay tìm kiếm những thông tin có giá trị trong đó.

Hiểu một cách đơn giản, obfuscate code sẽ sắp xếp, thay đổi để code trở nên rối tung và không thể đọc được.

Tìm hiểu thêm về obfuscation tại đây.

Đối với Flutter, ta sẽ thêm biến --obfuscate, kết hợp với --split-debug-info vào lệnh build như sau:

flutter build apk --obfuscate --split-debug-info=/<project-name>/<directory>

Ở đây, --split-debug-info có nhiệm vụ cung cấp địa chỉ của thư mục để Flutter lưu trữ file output debug. Ngoài ra, ta có thể thay thế apk thành appbundle, ipa, hay ios để build các file tương ứng cho iOS và Android.

Lưu ý: khi sử dụng --obfuscate trong lệnh build, ta mới chỉ obfuscate code của Dart. Nếu muốn obfuscate code native Android hay iOS, ta sẽ cần cấu hình hai phần riêng biệt trong từng thư mục /ios/android.

Ta có thể sử dụng ProGuard để obfuscate cho Android và iXGuard cho iOS.

3. Bảo mật API key

API key là một trong những thông tin quan trọng nhất mà ta cần bảo mật và tuyệt đối không để lọt vào tay kẻ gian. Một khi API key bị lộ, hacker có thể dùng để khai thác các thông tin của người dùng và hệ thống. Thông thường, để đảm bảo an toàn và củng cố các lớp bảo mật, ta có thể thực hiện bảo mật API key từ cả hai phía là Server sideClient side.

3.1. Server side

Đối với server, ta sẽ hạn chế quyền truy cập của một API key bằng cách cung cấp các dịch vụ cần thiết tối thiểu cho API key đó, thay vì cho phép truy cập vào tất cả các dịch vụ của hệ thống. Ngoài ra, ta còn có thể encrypt/decrypt API key trực tiếp lúc runtime (ví dụ như xác thực người dùng). Bằng cách này, ta có thể thêm một lớp bảo mật để bảo vệ API key nhằm tránh việc hacker có thể dễ dàng lấy và đọc được.

3.2. Client side

Thứ nhất, không bao giờ commit key trực tiếp lên git, đặc biệt là những dự án public hay open-source. Với những dự án này, để sử dụng API key, ta sẽ dùng các biến môi trường.

Trong Flutter, ta có thể sử dụng thư viện flutter_dotenv để tạo file .env và lưu các key vào trong đó.

Thứ hai, việc tạo biến môi trường có thể giảm thiểu rủi ro bằng cách không public key lên git, tuy nhiên không thể tránh việc key vẫn được sử dụng để compile code, vì vậy hacker vẫn có thể dịch ngược để lấy được key. Khi này, ta sẽ quay lại mục 2 bên trên và thực hiện obfuscate code nhằm mã hóa các key.

Thứ ba, không chia sẻ, trao đổi key, token, dữ liệu qua các kênh chat như Slack, Messenger hay Discord. Thay vào đó, ta có thể sử dụng các công cụ quản lý mật khẩu như 1Password.

Password manager

4. Hạn chế truy cập mạng

Khi ứng dụng gọi API request, các thông tin được trao đổi giữa app và server sẽ xảy ra ở tầng giao vận Transport Layer Security (TLS), trong đó mục tiêu chính của giao thức TLS là cung cấp sự riêng tư và toàn vẹn dữ liệu giữa hai ứng dụng trong môi trường mạng.

Một cách để hạn chế truy cập và bảo đảm việc truy cập đến địa chỉ được xác thực đó là liệt kê các tên miền được sử dụng trong ứng dụng.

  • Với Android, ta sẽ tạo file config android/src/main/res/xml/network_security_config.xml và thêm đoạn code sau:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<certificates src="@raw/my_ca"/>
</trust-anchors>
</domain-config>
</network-security-config>

Tham khảo thêm về config network security Android tại đây

  • Với iOS, ta sẽ config trong file ios/Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>cocoacasts.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

Tham khảo thêm về app transport security iOS tại đây

5. Giới hạn quyền tối thiểu

Một ứng dụng Flutter khi muốn truy cập vào phần cứng của thiết bị hay các API native sẽ phải yêu cầu các quyền tương ứng. Vì vậy, khi sử dụng thư viện bất kỳ của một bên thứ ba, ta cần kiểm tra cẩn thận để xem các quyền mà thư viện cần có đúng với chức năng của nó hay không. Ví dụ, một thư viện sử dụng camera để quay phim, chụp ảnh sẽ cần các quyền liên quan tới camera và bộ nhớ để lưu ảnh hoặc video vào thiết bị, thay vì các quyền không liên quan như network hay location.

Việc kiểm tra và cung cấp các quyền tối thiểu sẽ giúp ta hạn chế được việc bị kẻ gian khai thác dữ liệu và rò rỉ thông tin, từ đó tránh những sự cố đáng tiếc về sau.

Tổng kết

Trong bài viết này, ta đã tìm hiểu 5 bước giúp cải thiện và nâng cao độ bảo mật cho một ứng dụng Flutter. Ở bài viết tiếp theo, ta sẽ cùng tìm hiểu những cách khác có thể giúp ứng dụng an toàn hơn trước những nguy cơ tiềm ẩn của việc bị đánh cắp thông tin, qua đó cải thiện hiệu quả bảo mật cho app.


Tài liệu tham khảo

  1. 10 Tips to Secure Your Flutter Apps
  2. Flutter Security
  3. Flutter Obfuscation
  4. Tìm hiểu về giao thức TLS

Tags

flutter security

Share

Hai Son Tran

Expertise

Related Posts

UI Framework nào phù hợp cho Vue
Tips / Tricks
UI Framework nào phù hợp cho Vue
December 22, 2022
2 min
© 2023, All Rights Reserved.
Powered By

Quick Links

HomeOur Team

Social Media