Google is committed to advancing racial equity for Black communities. See how.
Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Benutzersitzungen verwalten

Firebase-Authentifizierungssitzungen sind langlebig. Jedes Mal, wenn sich ein Benutzer anmeldet, werden die Benutzeranmeldeinformationen an das Firebase-Authentifizierungs-Backend gesendet und gegen ein Firebase-ID-Token (JWT) und ein Aktualisierungstoken ausgetauscht. Firebase-ID-Token sind kurzlebig und halten eine Stunde lang. Mit dem Aktualisierungstoken können neue ID-Token abgerufen werden. Aktualisierungstoken verfallen nur, wenn eine der folgenden Situationen eintritt:

  • Der Benutzer wird gelöscht
  • Der Benutzer ist deaktiviert
  • Für den Benutzer wird eine wesentliche Kontoänderung festgestellt. Dies schließt Ereignisse wie Kennwort- oder E-Mail-Adressaktualisierungen ein.

Das Firebase Admin SDK bietet die Möglichkeit, Aktualisierungstoken für einen bestimmten Benutzer zu widerrufen. Darüber hinaus wird eine API zur Überprüfung der Sperrung von ID-Token bereitgestellt. Mit diesen Funktionen haben Sie mehr Kontrolle über Benutzersitzungen. Das SDK bietet die Möglichkeit, Einschränkungen hinzuzufügen, um zu verhindern, dass Sitzungen unter verdächtigen Umständen verwendet werden, sowie einen Mechanismus zur Wiederherstellung nach potenziellem Token-Diebstahl.

Aktualisierungstoken widerrufen

Sie können das vorhandene Aktualisierungstoken eines Benutzers widerrufen, wenn ein Benutzer ein verlorenes oder gestohlenes Gerät meldet. Wenn Sie eine allgemeine Sicherheitsanfälligkeit entdecken oder einen weit verbreiteten listUsers aktiver Token vermuten, können Sie mithilfe der listUsers API alle Benutzer suchen und ihre Token für das angegebene Projekt widerrufen.

Das Zurücksetzen von Passwörtern widerruft auch die vorhandenen Token eines Benutzers. Das Firebase-Authentifizierungs-Backend übernimmt den Widerruf in diesem Fall jedoch automatisch. Beim Widerruf wird der Benutzer abgemeldet und zur erneuten Authentifizierung aufgefordert.

Hier ist eine Beispielimplementierung, die das Admin-SDK verwendet, um das Aktualisierungstoken eines bestimmten Benutzers zu widerrufen. Befolgen Sie zum Initialisieren des Admin SDK die Anweisungen auf der Setup-Seite .

Node.js

// Revoke all refresh tokens for a specified user for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
admin
  .auth()
  .revokeRefreshTokens(uid)
  .then(() => {
    return admin.auth().getUser(uid);
  })
  .then((userRecord) => {
    return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
  })
  .then((timestamp) => {
    console.log(`Tokens revoked at: ${timestamp}`);
  });

Java

FirebaseAuth.getInstance().revokeRefreshTokens(uid);
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
// Convert to seconds as the auth_time in the token claims is in seconds too.
long revocationSecond = user.getTokensValidAfterTimestamp() / 1000;
System.out.println("Tokens revoked at: " + revocationSecond);

Python

# Revoke tokens on the backend.
auth.revoke_refresh_tokens(uid)
user = auth.get_user(uid)
# Convert to seconds as the auth_time in the token claims is in seconds.
revocation_second = user.tokens_valid_after_timestamp / 1000
print('Tokens revoked at: {0}'.format(revocation_second))

Gehen

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
if err := client.RevokeRefreshTokens(ctx, uid); err != nil {
	log.Fatalf("error revoking tokens for user: %v, %v\n", uid, err)
}
// accessing the user's TokenValidAfter
u, err := client.GetUser(ctx, uid)
if err != nil {
	log.Fatalf("error getting user %s: %v\n", uid, err)
}
timestamp := u.TokensValidAfterMillis / 1000
log.Printf("the refresh tokens were revoked at: %d (UTC seconds) ", timestamp)

C #

await FirebaseAuth.DefaultInstance.RevokeRefreshTokensAsync(uid);
var user = await FirebaseAuth.DefaultInstance.GetUserAsync(uid);
Console.WriteLine("Tokens revoked at: " + user.TokensValidAfterTimestamp);

ID-Token-Widerruf erkennen

