Android/IOS Secret 过期管理与客户端凭证流

Posted

技术标签:

【中文标题】Android/IOS Secret 过期管理与客户端凭证流【英文标题】:Android/IOS Secret expiration management with client credentials flow 【发布时间】:2018-03-23 01:49:46 【问题描述】:

我想知道是否有任何策略来管理移动设备中的机密过期。

在授权服务器允许移动客户端使用资源所有者密码流结合客户端凭据对他进行授权的情况下,客户端机密具有过期时间。

我已经看到至少有一些方法可以安全地在 android 应用上存储机密,但是,您如何在不发布新版本应用的情况下管理机密过期?

【问题讨论】:

【参考方案1】:

这就是我们在 OAuth Refresh Token Standards 之后在我们的应用中所做的。

第 1 步:您的 API 应该发送标准的身份验证令牌响应,如 here 所述

 HTTP/1.1 200 OK
 Content-Type: application/json;charset=UTF-8
 Cache-Control: no-store
 Pragma: no-cache

 
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"example",
   "expires_in":3600,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "example_parameter":"example_value"
 

第 2 步:将该响应保存在 Shared Preferences/Local Cache/Local Database 中,我们使用 Shared Preferences(假设 accountToken 是从 Auth Token 的响应创建的类的对象)

SharedPreferences.Editor editor = getContext().getSharedPreferences("AUTH_PREFS_NAME", Context.MODE_PRIVATE).edit();
editor.putString("AUTH_ACCESS_TOKEN_KEY", accountToken.getAccess_token());
editor.putString("AUTH_REFRESH_TOKEN_KEY", accountToken.getRefresh_token());
editor.putLong("AUTH_EXPIRES_IN_KEY", accountToken.getExpires_in());
editor.putLong("AUTH_TIME_SAVED_KEY", ((int) (System.currentTimeMillis() / 1000)));
editor.commit();

第 3 步:每次必须使用保存的访问令牌时,请确保它没有过期

public boolean needsTokenRefresh(String accessToken) 
    if (accessToken == null || accessToken.length() == 0) 
        // no access token to refresh. Don't refresh.
        return false;
    

    SharedPreferences pref = mContext.getSharedPreferences("AUTH_PREFS_NAME", Context.MODE_PRIVATE);
    String refreshToken = pref.getString("AUTH_REFRESH_TOKEN_KEY", null);
    if (refreshToken == null || refreshToken.length() == 0) 
        // no refresh token. Can't refresh.
        return false;
    

    Integer timeSaved = pref.getInt("AUTH_TIME_SAVED_KEY", 0);
    if (timeSaved == 0) 
        // No recording of having saved the token. Don't refresh.
        return false;
    

    long expiresIn = pref.getLong("AUTH_EXPIRES_IN_KEY", 0);
    int now = (int) (System.currentTimeMillis() / 1000);
    int timePassed = Math.abs(now - timeSaved);
    boolean expired = false;
    if (expiresIn <= timePassed) 
        expired = true;
    
    return expired;

如果needsTokenRefresh() 返回false,则使用保存的身份验证令牌。如果返回true,则进行下一步。

第 4 步:再次进行 Auth 调用,将 grant_type 设置为 refresh_token 为 stated in standards

第 5 步:身份验证调用应返回标准身份验证响应,如第 1 步中所述,并刷新令牌和新的refresh_token

【讨论】:

我想您在确定令牌是否过期时忘记写下保存 "AUTH_TIME_SAVED_KEY" 的调用,所以我冒昧地为您添加了它。 :) 一般来说,您可能应该对这个时间戳有点保守,因为延迟(在移动设备中很常见)可能会导致服务器不接受它,尽管您的方法说它没有过期(您只在本地检查)。不过,这是一个极端的情况,可以处理。 我想我在截断额外位时错过了这一点。感谢添加。 这个解决方案以多种方式拯救了我。谢谢!非常直接且易于实施。【参考方案2】:

我能想到的唯一方法是,当您第一次运行该应用程序时,它会连接到服务器并发送手机指纹,只有当指纹未在其数据库中列出时,服务器才会发送文件,该文件包含当前日期和该日期的数字签名,因此用户不会更改其值。 并且每次运行应用程序时,您都会通过应用 VerifySignature 方法检查日期和日期的完整性。

【讨论】:

以上是关于Android/IOS Secret 过期管理与客户端凭证流的主要内容,如果未能解决你的问题,请参考以下文章

主观与客观

jwt检查令牌是否过期

云原生之kuberneteskubernetes集群下Secret存储对象的管理

如何使节点 js 中的 jwt 过期?

Linux企业运维——Kubernetes存储之Secret配置管理

Json Web 令牌不会过期