Chấp nhận thông tin xác thực kỹ thuật số trực tuyến

Bạn có thể chấp nhận thẻ căn cước điện tử trong cả quy trình trong ứng dụngtrên web. Để chấp nhận thông tin đăng nhập từ Google Wallet, bạn cần:

  1. Tích hợp bằng ứng dụng hoặc web theo hướng dẫn được cung cấp.
  2. Sử dụng mã nhận dạng kiểm thử để kiểm thử quy trình của bạn trên hộp cát của Google Wallet.
  3. Khi bạn đã sẵn sàng phát hành, hãy điền vào biểu mẫu này để yêu cầu và đồng ý với điều khoản dịch vụ về việc chấp nhận thông tin đăng nhập từ Google Wallet.

Điều kiện tiên quyết

Để kiểm thử việc xuất trình giấy tờ tuỳ thân bằng phương thức kỹ thuật số, trước tiên, bạn phải đăng ký tham gia chương trình thử nghiệm beta công khai bằng tài khoản kiểm thử dự kiến (đây phải là tài khoản Gmail). Sau đó, hãy cung cấp những thông tin chi tiết sau đây cho người liên hệ được chỉ định của bạn tại Google.

  • Đường liên kết đến Điều khoản dịch vụ
  • Biểu trưng
  • Trang web
  • Mã nhận dạng gói ứng dụng (đối với các chế độ tích hợp ứng dụng Android)
    • Bao gồm cả bản gỡ lỗi / bản dành cho nhà phát triển
  • Chữ ký ứng dụng
    • $ $ANDROID_SDK/build-tools/$BUILD_TOOLS_VERSION/apksigner verify --print-certs -v $APK
  • Gmail ID that was used to join the public beta

Định dạng thông tin xác thực được hỗ trợ

Có một số tiêu chuẩn được đề xuất xác định định dạng dữ liệu của tài liệu nhận dạng kỹ thuật số, trong đó có 2 tiêu chuẩn được ngành công nghiệp chấp nhận rộng rãi:

  1. mdocs – do ISO xác định.
  2. Thông tin đăng nhập có thể xác minh của w3c – do w3c xác định.

Mặc dù Trình quản lý thông tin xác thực Android hỗ trợ cả hai định dạng này, nhưng hiện tại Google Wallet chỉ hỗ trợ thẻ căn cước điện tử dựa trên mdoc.

Thông tin đăng nhập được hỗ trợ

Google Wallet hỗ trợ 2 loại thông tin đăng nhập:

  1. Giấy phép lái xe trên thiết bị di động (mDL)
  2. Thẻ giấy tờ tuỳ thân

Bạn có thể yêu cầu một trong hai thông tin đăng nhập trong quy trình của mình chỉ bằng một thay đổi về tham số.

Trải nghiệm người dùng

Phần này trình bày về quy trình trình bày trực tuyến được đề xuất. Luồng này cho thấy cách trình bày độ tuổi cho một ứng dụng giao đồ uống có cồn, nhưng trải nghiệm người dùng cũng tương tự đối với web cũng như các loại bản trình bày khác.

Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng thấy thông tin đăng nhập đủ điều kiện hiện có Người dùng thấy trang xác nhận trong Google Wallet Người dùng xác thực để xác nhận việc chia sẻ Dữ liệu được gửi đến ứng dụng hoặc trang web
Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng thấy thông tin đăng nhập đủ điều kiện hiện có Người dùng thấy trang xác nhận trong Google Wallet Người dùng xác thực để xác nhận việc chia sẻ Dữ liệu được gửi đến ứng dụng hoặc trang web

Ghi chú chính

  1. Ứng dụng hoặc trang web có thể linh hoạt trong cách tạo điểm truy cập vào API. Như minh hoạ trong Bước 1, bạn nên hiển thị một nút chung như "Xác minh bằng thẻ căn cước điện tử" vì theo thời gian, chúng tôi dự kiến sẽ có các lựa chọn khác ngoài Google Wallet thông qua API.
  2. Màn hình bộ chọn ở bước 2 do Android kết xuất. Thông tin đăng nhập đủ điều kiện được xác định bằng cách so khớp giữa logic đăng ký do mỗi Ví cung cấp và yêu cầu do bên đáng tin cậy gửi
  3. Bước 3 do Google Wallet hiển thị. Google Wallet sẽ hiển thị tên, biểu trưng và chính sách quyền riêng tư mà nhà phát triển cung cấp trên màn hình này.

