Cấu hình bảo mật mạng

Tính năng Cấu hình bảo mật mạng cho phép bạn tuỳ chỉnh các chế độ cài đặt bảo mật mạng của ứng dụng trong một tệp cấu hình an toàn, mang tính khai báo mà không cần sửa đổi mã ứng dụng. Bạn có thể định cấu hình các chế độ cài đặt này cho những miền cụ thể và cho một ứng dụng cụ thể. Dưới đây là các chức năng chính của tính năng này:

  • Neo tin cậy tuỳ chỉnh: Tuỳ chỉnh Tổ chức phát hành chứng chỉ (CA) đáng tin cậy cho các kết nối bảo mật của một ứng dụng. Ví dụ: tin tưởng các chứng chỉ tự ký cụ thể hoặc hạn chế nhóm các CA công khai mà ứng dụng tin tưởng.
  • Ghi đè chế độ chỉ gỡ lỗi: Gỡ lỗi an toàn cho các kết nối bảo mật trong một ứng dụng mà không làm tăng rủi ro cho số lượt cài đặt.
  • Chọn không sử dụng lưu lượng truy cập qua văn bản thô: Bảo vệ các ứng dụng khỏi trường hợp vô tình sử dụng lưu lượng truy cập qua văn bản thô (không được mã hoá).
  • Ghim chứng chỉ: Hạn chế kết nối bảo mật của một ứng dụng với các chứng chỉ cụ thể.

Thêm một tệp Cấu hình bảo mật mạng

Tính năng Cấu hình bảo mật mạng sử dụng một tệp XML nơi bạn chỉ định các chế độ cài đặt cho ứng dụng. Bạn phải đưa một mục nhập vào tệp kê khai của ứng dụng để trỏ đến tệp này. Đoạn mã sau đây được trích từ một tệp kê khai, minh hoạ cách tạo mục nhập này:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

Tuỳ chỉnh CA đáng tin cậy

Bạn có thể muốn ứng dụng của mình tin tưởng một nhóm CA tuỳ chỉnh thay vì nền tảng mặc định. Nguyên nhân phổ biến nhất là do bạn muốn:

  • Kết nối với một máy chủ lưu trữ bằng một CA tuỳ chỉnh, chẳng hạn như CA tự ký hoặc được phát hành nội bộ trong một công ty.
  • Giới hạn một nhóm các CA chỉ gồm các CA mà bạn tin tưởng thay vì mọi CA được cài đặt sẵn.
  • Tin tưởng các CA khác không có trong hệ thống.

Theo mặc định, các kết nối bảo mật (sử dụng những giao thức như Bảo mật tầng truyền tải (TLS) và HTTPS) của mọi ứng dụng sẽ tin tưởng các CA do hệ thống cài đặt sẵn, đồng thời các ứng dụng nhắm đến Android 6.0 (API cấp 23) trở xuống cũng sẽ tin tưởng kho CA do người dùng thêm. Bạn có thể tuỳ chỉnh kết nối của ứng dụng bằng base-config (để tuỳ chỉnh trên toàn ứng dụng) hoặc domain-config (để tuỳ chỉnh theo từng miền).

Định cấu hình một CA tuỳ chỉnh

Bạn nên kết nối với một máy chủ lưu trữ dùng chứng chỉ SSL tự ký hoặc với một máy chủ lưu trữ có chứng chỉ SSL do một CA không công khai mà bạn tin tưởng (chẳng hạn như CA nội bộ của công ty) phát hành. Phần trích dẫn mã sau đây minh hoạ cách định cấu hình ứng dụng cho một CA tuỳ chỉnh trong res/xml/network_security_config.xml:

<?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>

Thêm chứng chỉ CA tự ký hoặc không công khai ở định dạng PEM hoặc DER vào res/raw/my_ca.

Giới hạn nhóm CA đáng tin cậy

Nếu không muốn ứng dụng của mình tin tưởng tất cả các CA mà hệ thống tin cậy, bạn có thể chỉ định một nhóm CA nhỏ hơn để tin tưởng. Việc này giúp bảo vệ ứng dụng khỏi các chứng chỉ gian lận do bất kỳ CA nào khác cấp.

