Hướng dẫn di chuyển luồng ngoài phạm vi (OOB)

Tổng quan

Vào ngày 16 tháng 2 năm 2022, chúng tôi đã thông báo kế hoạch tăng cường tính an toàn cho các hoạt động tương tác với Google OAuth bằng cách sử dụng các quy trình OAuth an toàn hơn. Hướng dẫn này giúp bạn hiểu rõ những thay đổi và bước cần thiết để di chuyển thành công từ quy trình OAuth ngoài băng tần (OOB) sang các phương án thay thế được hỗ trợ.

Đây là một biện pháp bảo vệ chống lại các cuộc tấn công lừa đảo và mạo danh ứng dụng trong quá trình tương tác với các điểm cuối uỷ quyền OAuth 2.0 của Google.

OOB là gì?

OAuth ngoài băng tần (OOB), còn được gọi là tuỳ chọn sao chép và dán thủ công, là một quy trình cũ được phát triển để hỗ trợ các ứng dụng đã cài đặt không có URI chuyển hướng để chấp nhận thông tin đăng nhập sau khi người dùng phê duyệt yêu cầu đồng ý OAuth. Quy trình OOB có nguy cơ bị lừa đảo từ xa và ứng dụng khách phải chuyển sang một phương thức thay thế để bảo vệ khỏi lỗ hổng bảo mật này.

Quy trình OOB sẽ ngừng hoạt động đối với tất cả các loại ứng dụng, tức là ứng dụng web, Android, iOS, Nền tảng Windows chung (UWP), ứng dụng Chrome, TV và thiết bị có phương thức nhập hạn chế, ứng dụng dành cho máy tính.

Các mốc thời gian quan trọng cần tuân thủ

  • Ngày 28 tháng 2 năm 2022 – chặn việc sử dụng OAuth mới cho quy trình OOB
  • Ngày 5 tháng 9 năm 2022 – thông báo cảnh báo dành cho người dùng có thể xuất hiện đối với các yêu cầu OAuth không tuân thủ chính sách
  • Ngày 3 tháng 10 năm 2022 – quy trình OOB không còn được dùng cho các ứng dụng OAuth được tạo trước ngày 28 tháng 2 năm 2022
  • Ngày 31 tháng 1 năm 2023 – tất cả ứng dụng khách hiện có đều bị chặn (bao gồm cả ứng dụng khách được miễn trừ)

Thông báo lỗi dành cho người dùng sẽ xuất hiện đối với các yêu cầu không tuân thủ. Thông báo này sẽ cho người dùng biết rằng ứng dụng đã bị chặn, đồng thời hiển thị email hỗ trợ mà bạn đã đăng ký trong màn hình xin phép bằng OAuth trong Google Cloud Console.

Có hai bước chính để hoàn tất quá trình di chuyển:

  1. Xác định xem bạn có bị ảnh hưởng hay không.
  2. Hãy chuyển sang một giải pháp thay thế an toàn hơn nếu bạn bị ảnh hưởng.

Xác định xem bạn có bị ảnh hưởng hay không