Da es sich bei Firebase-ID-Token um zustandslose JWTs handelt, können Sie feststellen, dass ein Token nur widerrufen wurde, indem Sie den Status des Tokens vom Firebase-Authentifizierungs-Backend anfordern. Aus diesem Grund ist die Durchführung dieser Überprüfung auf Ihrem Server ein teurer Vorgang, der einen zusätzlichen Netzwerk-Roundtrip erfordert. Sie können diese Netzwerkanforderung vermeiden, indem Sie Firebase-Regeln einrichten, die auf Widerruf prüfen, anstatt das Admin-SDK für die Prüfung zu verwenden.

Erkennen des Widerrufs von ID-Token in Datenbankregeln

Um die Sperrung des ID-Tokens anhand von Datenbankregeln erkennen zu können, müssen zunächst einige benutzerspezifische Metadaten gespeichert werden.

Aktualisieren Sie benutzerspezifische Metadaten in der Firebase-Echtzeitdatenbank.

Speichern Sie den Zeitstempel für die Sperrung des Aktualisierungstokens. Dies ist erforderlich, um den Widerruf von ID-Token über Firebase-Regeln zu verfolgen. Dies ermöglicht effiziente Überprüfungen innerhalb der Datenbank. Verwenden Sie in den folgenden Codebeispielen die im vorherigen Abschnitt angegebene UID und die Sperrzeit.

Node.js

const metadataRef = admin.database().ref('metadata/' + uid);
metadataRef.set({ revokeTime: utcRevocationTimeSecs }).then(() => {
  console.log('Database updated successfully.');
});

Java

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("metadata/" + uid);
Map<String, Object> userData = new HashMap<>();
userData.put("revokeTime", revocationSecond);
ref.setValueAsync(userData);

Python

metadata_ref = firebase_admin.db.reference("metadata/" + uid)
metadata_ref.set({'revokeTime': revocation_second})

Fügen Sie den Datenbankregeln ein Häkchen hinzu

Um diese Prüfung zu erzwingen, richten Sie eine Regel ohne Client-Schreibzugriff ein, um die Sperrzeit pro Benutzer zu speichern. Dies kann mit dem UTC-Zeitstempel der letzten Sperrzeit aktualisiert werden, wie in den vorherigen Beispielen gezeigt:

{
  "rules": {
    "metadata": {
      "$user_id": {
        // this could be false as it is only accessed from backend or rules.
        ".read": "$user_id === auth.uid",
        ".write": "false",
      }
    }
  }
}

Für alle Daten, für die ein authentifizierter Zugriff erforderlich ist, muss die folgende Regel konfiguriert sein. Diese Logik ermöglicht nur authentifizierten Benutzern mit nicht widerrufenen ID-Token den Zugriff auf die geschützten Daten:

{
  "rules": {
    "users": {
      "$user_id": {
        ".read": "$user_id === auth.uid && (
            !root.child('metadata').child(auth.uid).child('revokeTime').exists()
          || auth.token.auth_time > root.child('metadata').child(auth.uid).child('revokeTime').val()
        )",
        ".write": "$user_id === auth.uid && (
            !root.child('metadata').child(auth.uid).child('revokeTime').exists()
          || auth.token.auth_time > root.child('metadata').child(auth.uid).child('revokeTime').val()
        )",
      }
    }
  }
}

Erkennen Sie den Widerruf von ID-Token im SDK.

Implementieren Sie auf Ihrem Server die folgende Logik für die Sperrung von Aktualisierungstoken und die Validierung von ID-Token:

Wenn ein ID - Token des Benutzers überprüft werden, die zusätzliche checkRevoked hat boolean - Flag übergeben werden verifyIdToken . Wenn das Token des Benutzers widerrufen wird, sollte der Benutzer auf dem Client abgemeldet oder aufgefordert werden, sich mithilfe der von den SDBs des Firebase-Authentifizierungsclients bereitgestellten Authentifizierungs-APIs erneut zu authentifizieren.

Befolgen Sie die Anweisungen auf der Setup-Seite, um das Admin SDK für Ihre Plattform zu initialisieren. Beispiele zum Abrufen des ID-Tokens finden Sie im Abschnitt verifyIdToken .

Node.js

// Verify the ID token while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
admin
  .auth()
  .verifyIdToken(idToken, checkRevoked)
  .then((payload) => {
    // Token is valid.
  })
  .catch((error) => {
    if (error.code == 'auth/id-token-revoked') {
      // Token has been revoked. Inform the user to reauthenticate or signOut() the user.
    } else {
      // Token is invalid.
    }
  });

Java