Cấu hình dùng để giới hạn một nhóm các CA đáng tin cậy cũng tương tự như việc tin tưởng một CA tuỳ chỉnh cho một miền cụ thể, ngoại trừ trường hợp có nhiều CA được cung cấp trong tài nguyên. Phần trích dẫn mã sau đây minh hoạ cách giới hạn nhóm CA đáng tin cậy của ứng dụng trong res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <domain includeSubdomains="true">cdn.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/trusted_roots"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

Thêm các CA đáng tin cậy ở định dạng PEM hoặc DER vào res/raw/trusted_roots. Xin lưu ý rằng nếu bạn sử dụng định dạng PEM thì tệp này chỉ được chứa dữ liệu PEM và không được có thêm văn bản. Bạn cũng có thể cung cấp nhiều phần tử <certificates> thay vì một phần tử.

Tin tưởng CA khác

Bạn có thể muốn ứng dụng của mình tin tưởng các CA khác không được hệ thống tin cậy, chẳng hạn như nếu hệ thống chưa bao gồm CA đó hoặc CA đó không đáp ứng các yêu cầu để được đưa vào hệ thống Android. Bạn có thể chỉ định nhiều nguồn chứng chỉ cho một cấu hình trong res/xml/network_security_config.xml bằng cách sử dụng mã như phần trích dẫn sau đây.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/extracas"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

Định cấu hình CA để gỡ lỗi

Khi gỡ lỗi một ứng dụng kết nối qua HTTPS, bạn nên kết nối với một máy chủ phát triển cục bộ không có chứng chỉ SSL cho máy chủ phát hành công khai của mình. Để hỗ trợ việc này mà không cần sửa đổi mã của ứng dụng, bạn có thể chỉ định các CA chỉ gỡ lỗi (chỉ được tin cậy khi android:debuggabletrue) bằng cách sử dụng debug-overrides. Thông thường, các IDE và công cụ tạo ứng dụng sẽ tự động thiết lập cờ này cho các bản dựng không phát hành.

Mã này an toàn hơn so với mã có điều kiện thông thường vì để đảm bảo an toàn, cửa hàng ứng dụng sẽ không chấp nhận các ứng dụng được đánh dấu là có thể gỡ lỗi.

Phần trích dẫn bên dưới minh hoạ cách chỉ định các CA chỉ gỡ lỗi trong res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="@raw/debug_cas"/>
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Chọn không sử dụng lưu lượng truy cập qua văn bản thô

Lưu ý: Hướng dẫn trong phần này chỉ áp dụng cho các ứng dụng nhắm đến Android 8.1 (API cấp 27) trở xuống. Kể từ Android 9 (API cấp 28), tính năng hỗ trợ văn bản thô sẽ bị tắt theo mặc định.

Nếu dự định ứng dụng của mình sẽ kết nối tới các đích đến chỉ sử dụng kết nối bảo mật, thì bạn có thể chọn không hỗ trợ văn bản thô (dùng giao thức HTTP không được mã hoá thay vì HTTPS) cho những đích đến đó. Lựa chọn này giúp ngăn chặn tình trạng hồi quy ngẫu nhiên trong ứng dụng do các thay đổi về URL mà các nguồn bên ngoài cung cấp, chẳng hạn như máy chủ phụ trợ. Hãy xem NetworkSecurityPolicy.isCleartextTrafficPermitted() để biết thêm chi tiết.

Ví dụ: có thể bạn muốn ứng dụng của mình đảm bảo rằng các kết nối đến secure.example.com luôn được thực hiện qua HTTPS để bảo vệ lưu lượng truy cập nhạy cảm khỏi các mạng gây hại.

Phần trích dẫn dưới đây minh hoạ cách chọn không sử dụng văn bản thô trong res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
    </domain-config>
</network-security-config>

Ghim chứng chỉ

Thông thường, một ứng dụng sẽ tin tưởng tất cả các CA được cài đặt sẵn. Nếu bất kỳ CA nào trong số này phát hành một chứng chỉ gian lận, thì ứng dụng đó sẽ gặp rủi ro trước một kẻ tấn công trên đường dẫn. Một số ứng dụng chọn giới hạn một nhóm chứng chỉ mà ứng dụng chấp nhận bằng cách giới hạn một nhóm gồm các CA mà ứng dụng tin tưởng hoặc bằng cách ghim chứng chỉ.

Để ghim chứng chỉ, bạn cần cung cấp một nhóm chứng chỉ theo hàm băm của khoá công khai (SubjectPublicKeyInfo của chứng chỉ X.509). Khi đó, một chuỗi chứng chỉ sẽ chỉ hợp lệ nếu chuỗi chứng chỉ đó chứa ít nhất một trong các khoá công khai đã ghim.