Thêm quy trình sử dụng thẻ căn cước điện tử

Trong trường hợp người dùng không có thông tin đăng nhập, bạn nên cung cấp một đường liên kết bên cạnh nút "Xác minh bằng giấy tờ tuỳ thân kỹ thuật số". Đường liên kết này sẽ liên kết sâu đến Google Wallet để cho phép người dùng thêm giấy tờ tuỳ thân kỹ thuật số.

Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng được chuyển đến Google Wallet để lấy thẻ căn cước điện tử
Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng được chuyển đến Google Wallet để lấy thẻ căn cước điện tử

Không có giấy tờ tuỳ thân điện tử

Nếu người dùng chọn "Xác minh bằng thẻ căn cước điện tử" mà không có thẻ căn cước điện tử, họ sẽ thấy thông báo lỗi này.

Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng sẽ thấy lỗi nếu không có giấy tờ tuỳ thân kỹ thuật số
Người dùng được nhắc xác minh độ tuổi trong ứng dụng hoặc trang web Người dùng sẽ thấy lỗi nếu không có giấy tờ tuỳ thân kỹ thuật số

API này không hỗ trợ tính năng tự động tìm hiểu xem người dùng có mã nhận dạng kỹ thuật số nào hay không để bảo vệ quyền riêng tư của người dùng. Do đó, bạn nên thêm lựa chọn đường liên kết tham gia như minh hoạ.

Định dạng yêu cầu để yêu cầu thông tin nhận dạng từ ví

Sau đây là mẫu yêu cầu mdoc requestJson để lấy thông tin đăng nhập về danh tính từ bất kỳ ví nào trên thiết bị Android hoặc web.

{
      "requests" : [
        {
          "protocol": "openid4vp",
          "data": {<credential_request>} // This is an object, shouldn't be a string.
        }
      ]
}

Yêu cầu mã hoá

client_metadata chứa khoá công khai mã hoá cho từng yêu cầu. Bạn sẽ phải lưu trữ khoá riêng tư cho từng yêu cầu và sử dụng khoá đó để xác thực và uỷ quyền mã thông báo mà bạn nhận được từ ứng dụng ví.

Tham số credential_request trong requestJson sẽ bao gồm các trường sau.

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt",
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "cred1",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"  // this is for mDL. Use com.google.wallet.idcard.1 for ID pass
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ]
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ]
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ]
          }
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",
          "alg" : "ECDH-ES",
        }
      ]
    },
    "authorization_encrypted_response_alg": "ECDH-ES",
    "authorization_encrypted_response_enc": "A128GCM"
  }
}

Bạn có thể yêu cầu bất kỳ số lượng thuộc tính được hỗ trợ nào từ mọi thông tin nhận dạng được lưu trữ trong Google Wallet.

Trong ứng dụng

Để yêu cầu thông tin xác thực danh tính từ các ứng dụng Android, hãy làm theo các bước sau:

Cập nhật phần phụ thuộc

Trong build.gradle của dự án, hãy cập nhật các phần phụ thuộc để sử dụng Trình quản lý thông tin xác thực (bản thử nghiệm):

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    // optional - needed for credentials support from play services, for devices running Android 13 and below.
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

Định cấu hình Trình quản lý thông tin xác thực

Để định cấu hình và khởi tạo một đối tượng CredentialManager, hãy thêm logic tương tự như sau:

// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)

Thuộc tính nhận dạng yêu cầu

Thay vì chỉ định các tham số riêng lẻ cho yêu cầu về danh tính, ứng dụng sẽ cung cấp tất cả các tham số đó cùng nhau dưới dạng một chuỗi JSON trong CredentialOption. Credential Manager sẽ chuyển chuỗi JSON này đến các ví điện tử hiện có mà không kiểm tra nội dung của chuỗi. Sau đó, mỗi ví sẽ chịu trách nhiệm: – Phân tích cú pháp chuỗi JSON để hiểu yêu cầu về danh tính. – Xác định xem có thông tin đăng nhập nào đã lưu trữ đáp ứng yêu cầu hay không.

Các đối tác nên tạo yêu cầu trên máy chủ ngay cả đối với các hoạt động tích hợp ứng dụng Android.

