คำแนะนำในการย้ายข้อมูลโฟลว์ Out-Of-Band (OOB)

ภาพรวม

เมื่อวันที่ 16 กุมภาพันธ์ 2022 เราได้ ประกาศแผนที่จะทำให้การโต้ตอบของ Google OAuth ปลอดภัยขึ้นโดยใช้ขั้นตอน OAuth ที่มีความปลอดภัยมากขึ้น คำแนะนำนี้จะช่วยให้คุณเข้าใจการเปลี่ยนแปลงที่จำเป็นและขั้นตอนการย้ายข้อมูลจากขั้นตอน OAuth นอกขอบเขต (OOB) ไปยังทางเลือกที่รองรับได้สำเร็จ

ความพยายามนี้เป็นมาตรการป้องกันฟิชชิงและการโจมตีแบบแอบอ้างเป็นแอป ในระหว่างการโต้ตอบกับปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google

OOB คืออะไร

OAuth แบบนอกขอบเขต (OOB) หรือที่เรียกว่าตัวเลือกการคัดลอก/วางด้วยตนเองเป็นกระบวนการแบบเดิมที่พัฒนาขึ้นเพื่อรองรับไคลเอ็นต์แบบเนทีฟที่ไม่มี URI การเปลี่ยนเส้นทางเพื่อยอมรับข้อมูลเข้าสู่ระบบหลังจากที่ผู้ใช้อนุมัติคำขอความยินยอมของ OAuth โฟลว์ OOB ก่อให้เกิดความเสี่ยงเกี่ยวกับฟิชชิงจากระยะไกล และลูกค้าต้องย้ายข้อมูลไปยังวิธีการอื่นเพื่อป้องกันช่องโหว่นี้

เราจะเลิกใช้งานโฟลว์ OOB สำหรับไคลเอ็นต์ทุกประเภท ได้แก่ เว็บแอปพลิเคชัน, Android, iOS, Universal Windows Platform (UWP), แอป Chrome, ทีวีและอุปกรณ์อินพุตแบบจำกัด, แอปบนเดสก์ท็อป

วันที่ที่สำคัญในการปฏิบัติตามข้อกำหนด

  • 28 กุมภาพันธ์ 2022 - บล็อกการใช้ OAuth ใหม่สำหรับขั้นตอน OOB
  • 5 กันยายน 2022 - ข้อความเตือนที่แสดงต่อผู้ใช้อาจแสดงสำหรับคำขอ OAuth ที่ไม่เป็นไปตามข้อกำหนด
  • 3 ตุลาคม 2022 - เราจะเลิกใช้งานขั้นตอน OOB สำหรับไคลเอ็นต์ OAuth ที่สร้างขึ้นก่อนวันที่ 28 กุมภาพันธ์ 2022
  • 31 มกราคม 2023 - ลูกค้าที่มีอยู่ทั้งหมดถูกบล็อก (รวมถึงลูกค้าที่ได้รับการยกเว้น)

ข้อความแสดงข้อผิดพลาดที่แสดงต่อผู้ใช้สำหรับคำขอที่ไม่เป็นไปตามนโยบาย ข้อความนี้จะแจ้งให้ผู้ใช้ทราบว่าแอปถูกบล็อกขณะแสดงอีเมลการสนับสนุนที่คุณได้ลงทะเบียนไว้ในหน้าจอคำยินยอม OAuth ในคอนโซล Google API

กระบวนการย้ายข้อมูลมี 2 ขั้นตอนหลักๆ ดังนี้
  1. ตรวจสอบว่าคุณได้รับผลกระทบหรือไม่
  2. ย้ายข้อมูลไปยังทางเลือกที่ปลอดภัยกว่าหากได้รับผลกระทบ

ตรวจสอบว่าคุณได้รับผลกระทบหรือไม่

