מדריך להעברת זרם מחוץ למסגרת (OOB)

סקירה כללית

ב-16 בפברואר 2022 הודענו על תוכניות להפוך את האינטראקציות עם Google OAuth לבטוחות יותר באמצעות תהליכי OAuth מאובטחים יותר. המדריך הזה יעזור לכם להבין את השינויים והשלבים הנדרשים כדי לבצע בהצלחה מעבר מתהליך OAuth out-of-band ‏ (OOB) לחלופות נתמכות.

המאמץ הזה הוא אמצעי הגנה מפני פישינג ומתקפות התחזות לאפליקציות במהלך אינטראקציות עם נקודות הקצה של הרשאת OAuth 2.0 של Google.

מה זה OOB?

‫OAuth out-of-band (OOB), שנקרא גם האפשרות של העתקה והדבקה ידניות, הוא תהליך מדור קודם שפותח כדי לתמוך בלקוחות מקומיים שאין להם URI להפניה אוטומטית לקבלת פרטי הכניסה אחרי שהמשתמש מאשר בקשת הסכמה ל-OAuth. תהליך OOB יוצר סיכון לפישינג מרחוק, ולכן הלקוחות צריכים לעבור לשיטה חלופית כדי להגן על עצמם מפני נקודת החולשה הזו.

תהליך ה-OOB יוצא משימוש בכל סוגי הלקוחות, כלומר באפליקציות אינטרנט, ב-Android, ב-iOS, בפלטפורמת Windows האוניברסלית (UWP), באפליקציות Chrome, בטלוויזיות ובמכשירים עם קלט מוגבל, ובאפליקציות למחשב.

תאריכים חשובים שקשורים לתאימות

  • 28 בפברואר 2022 – שימוש חדש ב-OAuth נחסם בתהליך OOB
  • 5 בספטמבר 2022 – יכול להיות שתוצג הודעת אזהרה למשתמשים בבקשות OAuth שלא עומדות בדרישות
  • ‫3 באוקטובר 2022 – הוצאנו משימוש את תהליך OOB עבור לקוחות OAuth שנוצרו לפני 28 בפברואר 2022
  • 31 בינואר 2023 – כל הלקוחות הקיימים נחסמים (כולל לקוחות שקיבלו פטור)

לגבי בקשות שלא עומדות בדרישות, תוצג הודעת שגיאה למשתמשים. ההודעה תציין למשתמשים שהאפליקציה חסומה, ותציג את כתובת האימייל לתמיכה שרשמתם במסך ההסכמה ל-OAuth ב-Google API Console.

יש שני שלבים עיקריים להשלמת תהליך ההעברה:
  1. בודקים אם אתם מושפעים מהשינוי.
  2. אם אתם מושפעים מהשינוי, עליכם לעבור לחלופה מאובטחת יותר.

איך יודעים אם השינוי משפיע עליכם

הוצאת התכונה משימוש רלוונטית רק לאפליקציות בסביבת הייצור (כלומר, לאפליקציות שסטטוס הפרסום שלהן מוגדר ל בסביבת הייצור). התהליך ימשיך לפעול באפליקציות עם סטטוס פרסום של בדיקה.

בודקים את סטטוס הפרסום ב-OAuth Branding page של Google Cloud Console וממשיכים לשלב הבא אם משתמשים ב תהליך OOB בפרויקט עם סטטוס פרסום 'בשלב הייצור'.

איך בודקים אם האפליקציה משתמשת בתהליך OOB

בודקים את קוד האפליקציה או את הבקשה היוצאת מהרשת (אם האפליקציה משתמשת בספריית OAuth) כדי לראות אם בקשת ההרשאה של Google OAuth שהאפליקציה שולחת משתמשת בערך של מזהה URI להפניה מחוץ להקשר.

בדיקת קוד האפליקציה

בודקים את החלק בקוד האפליקציה שבו מתבצעות קריאות אל Google OAuth נקודות הקצה של ההרשאה ובודקים אם הפרמטר redirect_uri מכיל אחת מהערכים הבאים:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
בקשה לדוגמה של תהליך הפניה אוטומטית מחוץ לנתיב תיראה כמו הבקשה הבאה:
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>

בדיקת שיחה יוצאת ברשת

השיטה לבדיקת קריאות לרשת משתנה בהתאם לסוג הלקוח של האפליקציה.
במהלך בדיקת קריאות הרשת, מחפשים בקשות שנשלחות אל נקודות הקצה של הרשאת Google OAuth, ובודקים אם הפרמטר redirect_uri מכיל אחד מהערכים הבאים:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
בקשה לדוגמה של תהליך הפניה אוטומטית מחוץ לנתיב תיראה כמו הבקשה הבאה:
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>

מעבר לחלופה מאובטחת

לקוחות לנייד (Android / iOS)

אם קבעתם שהאפליקציה שלכם משתמשת בתהליך OOB עם סוג לקוח OAuth של Android או iOS, אתם צריכים לעבור לשימוש בערכות ה-SDK המומלצות (Android,‏ iOS).

