我一直在阅读很多主题并决定在进行编码之前发表我的结论。我发现了很多有趣的东西(What is the most appropriate way to store user settings in Android application),这是我到目前为止收集的内容:
我们假设始终使用https。
通过“记住我”,我的意思是:用户永远不会再次在应用程序上进行身份验证,因为它会让他每周进行一次身份验证。
当不使用“记住我”功能时:Oauth2是要走的路,使用交换令牌 - >什么都没有存储,最安全
使用“记住我”功能时
首次注册/用户/登录应用时: 服务器使用自己的“私钥”/哈希对密码进行哈希处理并返回到android。
然后将此散列密码加密,然后存储在SharedPreferences中。鉴于Hashed密码永不过期,我们现在有以下警告:
结论: 使用“记住我”功能虽然方便了用户,但却很容易受到攻击。
我的问题(最后:)) 这个结论是否正确?我忘记了一个明显的解决方案吗?
鉴于约束(没有过期,使用记住我的功能),我找不到任何更安全的解决方案
感谢您的帮助!
答案 0 :(得分:0)
我不确定你的问题是什么,但我会用这个空间来澄清一些内容。
您的发现是正确的:"记住密码" (甚至散列)本地设备是一个坏主意,不应该被任何人编码,用户永远不应该使用这样做的应用程序。
实际上,即使在服务器端,密码在技术上也不可能是未加密的。服务器端密码哈希必须始终使用单向加密。
您永远不会在本地存储密码。永远!您始终在本地存储oauth密钥。哈希会很好。如果在服务器端Oauth密钥与某种设备ID绑定,那就更好了,这意味着Oauth只能与该设备一起使用。
是什么让您认为用户必须再次登录"什么时候使用Oauth?密钥不必过期(服务器可能有一些过期机制),即使他们这样做,也会有密钥交换技术。
答案 1 :(得分:0)
原则上你是对的,我只会添加一些技术说明。


https - 为了更高的安全性使用证书固定,你的.apk应该包含允许的证书CA,或服务器证书的签名,或与服务器证书进行比较的公钥(这可以防止中间人的SSL攻击)。


在服务器端将密码存储为“strong_hash(salted(password))”。不要存储纯文本密码或仅哈希密码。无论盐是固定的,还是按用户生成(将用户名固定为固定盐),或者每次注册(您将无法从不同的设备登录,不知道正确的盐),这是您的选择。


关于登录(如果“记住我”令牌过期):使用始终挑战 - 响应方式,因此客户端将他的挑战发送到服务器,服务器将他的挑战发送给客户端,然后客户端将发送strong_hash(client_challenge + server_challenge + strong_hash(salted(密码))),服务器也可以从存储的strong_hash(salted(密码))生成,并比较(发送回“记住我”令牌,存储在服务器上) /客户端以加密形式,具有关于创建日期的元数据等)。如果有人在窃听通信,则发送的哈希仅对那些挑战值有效,接下来尝试登录同一用户帐户时会遇到不同的挑战会使其无效。


如果应用程序数据的安全性非常重要(如移动银行),您可以通过一些简单的“PIN”加密完整的“记住我”令牌来加强“记住我”到半安全级别的不良安全性,要求用户每次运行应用程序时都要输入PIN码。这使得无法手动闯入(5-8个错误的PIN将删除令牌并阻止应用程序,需要完全登录挑战+密码,甚至通过其他渠道(电话或网络应用程序)重置设备服务器),并以编程方式强制它可以在服务器API端触发特定用户的可疑故障率的一些警报。然而,输入4位以上的PIN并不像输入完整密码那么麻烦,而且在安全性要求较高的应用程序中,用户通常会很好地接受它。


否则是的,“记得我“可以被盗,只是质疑你制作它有多容易,如果设备有一些由用户存在解锁的防篡改密钥库,使用一个而不是共享的prefs,或者至少用一些密钥加密值(固定+生成) - 设备部分?)。但它只是堆积在路径上的石头,有人足够坚定并且熟练可以提取令牌无论如何,并在其他设备上使用它来模仿原始用户。