การเลิกใช้งานนี้จะมีผลเฉพาะกับแอปเวอร์ชันที่ใช้งานจริง (นั่นคือแอปที่ตั้งค่าสถานะการเผยแพร่เป็น ในเวอร์ชันที่ใช้งานจริง ขั้นตอนดังกล่าวจะทำงานต่อไปสำหรับแอปที่มี สถานะการเผยแพร่ทดสอบ

ตรวจสอบสถานะการเผยแพร่ใน OAuth Consent Screen pageของ Google API Console และทำตามขั้นตอนถัดไปหากคุณใช้ ขั้นตอน OOB ในโปรเจ็กต์ที่มีสถานะการเผยแพร่ "ในเวอร์ชันที่ใช้งานจริง"

วิธีตรวจสอบว่าแอปของคุณใช้ขั้นตอน OOB หรือไม่

ตรวจสอบรหัสแอปหรือการโทรออกผ่านเครือข่าย (ในกรณีที่แอปใช้ไลบรารี OAuth) เพื่อดูว่า คำขอการให้สิทธิ์ของ Google OAuth ที่แอปของคุณดำเนินการอยู่โดยใช้ค่า URI การเปลี่ยนเส้นทาง OOB หรือไม่

ตรวจสอบโค้ดของแอปพลิเคชัน

ตรวจสอบส่วนโค้ดของแอปพลิเคชันที่คุณกำลังเรียกใช้ ปลายทางการให้สิทธิ์ของ 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
ตัวอย่างคำขอโฟลว์การเปลี่ยนเส้นทาง 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
ตัวอย่างคำขอขั้นตอนการเปลี่ยนเส้นทาง 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 บนอุปกรณ์เคลื่อนที่ของ Google Sign-In (Android, iOS)

SDK ช่วยให้เข้าถึง Google API ได้ง่ายขึ้นและจัดการการเรียกใช้ทั้งหมดไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google

ลิงก์เอกสารประกอบด้านล่างนี้ให้ข้อมูลเกี่ยวกับวิธีใช้ SDK ของ Google Sign-In เพื่อเข้าถึง Google API โดยไม่ต้องใช้ URI การเปลี่ยนเส้นทาง OOB

เข้าถึง Google APIs บน Android

การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
ตัวอย่างด้านล่างแสดงวิธีเข้าถึง Google APIs จากฝั่งเซิร์ฟเวอร์บน Android
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
  GoogleSignInAccount account = task.getResult(ApiException.class);
  
  // request a one-time authorization code that your server exchanges for an
  // access token and sometimes refresh token
  String authCode = account.getServerAuthCode();
  
  // Show signed-in UI
  updateUI(account);

  // TODO(developer): send code to server and exchange for access/refresh/ID tokens
} catch (ApiException e) {
  Log.w(TAG, "Sign-in failed", e);
  updateUI(null);
}

อ่านคู่มือการเข้าถึงฝั่งเซิร์ฟเวอร์เพื่อดูวิธีเข้าถึง Google APIs จากฝั่งเซิร์ฟเวอร์

เข้าถึง Google APIs ในแอป 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) หรือใช้ผู้ให้สิทธิ์โปรแกรม Googlebot จำลอง (GTMFetcherAuthorizationProtocol) กับ ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Objective-C สําหรับ REST

อ่านคู่มือการเข้าถึงฝั่งไคลเอ็นต์เกี่ยวกับวิธีเข้าถึง Google APIs ในฝั่งไคลเอ็นต์ เกี่ยวกับวิธีเข้าถึง Google APIs ในฝั่งไคลเอ็นต์

การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
ตัวอย่างด้านล่างแสดงวิธีเข้าถึง Google API ในฝั่งเซิร์ฟเวอร์เพื่อรองรับไคลเอ็นต์ 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 APIs จากฝั่งเซิร์ฟเวอร์

ไคลเอ็นต์แอปของ Chrome

หากคิดว่าแอปใช้ขั้นตอน 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 เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเข้าถึงการตรวจสอบสิทธิ์ผู้ใช้และการเรียกใช้ปลายทางของ Google ด้วย Chrome Identity API

เว็บแอปพลิเคชัน

หากคุณพิจารณาว่าแอปกำลังใช้ขั้นตอน OOB สำหรับเว็บแอปพลิเคชัน คุณควรย้ายข้อมูลไปยังไลบรารีของไคลเอ็นต์ Google API ตัวใดตัวหนึ่งของเรา ดูรายการไลบรารีของไคลเอ็นต์สำหรับภาษาโปรแกรมต่างๆ ได้ที่นี่

ไลบรารีเหล่านี้ช่วยให้เข้าถึง Google API และจัดการการเรียกใช้ปลายทางทั้งหมดของ Google ได้อย่างง่ายดาย

การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
โหมดการเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์) กำหนดให้คุณดำเนินการต่อไปนี้
  • สร้างเซิร์ฟเวอร์และกำหนดปลายทางที่เข้าถึงได้แบบสาธารณะ (URI การเปลี่ยนเส้นทาง) เพื่อรับรหัสการให้สิทธิ์
  • กำหนดค่า URI การเปลี่ยนเส้นทาง ใน Credentials page ของ Google API Console

ข้อมูลโค้ดด้านล่างแสดงตัวอย่าง NodeJS ในการใช้ Google Drive API เพื่อแสดงไฟล์ใน Google ไดรฟ์ของผู้ใช้ในฝั่งเซิร์ฟเวอร์โดยไม่ใช้ 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 APIs จากฝั่งเซิร์ฟเวอร์

การเข้าถึงฝั่งไคลเอ็นต์

ใน 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 แบบ Loopback (localhost หรือ 127.0.0.1)