try {
  // Verify the ID token while checking if the token is revoked by passing checkRevoked
  // as true.
  boolean checkRevoked = true;
  FirebaseToken decodedToken = FirebaseAuth.getInstance()
      .verifyIdToken(idToken, checkRevoked);
  // Token is valid and not revoked.
  String uid = decodedToken.getUid();
} catch (FirebaseAuthException e) {
  if (e.getAuthErrorCode() == AuthErrorCode.REVOKED_ID_TOKEN) {
    // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
  } else {
    // Token is invalid.
  }
}

Python

try:
    # Verify the ID token while checking if the token is revoked by
    # passing check_revoked=True.
    decoded_token = auth.verify_id_token(id_token, check_revoked=True)
    # Token is valid and not revoked.
    uid = decoded_token['uid']
except auth.RevokedIdTokenError:
    # Token revoked, inform the user to reauthenticate or signOut().
    pass
except auth.InvalidIdTokenError:
    # Token is invalid
    pass

Gehen

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.VerifyIDTokenAndCheckRevoked(ctx, idToken)
if err != nil {
	if err.Error() == "ID token has been revoked" {
		// Token is revoked. Inform the user to reauthenticate or signOut() the user.
	} else {
		// Token is invalid
	}
}
log.Printf("Verified ID token: %v\n", token)

C #

try
{
    // Verify the ID token while checking if the token is revoked by passing checkRevoked
    // as true.
    bool checkRevoked = true;
    var decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(
        idToken, checkRevoked);
    // Token is valid and not revoked.
    string uid = decodedToken.Uid;
}
catch (FirebaseAuthException ex)
{
    if (ex.AuthErrorCode == AuthErrorCode.RevokedIdToken)
    {
        // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
    }
    else
    {
        // Token is invalid.
    }
}

Reagieren Sie auf den Token-Widerruf auf dem Client

Wenn das Token über das Admin-SDK widerrufen wird, wird der Client über den Widerruf informiert und der Benutzer muss sich erneut authentifizieren oder abmelden:

function onIdTokenRevocation() {
  // For an email/password user. Prompt the user for the password again.
  let password = prompt('Please provide your password for reauthentication');
  let credential = firebase.auth.EmailAuthProvider.credential(
      firebase.auth().currentUser.email, password);
  firebase.auth().currentUser.reauthenticateWithCredential(credential)
    .then(result => {
      // User successfully reauthenticated. New ID tokens should be valid.
    })
    .catch(error => {
      // An error occurred.
    });
}

Erweiterte Sicherheit: Erzwingen Sie IP-Adressbeschränkungen

Ein gängiger Sicherheitsmechanismus zum Erkennen von Token-Diebstahl besteht darin, den Ursprung der IP-Adresse der Anforderung zu verfolgen. Wenn beispielsweise Anforderungen immer von derselben IP-Adresse kommen (Server, der den Anruf tätigt), können Sitzungen mit einer einzelnen IP-Adresse erzwungen werden. Sie können das Token eines Benutzers auch widerrufen, wenn Sie feststellen, dass sich die IP-Adresse des Benutzers plötzlich geändert hat oder Sie eine Anfrage von einem verdächtigen Ursprung erhalten.

Um Sicherheitsüberprüfungen basierend auf der IP-Adresse durchzuführen, überprüfen Sie für jede authentifizierte Anforderung das ID-Token und prüfen Sie, ob die IP-Adresse der Anforderung mit früheren vertrauenswürdigen IP-Adressen übereinstimmt oder innerhalb eines vertrauenswürdigen Bereichs liegt, bevor Sie den Zugriff auf eingeschränkte Daten zulassen. Beispielsweise:

app.post('/getRestrictedData', (req, res) => {
  // Get the ID token passed.
  const idToken = req.body.idToken;
  // Verify the ID token, check if revoked and decode its payload.
  admin.auth().verifyIdToken(idToken, true).then((claims) => {
    // Get the user's previous IP addresses, previously saved.
    return getPreviousUserIpAddresses(claims.sub);
  }).then(previousIpAddresses => {
    // Get the request IP address.
    const requestIpAddress = req.connection.remoteAddress;
    // Check if the request IP address origin is suspicious relative to previous
    // IP addresses. The current request timestamp and the auth_time of the ID
    // token can provide additional signals of abuse especially if the IP address
    // suddenly changed. If there was a sudden location change in a
    // short period of time, then it will give stronger signals of possible abuse.
    if (!isValidIpAddress(previousIpAddresses, requestIpAddress)) {
      // Invalid IP address, take action quickly and revoke all user's refresh tokens.
      revokeUserTokens(claims.uid).then(() => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      }, error => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      });
    } else {
      // Access is valid. Try to return data.
      getData(claims).then(data => {
        res.end(JSON.stringify(data);
      }, error => {
        res.status(500).send({ error: 'Server error!' })
      });
    }
  });
});