ภาพรวม
เมื่อวันที่ 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
- ตรวจสอบว่าคุณได้รับผลกระทบหรือไม่
- โปรดเปลี่ยนไปใช้ทางเลือกอื่นที่มีความปลอดภัยมากขึ้นหากคุณได้รับผลกระทบ
ตรวจสอบว่าคุณได้รับผลกระทบหรือไม่
การเลิกใช้งานนี้มีผลกับแอปเวอร์ชันที่ใช้งานจริงเท่านั้น (เช่น แอปที่มี สถานะการเผยแพร่เป็น ในเวอร์ชันที่ใช้งานจริง) ขั้นตอนการทำงานจะยังคงใช้ได้กับแอปที่มี สถานะการเผยแพร่ "กำลังทดสอบ"
ตรวจสอบสถานะการเผยแพร่ใน OAuth Branding page ของ Google Cloud Console และไปยังขั้นตอนถัดไปหากคุณใช้ โฟลว์ OOB ในโปรเจ็กต์ที่มีสถานะการเผยแพร่เป็น "ใช้งานจริง"
วิธีตรวจสอบว่าแอปใช้โฟลว์ OOB หรือไม่
ตรวจสอบโค้ดของแอปหรือ การเรียกเครือข่ายขาออก (ในกรณีที่ แอปใช้ไลบรารี OAuth) เพื่อพิจารณาว่า Google OAuth คำขอให้สิทธิ์ ที่แอปของคุณสร้างขึ้นใช้ค่า URI การเปลี่ยนเส้นทาง OOB หรือไม่
ตรวจสอบโค้ดของแอปพลิเคชัน
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>
ตรวจสอบการเรียกเครือข่ายขาออก
- เว็บแอปพลิเคชัน - ตรวจสอบกิจกรรมเครือข่ายใน Chrome
- Android - ตรวจสอบการรับส่งข้อมูลเครือข่ายด้วย Network Inspector
-
แอป Chrome
- ไปที่หน้าส่วนขยาย Chrome
- เลือกช่องทำเครื่องหมายโหมดนักพัฒนาซอฟต์แวร์ที่มุมบนขวาของหน้าส่วนขยาย
- เลือกส่วนขยายที่ต้องการตรวจสอบ
- คลิกลิงก์หน้าพื้นหลังในส่วนตรวจสอบมุมมองของหน้าส่วนขยาย
- ป๊อปอัปเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์จะเปิดขึ้นเพื่อให้คุณ ตรวจสอบการรับส่งข้อมูลในเครือข่ายได้ใน แท็บเครือข่าย
- iOS - การวิเคราะห์การรับส่งข้อมูล HTTP ด้วย Instruments
- Universal Windows Platform (UWP) - ตรวจสอบการรับส่งข้อมูลเครือข่ายใน Visual Studio
- แอปเดสก์ท็อป - ใช้เครื่องมือจับภาพเครือข่าย พร้อมใช้งานสำหรับระบบปฏิบัติการที่ใช้พัฒนาแอป
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 APIs โดยไม่ต้องใช้ URI เปลี่ยนเส้นทาง OOB
เข้าถึง Google APIs ใน Android
การเข้าถึงฝั่งไคลเอ็นต์
ตัวอย่างต่อไปนี้แสดงวิธีเข้าถึง Google APIs ในฝั่งไคลเอ็นต์บน Android โดยใช้ไลบรารี Android ของบริการระบุตัวตนของ Google ที่แนะนำ
ListrequestedScopes = 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
ไปยังเมธอดที่กำหนดเพื่อบันทึกเนื้อหาลงในโฟลเดอร์ไดรฟ์ของผู้ใช้ authorizationResult
มีเมธอด
getAccessToken()
ที่แสดงผลโทเค็นเพื่อการเข้าถึง
การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
ตัวอย่างต่อไปนี้แสดงวิธีเข้าถึง Google APIs ในฝั่งเซิร์ฟเวอร์บน AndroidListrequestedScopes = 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
มีเมธอด
getServerAuthCode()
ที่แสดงรหัสการให้สิทธิ์ซึ่งคุณสามารถส่งไปยัง
แบ็กเอนด์เพื่อรับโทเค็นการเข้าถึงและการรีเฟรช
เข้าถึง 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
)
หรือใช้เครื่องมือให้สิทธิ์ของตัวดึงข้อมูล (GTMFetcherAuthorizationProtocol
) กับ
ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Objective-C สำหรับ REST
ดู คู่มือการเข้าถึงฝั่งไคลเอ็นต์เกี่ยวกับวิธีเข้าถึง Google API ในฝั่งไคลเอ็นต์ เกี่ยวกับวิธีเข้าถึง Google APIs ในฝั่งไคลเอ็นต์
การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
ตัวอย่างด้านล่างแสดงวิธีเข้าถึง Google API ในฝั่งเซิร์ฟเวอร์เพื่อรองรับไคลเอ็นต์ iOSGIDSignIn.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
หากพิจารณาแล้วว่าแอปของคุณใช้ขั้นตอน 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) }); }); }); };
โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเข้าถึงผู้ใช้ที่ตรวจสอบสิทธิ์และเรียกปลายทางของ Google ด้วย Chrome Identity API ใน คู่มือ Chrome Identity API
เว็บแอปพลิเคชัน
หากพิจารณาแล้วว่าแอปของคุณใช้ขั้นตอน OOB สำหรับเว็บแอปพลิเคชัน คุณควรย้ายข้อมูลไปใช้ไลบรารีของไคลเอ็นต์ Google API อย่างใดอย่างหนึ่งของเรา ไลบรารีของไคลเอ็นต์ สำหรับภาษาโปรแกรมต่างๆ แสดงอยู่ที่นี่
ไลบรารีช่วยให้เข้าถึง Google APIs และจัดการการเรียกไปยัง ปลายทางของ Google ทั้งหมดได้ง่าย
การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)
- สร้างเซิร์ฟเวอร์และกำหนดปลายทางที่เข้าถึงได้แบบสาธารณะ (URI เปลี่ยนเส้นทาง) เพื่อรับรหัสการให้สิทธิ์
- กำหนดค่า URI การเปลี่ยนเส้นทาง ใน Clients page ของ Google Cloud Console
ข้อมูลโค้ดด้านล่างแสดงตัวอย่าง NodeJS ของการใช้ Google ไดรฟ์ API เพื่อแสดงไฟล์ Google ไดรฟ์ของผู้ใช้ในฝั่งเซิร์ฟเวอร์โดยไม่ต้องใช้ OOB URI การเปลี่ยนเส้นทาง
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 API จากฝั่งไคลเอ็นต์
ไคลเอ็นต์บนเดสก์ท็อป
หากพิจารณาแล้วว่าแอปของคุณใช้โฟลว์ OOB ในไคลเอ็นต์เดสก์ท็อป
คุณควรย้ายข้อมูลไปใช้
โฟลว์ที่อยู่ IP ของ Loopback (localhost
หรือ 127.0.0.1
)