Việc ngừng sử dụng này chỉ áp dụng cho các ứng dụng chính thức (tức là các ứng dụng có trạng thái xuất bản được đặt thành Đang phát hành. Quy trình này sẽ tiếp tục hoạt động đối với các ứng dụng có Trạng thái xuất bản thử nghiệm.

Xem lại trạng thái xuất bản của bạn trong trang Thương hiệu OAuth của Google Cloud Console và chuyển sang bước tiếp theo nếu bạn đang sử dụng quy trình OOB trong một dự án có trạng thái xuất bản là "Đang phát hành".

Cách xác định xem ứng dụng của bạn có đang sử dụng quy trình OOB hay không

Kiểm tra mã ứng dụng của bạn hoặc lệnh gọi mạng đi (trong trường hợp ứng dụng của bạn đang sử dụng thư viện OAuth) để xác định xem yêu cầu uỷ quyền Google OAuth mà ứng dụng của bạn đang thực hiện có sử dụng giá trị URI chuyển hướng OOB hay không.

Kiểm tra mã xử lý ứng dụng

Xem lại phần mã xử lý ứng dụng mà bạn đang thực hiện lệnh gọi đến điểm cuối uỷ quyền của Google OAuth và xác định xem tham số redirect_uri có giá trị nào sau đây hay không:

  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob

Yêu cầu mẫu về quy trình chuyển hướng ngoài băng tần sẽ có dạng như sau:

https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

Kiểm tra lệnh gọi mạng đi

Phương thức kiểm tra lệnh gọi mạng sẽ khác nhau tuỳ thuộc vào loại ứng dụng của bạn.

Trong khi kiểm tra các lệnh gọi mạng, hãy tìm các yêu cầu được gửi đến điểm cuối uỷ quyền OAuth của Google và xác định xem tham số redirect_uri có giá trị nào sau đây hay không:

  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob

Yêu cầu mẫu về quy trình chuyển hướng ngoài băng tần sẽ có dạng như sau:

https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

Chuyển sang một phương án thay thế an toàn

Ứng dụng di động (Android và iOS)

Nếu xác định rằng ứng dụng của bạn đang sử dụng quy trình OOB với loại ứng dụng OAuth Android hoặc iOS, thì bạn nên di chuyển sang sử dụng các SDK được đề xuất (Android, iOS).

SDK giúp bạn truy cập vào các API của Google và xử lý tất cả lệnh gọi đến điểm cuối uỷ quyền OAuth 2.0 của Google.

Các đường liên kết đến tài liệu sau đây cung cấp thông tin về cách sử dụng SDK được đề xuất để truy cập vào API của Google mà không cần dùng URI chuyển hướng OOB.

Truy cập vào API của Google trên Android

Quyền truy cập phía máy khách

Ví dụ sau đây cho thấy cách truy cập vào API của Google ở phía máy khách trên Android bằng Thư viện Android của Dịch vụ nhận dạng của Google được đề xuất.

List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
AuthorizationRequest authorizationRequest =
    AuthorizationRequest.builder()
        .setRequestedScopes(requestedScopes)
        .build();
Identity.getAuthorizationClient(activity)
    .authorize(authorizationRequest)
    .addOnSuccessListener(
        authorizationResult -> {
          if (authorizationResult.hasResolution()) {
            // Access needs to be granted by the user
            PendingIntent pendingIntent =
                authorizationResult.getPendingIntent();
            try {
              startIntentSenderForResult(
                  pendingIntent.getIntentSender(),
                  REQUEST_AUTHORIZE, null, 0, 0, 0, null);
            } catch (IntentSender.SendIntentException e) {
              Log.e(
                  TAG,
                  "Couldn't start Authorization UI: "
                      + e.getLocalizedMessage());
            }
          } else {
            // Access already granted, continue with user action
            saveToDriveAppFolder(authorizationResult);
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

Truyền authorizationResult vào phương thức đã xác định để lưu nội dung vào thư mục trên Drive của người dùng. authorizationResult có phương thức getAccessToken() trả về mã truy cập.

Quyền truy cập phía máy chủ (ngoại tuyến)

Ví dụ sau đây cho thấy cách truy cập vào API của Google ở phía máy chủ trên Android.

List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
AuthorizationRequest authorizationRequest =
    AuthorizationRequest.builder()
        .requestOfflineAccess(webClientId)
        .setRequestedScopes(requestedScopes)
        .build();
Identity.getAuthorizationClient(activity)
    .authorize(authorizationRequest)
    .addOnSuccessListener(
        authorizationResult -> {
          if (authorizationResult.hasResolution()) {
            // Access needs to be granted by the user
            PendingIntent pendingIntent =
                authorizationResult.getPendingIntent();
            try {
              startIntentSenderForResult(
                  pendingIntent.getIntentSender(),
                  REQUEST_AUTHORIZE, null, 0, 0, 0, null);
            } catch (IntentSender.SendIntentException e) {
              Log.e(
                  TAG,
                  "Couldn't start Authorization UI: "
                      + e.getLocalizedMessage());
            }
          } else {
            String authCode =
                authorizationResult.getServerAuthCode();
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

authorizationResult có phương thức getServerAuthCode() trả về mã uỷ quyền mà bạn có thể gửi đến phần phụ trợ để lấy mã truy cập và mã làm mới.

Truy cập vào API của Google trong ứng dụng iOS

Quyền truy cập phía máy khách

Ví dụ sau đây cho thấy cách truy cập vào API của Google ở phía máy khách trên iOS.

user.authentication.do { authentication, error in
  guard error == nil else { return }
  guard let authentication = authentication else { return }
  
  // Get the access token to attach it to a REST or gRPC request.
  let accessToken = authentication.accessToken
  
  // Or, get an object that conforms to GTMFetcherAuthorizationProtocol for
  // use with GTMAppAuth and the Google APIs client library.
  let authorizer = authentication.fetcherAuthorizer()
}

Sử dụng mã truy cập để gọi API, bằng cách thêm mã truy cập vào tiêu đề của yêu cầu REST hoặc gRPC (Authorization: Bearer <var>ACCESS_TOKEN</var>) hoặc bằng cách sử dụng trình uỷ quyền của trình tìm nạp (GTMFetcherAuthorizationProtocol) với thư viện ứng dụng API của Google cho Objective-C cho REST.

Xem hướng dẫn truy cập phía máy khách để biết cách truy cập vào API của Google ở phía máy khách.

Quyền truy cập phía máy chủ (ngoại tuyến)

Ví dụ sau đây cho thấy cách truy cập vào API của Google ở phía máy chủ để hỗ trợ ứng dụng iOS.

GIDSignIn.sharedInstance.signIn(
    with: signInConfig, presenting: self
) { user, error in
  guard error == nil else { return }
  guard let user = user else { return }
  
  // request a one-time authorization code that your server exchanges for
  // an access token and refresh token
  let authCode = user.serverAuthCode
}

Xem hướng dẫn truy cập phía máy chủ để biết cách truy cập vào API của Google từ phía máy chủ.

Ứng dụng Chrome cho máy khách

Nếu xác định rằng ứng dụng của bạn đang sử dụng quy trình OOB trên ứng dụng Chrome, bạn nên chuyển sang sử dụng Chrome Identity API.

Ví dụ sau đây cho thấy cách lấy tất cả danh bạ của người dùng mà không cần sử dụng URI chuyển hướng OOB.

window.onload = function() {
  document.querySelector('button').addEventListener('click', function() {

  
  // retrieve access token
  chrome.identity.getAuthToken({interactive: true}, function(token) {
  
  // ..........


  // the following example shows how to use a retrieved access token with an
  // appropriate scope to call the Google People API contactGroups.get endpoint

  fetch(
    'https://people.googleapis.com/v1/contactGroups/all'
        + '?maxMembers=20&key=API_KEY',
    init)
    .then((response) => response.json())
    .then(function(data) {
      console.log(data)
    });
   });
 });
};

Xem hướng dẫn về Chrome Identity API để biết thêm thông tin về cách xác thực người dùng và gọi các điểm cuối của Google bằng Chrome Identity API.

Ứng dụng web

Nếu xác định rằng ứng dụng của bạn đang sử dụng quy trình OOB cho một ứng dụng web, thì bạn nên di chuyển sang một trong các thư viện ứng dụng API của Google. Xem danh sách thư viện ứng dụng API của Google cho các ngôn ngữ lập trình khác nhau.

Các thư viện này đơn giản hoá quyền truy cập vào API của Google và xử lý tất cả lệnh gọi đến các điểm cuối của Google.

Quyền truy cập phía máy chủ (ngoại tuyến)

Chế độ truy cập phía máy chủ (ngoại tuyến) yêu cầu bạn làm như sau :

  • Thiết lập một máy chủ và xác định một điểm cuối có thể truy cập công khai (URI chuyển hướng) để nhận mã uỷ quyền.
  • Định cấu hình URI chuyển hướng trong trang ứng dụng của Google Cloud Console

Đoạn mã sau đây cho thấy một ví dụ về NodeJS khi sử dụng API Google Drive để liệt kê các tệp trên Google Drive của người dùng ở phía máy chủ mà không cần sử dụng URI chuyển hướng OOB.

async function main() {
  const server = http.createServer(async function (req, res) {

  if (req.url.startsWith('/oauth2callback')) {
    let q = url.parse(req.url, true).query;

    if (q.error) {
      console.log('Error:' + q.error);
    } else {
      
      // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      // Example of using Google Drive API to list filenames in user's Drive.
      const drive = google.drive('v3');
      drive.files.list({
        auth: oauth2Client,
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err1, res1) => {
        // TODO(developer): Handle response / error.
      });
    }
  }
}

Xem hướng dẫn về ứng dụng web phía máy chủ để biết cách truy cập vào API của Google từ phía máy chủ.

Quyền truy cập phía máy khách

Đoạn mã sau đây (bằng JavaScript) cho thấy ví dụ về cách sử dụng API của Google để truy cập vào các sự kiện trên lịch của người dùng ở phía máy khách.


// initTokenClient() initializes a new token client with your
// web app's client ID and the scope you need access to

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  
  // callback function to handle the token response
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) { 
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

Xem hướng dẫn về ứng dụng web phía máy khách để biết cách truy cập vào API của Google từ phía máy khách.

Ứng dụng dành cho máy tính

Nếu xác định rằng ứng dụng của bạn đang sử dụng quy trình OOB trên ứng dụng dành cho máy tính, thì bạn nên chuyển sang sử dụng quy trình địa chỉ IP lặp lại (localhost hoặc 127.0.0.1).