$30 off During Our Annual Pro Sale. View Details »

Protect your backends with Firebase App Check

Protect your backends with Firebase App Check

A powerful layer of security for your backend infrastructure that helps protect access to your services by attesting that incoming traffic is coming from your app, and blocking traffic that doesn't have valid credentials. It helps protect your backend from abuse, such as billing fraud, phishing, app impersonation, and data poisoning.

Firebase Thailand

October 01, 2022
Tweet

More Decks by Firebase Thailand

Other Decks in Technology

Transcript

  1. Bangkok Protect your backends with Firebase App Check Jirawat Karanwittayakarn

    Google Developer Expert in Firebase
  2. Release and Monitor Crashlytics Performance Monitoring Test Lab Engage In-App

    Messaging Predictions Cloud Messaging Remote Config A/B Testing Dynamic Links Build Auth Cloud Functions Cloud Firestore Cloud Storage Hosting Realtime Database
  3. Firebase Security

  4. None
  5. User Data + Security Rules Firebase Auth Firebase Security

  6. None
  7. Firebase App Check

  8. Firebase Google Cloud API Endpoints

  9. None
  10. None
  11. Firebase Resources Cloud Firestore Cloud Storage for Firebase Realtime Database

    Cloud Functions for Firebase
  12. App Check Attestation Providers

  13. Attestation Providers SafetyNet Device Check reCAPTCHA V3 Custom Attestation New

    App Attest reCAPTCHA Enterprise New Play Integrity New reCAPTCHA V3 SafetyNet Device Check
  14. Only supported on iOS 14+ Device Check App Attest And/Or?

  15. To support prior versions to iOS 11, use custom attestation.

    Device Check Supported on iOS 11+ Only supported on iOS 14+ App Attest And
  16. App Check Token and TTL

  17. SafetyNet App Check App Attestation Cloud Firestore App Check Resource

    Access
  18. App Check Backend Issues App Check token with TTL in

    Attestation flow App Check token grants access to Firestore while TTL is valid
  19. App Check Backend App Check token exceeds TTL Re-perform Attestation

    flow to keep valid App Check token Issues App Check token with TTL in Attestation flow
  20. App Check Backend Refreshed App Check token with valid TTL

    Re-perform Attestation flow to keep valid App Check token Issues App Check token with TTL in Attestation flow
  21. 30 Min 7 Days Short TTL Long TTL Recommend 1

    hr for most apps Custom TTL
  22. Custom TTL

  23. App Check Enforcement

  24. None
  25. Secure New Apps Before Launch Migrate Existing Apps

  26. App Check Service Access User Data + Security Rules Firebase

    Auth Better together Firebase Security
  27. Custom Backend Integration

  28. const express = require('express'); const app = express(); const firebaseAdmin

    = require('firebase-admin'); const firebaseApp = firebaseAdmin.initializeApp(); const appCheckVerification = async (req, res, next) => { // implementation details next slide. } app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => { // Handle request. }); App Check in the Backend Service
  29. const appCheckVerification = async (req, res, next) => { const

    appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service
  30. const appCheckVerification = async (req, res, next) => { const

    appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service
  31. const appCheckVerification = async (req, res, next) => { const

    appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service
  32. const appCheckVerification = async (req, res, next) => { const

    appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service
  33. x Custom Backend Resources

  34. class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")

    appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android
  35. class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")

    appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android
  36. class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")

    appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android
  37. class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")

    appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android
  38. x Custom Backend Resources

  39. AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil

    else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS
  40. AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil

    else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS
  41. AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil

    else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS
  42. x Custom Backend Resources

  43. const callApiWithAppCheckExample = async () => { let appCheckTokenResponse; try

    { appCheckTokenResponse = await firebase.appCheck().getToken(false); } catch (err) { return; } const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { headers: { 'X-Firebase-AppCheck': appCheckTokenResponse.token, } }); // Handle response from your backend. }; Custom Backend for Web
  44. const callApiWithAppCheckExample = async () => { let appCheckTokenResponse; try

    { appCheckTokenResponse = await firebase.appCheck().getToken(false); } catch (err) { return; } const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { headers: { 'X-Firebase-AppCheck': appCheckTokenResponse.token, } }); // Handle response from your backend. }; Custom Backend for Web
  45. x Custom Backend Resources

  46. void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if

    (appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter
  47. void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if

    (appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter
  48. void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if

    (appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter
  49. Apigee Integration

  50. None
  51. None
  52. None
  53. Demo

  54. Follow us Youtube.com/FirebaseThailand Fb.com/FirebaseThailand Fb.com/groups/FirebaseDevTh Medium.com/FirebaseThailand