Xin lưu ý rằng khi sử dụng tính năng ghim chứng chỉ, bạn phải luôn đính kèm một khoá dự phòng để nếu bạn buộc phải chuyển sang khoá mới hoặc thay đổi CA (khi ghim vào một chứng chỉ CA hoặc bên trung gian của CA đó), thì khả năng kết nối của ứng dụng sẽ không bị ảnh hưởng. Nếu không, bạn phải phát hành một bản cập nhật cho ứng dụng để khôi phục khả năng kết nối.

Ngoài ra, bạn có thể đặt thời gian hết hạn cho các ghim mà sau thời gian đó thao tác ghim sẽ không thực hiện được. Việc này giúp ngăn chặn các vấn đề về khả năng kết nối trong những ứng dụng chưa được cập nhật. Tuy nhiên, nếu bạn đặt thời gian hết hạn cho ghim, kẻ tấn công có thể vượt qua các chứng chỉ đã ghim của bạn.

Phần trích dẫn dưới đây minh hoạ cách ghim chứng chỉ trong res/xml/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Hành vi kế thừa cấu hình

Các giá trị không được đặt trong một cấu hình cụ thể sẽ được kế thừa. Hành vi này cho phép có các cấu hình phức tạp hơn trong khi vẫn giữ cho tệp cấu hình đó có thể đọc được.

Ví dụ: các giá trị không được thiết lập trong một domain-config sẽ được lấy từ domain-config mẹ, nếu được lồng, hoặc từ base-config, nếu không được lồng. Các giá trị không được thiết lập trong base-config sử dụng giá trị mặc định của nền tảng.

Ví dụ: hãy xem xét một trường hợp trong đó tất cả các kết nối đến miền con của example.com đều phải sử dụng một nhóm CA tuỳ chỉnh. Ngoài ra, lưu lượng truy cập qua văn bản thô đến những miền này đều được phép, ngoại trừ trường hợp kết nối đến secure.example.com. Bằng cách lồng cấu hình của secure.example.com bên trong cấu hình của example.com, bạn sẽ không cần sao chép trust-anchors.

Phần trích dẫn dưới đây cho thấy cách lồng cấu hình này sẽ trông như thế nào trong res/xml/network_security_config.xml:

<?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 cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </domain-config>
</network-security-config>

Định dạng tệp cấu hình

Tính năng Cấu hình bảo mật mạng sử dụng định dạng tệp XML. Cấu trúc tổng thể của tệp này được thể hiện trong mã mẫu sau:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
    </base-config>

    <domain-config>
        <domain>android.com</domain>
        ...
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
        <pin-set>
            <pin digest="...">...</pin>
            ...
        </pin-set>
    </domain-config>
    ...
    <debug-overrides>
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
    </debug-overrides>
</network-security-config>

Các phần sau đây mô tả cú pháp và các thông tin chi tiết khác của định dạng tệp này.

<network-security-config>

có thể chứa:
0 hoặc 1 của <base-config>
Bất kỳ số nào của <domain-config>
0 hoặc 1 của <debug-overrides>

<base-config>

cú pháp:
<base-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</base-config>
có thể chứa:
<trust-anchors>
mô tả:
Cấu hình mặc định được sử dụng bởi mọi kết nối có đích đến không thuộc phạm vi của domain-config.

Mọi giá trị không được thiết lập sẽ sử dụng giá trị mặc định của nền tảng.

Dưới đây là cấu hình mặc định cho các ứng dụng nhắm đến Android 9 (API cấp 28) trở lên:

<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

Dưới đây là cấu hình mặc định cho các ứng dụng nhắm đến Android 7.0 (API cấp 24) cho đến Android 8.1 (API cấp 27):

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

Dưới đây là cấu hình mặc định cho các ứng dụng nhắm đến Android 6.0 (API cấp 23) trở xuống:

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />
    </trust-anchors>
</base-config>

<domain-config>

cú pháp:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</domain-config>
có thể chứa:
1 hoặc nhiều <domain>
0 hoặc 1 <trust-anchors>
0 hoặc 1 <pin-set>
Bất kỳ số nào của <domain-config>
được lồng
mô tả:
Cấu hình được dùng cho các kết nối đến những đích đến cụ thể, do các phần tử domain xác định.

