Firebase Authentication oturum uzun ömürlüdür. Kullanıcı her oturum açtığında kullanıcı kimlik bilgileri Firebase Authentication arka ucuna gönderilir ve Firebase kimlik jetonu (JWT) ve yenileme jetonu. Firebase kimlik jetonları kısa ömürlüdür ve bir saat sürer; yenileme jetonu yeni kimlik jetonlarını almak için kullanılabilir. Yenileme jetonlarının süresi yalnızca aşağıdakilerden biri gerçekleştiğinde sona erer:
- Kullanıcı silindi
- Kullanıcı devre dışı bırakıldı
- Kullanıcı için önemli bir hesap değişikliği algılandı. Şifre veya e-posta adresi güncellemeleri gibi etkinlikler de buna dahildir.
Firebase Admin SDK, bir kullanıcı için yenileme jetonlarını iptal etmeyi sağlayan belirtilen kullanıcı. Buna ek olarak, kimlik jetonunun iptalini kontrol eden bir API de yardımcı olur. Bu özellikler sayesinde kullanıcı üzerinde daha fazla kontrole sahip olursunuz. anlamına gelir. SDK, oturumları önlemek için kısıtlamalar ekleme olanağı sağlar şüpheli durumlarda kullanılmasını engelleme, korumanıza yardımcı olur.
Yenileme jetonlarını iptal et
Bir kullanıcı, Search Console'da kaybolan veya
cihaz çalındı. Benzer şekilde, genel bir güvenlik açığı keşfederseniz veya
geniş çaplı bir etkin jeton sızıntısı varsa,
listUsers
API'yi kullanarak tüm kullanıcıları arayabilir ve belirtilen proje için jetonlarını iptal edebilirsiniz.
Şifre sıfırlama işlemi, kullanıcının mevcut jetonlarını da iptal eder; ancak Bu durumda Firebase Authentication arka ucu iptal işlemini otomatik olarak gerçekleştirir. İptal edildiğinde kullanıcının oturumu kapatılır ve yeniden kimlik doğrulaması yapması istenir.
Aşağıda, yenilemeyi iptal etmek için Admin SDK'yı kullanan örnek bir uygulama verilmiştir jetonundan oluşur. Admin SDK'yı başlatmak için şu sayfadaki talimatları uygulayın: kurulum sayfasına gidin.
Node.js
// Revoke all refresh tokens for a specified user for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
getAuth()
.revokeRefreshTokens(uid)
.then(() => {
return getAuth().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))
Go
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);
Kimlik jetonu iptalini algılama
Firebase kimlik jetonları durum bilgisiz JWT'ler olduğundan, bir jetonun yalnızca Firebase Authentication aracından jetonun durumu istenerek iptal edildi arka uçta olması gerekir. Bu nedenle, sunucunuzda bu kontrolün yapılması ve fazladan ağ gidiş dönüşü gerektirir. Aksi takdirde iptali kontrol eden Firebase Security Rules ayarlarını yaparak ağ isteği tercih edebilirsiniz.
Firebase Security Rules içinde kimlik jetonu iptalini tespit et
Güvenlik Kuralları'nı kullanarak kimlik jetonu iptalini tespit edebilmek için önce kullanıcıya özel bazı meta verileri depolamalıdır.
Kullanıcıya özel meta verileri Firebase Realtime Database ürününde güncelleyin.
Yenileme jetonu iptali zaman damgasını kaydedin. Bu, kimlik jetonunu izlemek için gereklidir Firebase Security Rules aracılığıyla iptal. Böylece belirli aralıklarla kontrol eder. Aşağıdaki kod örneklerinde, bölümüne göz atın.
Node.js
const metadataRef = getDatabase().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})
Firebase Security Rules için bir çek ekleyin
Bu kontrolü zorunlu kılmak için aşağıdaki verileri depolamak üzere istemci yazma erişimi olmayan bir kural oluşturun: her kullanıcı için iptal süresidir. Bu, önceki örneklerde gösterildiği gibi son iptal zamanı:
{
"rules": {
"metadata": {
"$user_id": {
// this could be false as it is only accessed from backend or rules.
".read": "$user_id === auth.uid",
".write": "false",
}
}
}
}
Kimlik doğrulaması yapılmış erişim gerektiren tüm veriler aşağıdaki kurala sahip olmalıdır yapılandırıldı. Bu mantık yalnızca iptal edilmemiş kimliğe sahip kimliği doğrulanmış kullanıcılara izin verir. jetonları arasında geçiş yapın:
{
"rules": {
"users": {
"$user_id": {
".read": "auth != null && $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": "auth != null && $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()
)",
}
}
}
}
SDK'daki kimlik jetonu iptalini tespit edin.
Sunucunuzda, yenileme jetonu iptali için aşağıdaki mantığı uygulayın ve kimlik jetonu doğrulaması:
Bir kullanıcının kimlik jetonu doğrulandığında ek checkRevoked
boole flag'i verifyIdToken
öğesine geçirilmelidir. Kullanıcının jetonu
iptal edilmişse kullanıcının istemcide oturumu kapatılmalı veya kullanıcının yeniden kimlik doğrulaması yapması
Firebase Authentication istemci SDK'ları tarafından sağlanan yeniden kimlik doğrulama API'lerini kullanıyor.
Platformunuz için Yönetici SDK'sını başlatmak üzere
kurulum sayfasına gidin. Kimliği alma örnekleri
jetonun içindeki
verifyIdToken
bölümü.
Node.js
// Verify the ID token while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
getAuth()
.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.UserDisabledError:
# Token belongs to a disabled user record.
pass
except auth.InvalidIdTokenError:
# Token is invalid
pass
Go
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.
}
}
İstemcide jeton iptaline yanıt verme
Jeton, Yönetici SDK'sı aracılığıyla iptal edilirse müşteri bu konuda bilgilendirilir. iptali gerçekleştirdiğinde, kullanıcının kimliğini tekrar doğrulaması beklenir veya kullanıcının oturumu kapatılır:
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.
});
}
Gelişmiş Güvenlik: IP adresi kısıtlamalarını zorunlu kılma
Jeton hırsızlığını tespit etmek için yaygın olarak kullanılan bir güvenlik mekanizması, istek IP adresi kaynakları. Örneğin, istekler her zaman aynı IP adresine (çağrıyı yapan sunucu) sahip olan tek IP adresi oturumları emin olun. Bir kullanıcının jetonunun iptal edildiğini tespit ederseniz IP adresi coğrafi konumu aniden değişti veya şüpheli kaynak.
Kimliği doğrulanmış her istek için IP adresine dayalı güvenlik kontrolleri gerçekleştirmek amacıyla Kimlik jetonunu inceleyin ve isteğin IP adresinin öncekiyle eşleşip eşleşmediğini kontrol edin güvenilir IP adresleri veya erişimine izin verilmeden önce güvenilir bir aralıktaysa kısıtlanmış verilerdir. Örneğin:
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!' })
});
}
});
});