bạn sẽ dùng requestJson từ Request Format (Định dạng yêu cầu) bao gồm request trong lệnh gọi hàm GetDigitalCredentialOption()

// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

Xác minh và xác thực phản hồi

Sau khi nhận được phản hồi từ ví, bạn sẽ xác minh xem phản hồi đó có thành công hay không và có chứa phản hồi credentialJson hay không.

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson) // make a server call to validate the response
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}

Phản hồi credentialJson chứa một identityToken (JWT) đã mã hoá, do W3C xác định. Ứng dụng Wallet chịu trách nhiệm tạo phản hồi này.

Ví dụ:

{
  "protocol" : "openid4vp",
  "data" : {
    <encrpted_response>
  }
}

Bạn sẽ chuyển phản hồi này trở lại máy chủ để xác thực tính xác thực của phản hồi. Bạn có thể xem các bước xác thực phản hồi thông tin xác thực.

Web

Để yêu cầu Thông tin xác thực danh tính bằng Digital Credentials API trên Chrome, bạn cần đăng ký bản dùng thử theo nguyên gốc Digital Credentials API.

const credentialResponse = await navigator.credentials.get({
          digital : {
          requests : [
            {
              protocol: "openid4vp",
              data: {<credential_request>} // This is an object, shouldn't be a string.
            }
          ]
        }
      })

Gửi phản hồi từ API này trở lại máy chủ của bạn để xác thực phản hồi về thông tin đăng nhập

Các bước để xác thực phản hồi thông tin xác thực