Xin lưu ý rằng nếu nhiều phần tử domain-config cùng xác định một đích đến, thì cấu hình có quy tắc so khớp miền cụ thể nhất (dài nhất) sẽ được sử dụng.

<domain>

cú pháp:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
thuộc tính:
includeSubdomains
Nếu "true", thì quy tắc miền này sẽ so khớp miền và tất cả các miền con, kể cả miền con của miền con. Nếu không, quy tắc này chỉ áp dụng cho các kết quả khớp chính xác.

<debug-overrides>

cú pháp:
<debug-overrides>
    ...
</debug-overrides>
có thể chứa:
0 hoặc 1 <trust-anchors>
mô tả:
Các cơ chế ghi đè sẽ được áp dụng khi android:debuggable"true". Trường hợp này thường xảy ra với các bản dựng không phát hành do được tạo bởi các IDE và công cụ tạo ứng dụng. Các neo tin cậy đã chỉ định trong debug-overrides sẽ được thêm vào tất cả các cấu hình khác và thao tác ghim chứng chỉ sẽ không được thực hiện khi chuỗi chứng chỉ của máy chủ sử dụng một trong các neo tin cậy chỉ gỡ lỗi này. Nếu android:debuggable"false", thì phần này sẽ bị bỏ qua hoàn toàn.

<trust-anchors>

cú pháp:
<trust-anchors>
...
</trust-anchors>
có thể chứa:
Bất kỳ số nào của <certificates>
mô tả:
Bộ neo tin cậy cho các kết nối bảo mật.

<certificates>

cú pháp:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
mô tả:
Nhóm chứng chỉ X.509 cho các phần tử trust-anchors.
thuộc tính:
src
Nguồn của các chứng chỉ CA. Mỗi chứng chỉ có thể có một trong các dạng sau:
  • mã nhận dạng tài nguyên thô trỏ đến một tệp chứa các chứng chỉ X.509. Các chứng chỉ phải được mã hoá theo định dạng DER hoặc PEM. Đối với chứng chỉ PEM, tệp này không được chứa dữ liệu bổ sung không ở định dạng PEM, chẳng hạn như các nhận xét.
  • "system" cho các chứng chỉ CA được cài đặt sẵn của hệ thống
  • "user" cho các chứng chỉ CA do người dùng thêm
overridePins

Chỉ định liệu các CA từ nguồn này có bỏ qua thao tác ghim chứng chỉ hay không. Nếu là "true", thì thao tác ghim sẽ không được thực hiện trên chuỗi chứng chỉ do một trong các CA từ nguồn này ký. Thao tác này có thể hữu ích khi bạn gỡ lỗi các CA hoặc kiểm thử các cuộc tấn công xen giữa đối với lưu lượng truy cập bảo mật của ứng dụng.

Giá trị mặc định là "false" trừ phi được chỉ định trong phần tử debug-overrides. Trong trường hợp này, giá trị mặc định sẽ là "true".

<pin-set>

cú pháp:
<pin-set expiration="date">
...
</pin-set>
có thể chứa:
Bất kỳ số nào của <pin>
mô tả:
Một bộ ghim khoá công khai. Để một kết nối bảo mật được tin tưởng, một trong các khoá công khai trong chuỗi tin cậy phải nằm trong bộ ghim. Hãy xem <pin> để biết định dạng ghim.
thuộc tính:
expiration
Ngày, ở định dạng yyyy-MM-dd, mà vào ngày đó các ghim sẽ hết hạn, khiến tính năng ghim bị tắt. Nếu bạn không đặt thuộc tính này thì ghim sẽ không hết hạn.

Thời gian hết hạn giúp ngăn chặn các vấn đề về khả năng kết nối trong những ứng dụng không nhận được bản cập nhật cho bộ ghim, chẳng hạn như khi người dùng tắt chế độ cập nhật ứng dụng.

<pin>

cú pháp:
<pin digest=["SHA-256"]>base64 encoded digest of X.509
    SubjectPublicKeyInfo (SPKI)</pin>
thuộc tính:
digest
Thuật toán chuỗi đại diện dùng để tạo ghim. Hiện tại, chúng tôi chỉ hỗ trợ "SHA-256".

Tài nguyên khác

Để biết thêm thông tin về Cấu hình bảo mật mạng, hãy tham khảo các tài nguyên sau đây.

Lớp học lập trình