ה-SDK מאפשר גישה קלה ל-Google APIs ומטפל בכל הקריאות לנקודות הקצה של הרשאות OAuth 2.0 של Google.

בקישורים למסמכי התיעוד שבהמשך מוסבר איך להשתמש בערכות ה-SDK המומלצות כדי לגשת לממשקי Google API בלי להשתמש בכתובת URI להפניה אוטומטית של OOB.

גישה אל Google APIs ב-Android

גישה מצד הלקוח

בדוגמה הבאה אפשר לראות איך ניגשים ל-Google APIs בצד הלקוח ב-Android באמצעות ספריית Google Identity Services Android המומלצת.

  List 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));

מעבירים את authorizationResult לשיטה שהגדרתם כדי לשמור את התוכן בתיקיית Drive של המשתמש. ל-authorizationResult יש את ה-method‏ getAccessToken() שמחזיר את טוקן הגישה.

גישה בצד השרת (אופליין)
בדוגמה הבאה מוצגות דרכים לגשת לממשקי Google API בצד השרת ב-Android.
  List 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 יש את ה-method‏ getServerAuthCode() שמחזיר את קוד ההרשאה שאפשר לשלוח לשרת העורפי כדי לקבל אסימון גישה ואסימון רענון.

גישה לממשקי API של Google באפליקציית iOS

גישה מצד הלקוח

בדוגמה הבאה מוסבר איך ניגשים ל-Google APIs בצד הלקוח ב-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()
}

משתמשים באסימון הגישה כדי לקרוא ל-API. אפשר לכלול את אסימון הגישה בכותרת של בקשת REST או gRPC ‏ (Authorization: Bearer ACCESS_TOKEN), או להשתמש ב-fetcher authorizer ‏ (GTMFetcherAuthorizationProtocol) עם ספריית הלקוח של Google APIs ל-Objective-C ל-REST.

במאמר גישה בצד הלקוח מוסבר איך לגשת ל-Google APIs בצד הלקוח. איך לגשת ל-Google APIs בצד הלקוח.

גישה בצד השרת (אופליין)
בדוגמה הבאה מוצגות דרכים לגשת ל-Google APIs בצד השרת כדי לתמוך בלקוח 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
}

במדריך בנושא גישה מצד השרת מוסבר איך לגשת לממשקי Google API מצד השרת.

Chrome App Client

אם קובעים שהאפליקציה משתמשת בתהליך OOB בלקוח של אפליקציית Chrome, צריך לעבור לשימוש ב- Chrome Identity API.

בדוגמה הבאה מוצג אופן קבלת כל אנשי הקשר של המשתמש ללא שימוש בכתובת URI להפניה אוטומטית של OOB.

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

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


  // the example below 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)
    });
   });
 });
};

ב מדריך Chrome Identity API יש מידע נוסף על גישה למשתמשים מאומתים ועל קריאה לנקודות קצה (endpoints) של Google באמצעות Chrome Identity API.

אפליקציית אינטרנט

אם קבעתם שהאפליקציה שלכם משתמשת בתהליך OOB לאפליקציית אינטרנט, עליכם לעבור לשימוש באחת מספריות הלקוח של Google API. כאן מפורטות ספריות לקוח לשפות תכנות שונות.

הספריות מאפשרות לגשת בקלות אל Google APIs ולטפל בכל הקריאות לנקודות הקצה של Google.

גישה בצד השרת (אופליין)
כדי להשתמש במצב גישה בצד השרת (אופליין), צריך לבצע את הפעולות הבאות:
  • מקימים שרת ומגדירים נקודת קצה שגלויה לכולם (כתובת ה-URI להפניה אוטומטית) כדי לקבל את קוד ההרשאה.
  • מגדירים את ה-URI של ההפניה ב- Clients page של Google Cloud Console

קטע הקוד הבא מציג דוגמה ל-NodeJS לשימוש ב-Google Drive API כדי ליצור רשימה של קבצים ב-Google Drive של משתמש בצד השרת, בלי להשתמש ב-URI להפניה אוטומטית של 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.
      });
    }
  }
}

במדריך לאפליקציות אינטרנט בצד השרת מוסבר איך לגשת לממשקי Google API מצד השרת.

גישה מצד הלקוח

בקטע הקוד הבא, ב-JavaScript, מוצגת דוגמה לשימוש ב-Google API כדי לגשת לאירועים ביומן של המשתמש בצד הלקוח.


// 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(...);
}

ב מדריך לאפליקציות אינטרנט בצד הלקוח מוסבר איך לגשת ל-Google APIs מצד הלקוח.

תוכנת לקוח למחשב

אם תגלו שהאפליקציה שלכם משתמשת בתהליך OOB בלקוח למחשב, תצטרכו לעבור לשימוש בתהליך כתובת ה-IP של הלולאה החוזרת (localhost או 127.0.0.1).