Sau khi nhận được identityToken được mã hoá từ ứng dụng hoặc trang web của bạn, bạn cần thực hiện nhiều bước xác thực trước khi tin tưởng phản hồi.

  1. Giải mã phản hồi bằng khoá riêng tư

    Bước đầu tiên là giải mã mã thông báo bằng khoá riêng tư đã lưu và nhận được một JSON phản hồi.

    Ví dụ về Python:

    from jwcrypto import jwe, jwk
    
    # Retrieve the Private Key from Datastore
    reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str)
    
    # Decrypt the JWE encrypted response from Google Wallet
    jwe_object = jwe.JWE()
    jwe_object.deserialize(encrypted_jwe_response_from_wallet)
    jwe_object.decrypt(reader_private_jwk)
    decrypted_payload_bytes = jwe_object.payload
    decrypted_data = json.loads(decrypted_payload_bytes)
    

    decrypted_data sẽ tạo ra một JSON vp_token chứa thông tin đăng nhập

    {
      "vp_token":
      {
        "cred1": "<credential_token>"
      }
    }
    
  2. Tạo bản chép lời phiên học

    Bước tiếp theo là tạo SessionTranscript từ ISO/IEC 18013-5:2021 bằng cấu trúc Bàn giao dành riêng cho Android hoặc Web:

    SessionTranscript = [
      null,                // DeviceEngagementBytes not available
      null,                // EReaderKeyBytes not available
      [
        "OpenID4VPDCAPIHandover",
        AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
      ]
    ]
    

    Đối với cả hoạt động chuyển giao Android / web, bạn sẽ cần sử dụng cùng một số chỉ dùng một lần mà bạn đã dùng để tạo credential_request.

    Android Handover

        AndroidHandoverData = [
          origin,             // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>",
          clientId,           // "android-origin:<app_package_name>",
          nonce,              // nonce that was used to generate credential request
        ]
    
        AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
        

    Chuyển giao trình duyệt

        BrowserHandoverData =[
          origin,               // Origin URL
          clientId,             // "web-origin:<origin>"
          nonce,               //  nonce that was used to generate credential request
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    Khi sử dụng SessionTranscript, DeviceResponse phải được xác thực theo điều khoản 9 của ISO/IEC 18013-5:2021. Quá trình này bao gồm một số bước, chẳng hạn như:

  3. Kiểm tra Chứng chỉ của tổ chức phát hành tiểu bang. Kiểm tra chứng chỉ IACA của tổ chức phát hành được hỗ trợ

  4. Xác minh chữ ký MSO (18013-5 Phần 9.1.2)

  5. Tính toán và kiểm tra ValueDigest cho các Phần tử dữ liệu (18013-5 Phần 9.1.2)

  6. Xác minh chữ ký deviceSignature (18013-5 Phần 9.1.3)

{
  "version": "1.0",
  "documents": [
    {
      "docType": "org.iso.18013.5.1.mDL",
      "issuerSigned": {
        "nameSpaces": {...}, // contains data elements
        "issuerAuth": [...]  // COSE_Sign1 w/ issuer PK, mso + sig
      },
      "deviceSigned": {
        "nameSpaces": 24(<< {} >>), // empty
        "deviceAuth": {
          "deviceSignature": [...] // COSE_Sign1 w/ device signature
        }
      }
    }
  ],
  "status": 0
}

Kiểm thử giải pháp

Để kiểm thử giải pháp của bạn, hãy tạo và chạy trình giữ tham chiếu nguồn mở ứng dụng Android của chúng tôi. Sau đây là các bước để tạo và chạy ứng dụng giữ chỗ tham chiếu:

  • Sao chép kho lưu trữ ứng dụng tham chiếu
  • Mở dự án trên Android Studio
  • Tạo và chạy mục tiêu appholder trên thiết bị Android hoặc trình mô phỏng.

Xác minh dựa trên Bằng chứng không tiết lộ (ZKP)

Chứng minh không tiết lộ (ZKP) là một phương pháp mật mã hoá cho phép một cá nhân (người chứng minh) chứng minh cho người xác minh rằng họ sở hữu một thông tin nhận dạng nhất định hoặc đáp ứng một tiêu chí cụ thể (ví dụ: trên 18 tuổi, có thông tin xác thực hợp lệ) mà không tiết lộ dữ liệu cơ bản thực tế. Về cơ bản, đây là một cách để xác nhận tính xác thực của một tuyên bố về danh tính của một người trong khi vẫn giữ kín các thông tin nhạy cảm.

Các hệ thống nhận dạng kỹ thuật số dựa vào việc chia sẻ trực tiếp dữ liệu nhận dạng thường yêu cầu người dùng chia sẻ quá nhiều thông tin cá nhân, làm tăng nguy cơ rò rỉ dữ liệu và đánh cắp danh tính. ZKP mang đến một sự thay đổi mô hình, cho phép xác minh với mức độ công khai tối thiểu.

Các khái niệm chính về ZKP trong danh tính kỹ thuật số:

  • Người chứng minh: Cá nhân đang cố gắng chứng minh một khía cạnh danh tính của mình.
  • Người xác minh: Pháp nhân yêu cầu bằng chứng về một thuộc tính nhận dạng.
  • Bằng chứng: Một giao thức mật mã cho phép người chứng minh thuyết phục người xác minh về tính xác thực của tuyên bố mà không tiết lộ thông tin bí mật.

Các thuộc tính cốt lõi của bằng chứng không kiến thức:

  • Tính đầy đủ: Nếu câu lệnh là đúng và cả người chứng minh lẫn người xác minh đều trung thực, thì người xác minh sẽ tin tưởng.
  • Tính hợp lệ: Nếu câu lệnh là sai, thì người chứng minh không trung thực không thể (với xác suất rất cao) thuyết phục người xác minh trung thực rằng câu lệnh đó là đúng.
  • Không có kiến thức: Bên xác minh không học được gì ngoài việc câu lệnh là đúng. Không có dữ liệu thực tế nào về danh tính của người chứng minh được tiết lộ.

Để nhận được bằng chứng Zero Knowledge từ Google Wallet, bạn cần thay đổi định dạng yêu cầu thành mso_mdoc_zk và thêm zk_system_type vào Yêu cầu

  ...
  "dcql_query": {
    "credentials": [{
      "id": "cred1",
      "format": "mso_mdoc_zk",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
        "zk_system_type": [
         {
            "system": "longfellow-libzk-v1",
            "circuit_hash": "2093f64f54c81fb2f7f96a46593951d04005784da3d479e4543e2190dcf205d6", //This will differ if you need more than 1 attribute.
            "num_attributes": 1, // number of attributes (in claims) this has can support
            "version": 2
        },
        {
            "system": "longfellow-libzk-v1",
            "circuit_hash": "2836f0df5b7c2c431be21411831f8b3d2b7694b025a9d56a25086276161f7a93", // This will differ if you need more than 1 attribute.
            "num_attributes": 1, // number of attributes (in claims) this has can support
            "version": 1
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...