美文网首页iosiOS开发文章性能优化
iOS开发中用户密码应该保存在哪里

iOS开发中用户密码应该保存在哪里

作者: 陈怀哲 | 来源:发表于2016-01-15 10:06 被阅读8838次

版权声明
本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;
微信公众号:陈怀哲(chenhuaizhe2016);
无需授权即可转载,但请自觉保留以上版权声明。


如果要实现自动登录,不必每次打开应用都去登录,我们势必要把密码保存到本地。
一般我们的操作是:
每次打开应用后,如果存在密码,直接进入界面,然后再进行后台密码验证。如果没网络,我们可以跳过验证;如果有网络,我们可以后台去验证帐号密码的正确性,并根据服务器的response做一些操作。

</br>

为什么直接把密码存储在NSUserDefaults中不安全?

</br>

iOS中沙盒有哪几个文件夹,都是用来干吗的

默认情况下,每个沙盒含有3个文件夹:Documents, Library 和 tmp。因为应用的沙盒机制,应用只能在几个目录下读写文件

  • Documents:苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
  • Library:存储程序的默认设置或其它状态信息;
  • Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除
  • tmp:提供一个即时创建临时文件的地方。

获取到沙盒Library路径

 //获取Library目录路径
-  (void)getLibraryPath
 {
    NSArray * pathArray = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask, YES);
   NSString * libraryStrPath = [pathArray objectAtIndex:0];
    NSLog(@"LibraryPath:%@“,libraryStrPath);
 }

如图就是NSUserDefaults对应的plist文件在sandbox中的位置

蓝色部分为plist文件

如果sandbox被破解,或者你的手机被越狱,那么就能轻松拿到这个文件。
那么就能轻松读到存储的信息,密码就会不安全:

在plist中可以找到密码

这对于其它保存在NSUserDefaults中的信息也是一样的,所以对于存在NSUserDefaults中的东西,最好混淆加密一下再存储。

如何删除NSUserDefaults对应的plist文件?

其实就是删除plist文件中所有的键值对。

NSUserDefaults *userDefatluts = [NSUserDefaults standardUserDefaults];
NSDictionary *dictionary = [userDefaults dictionaryRepresentation];
for(NSString* key in [dictionary allKeys]){
     [userDefaults removeObjectForKey:key];
     [userDefaults synchronize];
}

</br>

如何解决“直接把密码存储在NSUserDefaults中不安全”的问题?

把密码加密后再存储到NSUserDefaults中

iOS中提供了很多种加密算法,对于存储密码,可以使用不可逆的MD5加密。
使用MD5加密需要导入头文件:
''#import <CommonCrypto/CommonDigest.h>

##### 简单的MD5加密
+ ( NSString *)md5String:( NSString *)str

{

const char *myPasswd = [str UTF8String ];

unsigned char mdc[ 16 ];

CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);

NSMutableString *md5String = [ NSMutableString string ];

for ( int i = 0 ; i< 16 ; i++) {

[md5String appendFormat : @"%02x" ,mdc[i]];

}

return md5String;

}

##### 复杂一些的MD5加密
+ ( NSString *)md5String:( NSString *)str
 
 {
 
 const char *myPasswd = [str UTF8String ];
 
 unsigned char mdc[ 16 ];
 
 CC_MD5 (myPasswd, ( CC_LONG ) strlen (myPasswd), mdc);
 
 NSMutableString *md5String = [ NSMutableString string ];
 
 [md5String appendFormat : @"%02x" ,mdc[ 0 ]];
 
 for ( int i = 1 ; i< 16 ; i++) {
 
 [md5String appendFormat : @"%02x" ,mdc[i]^mdc[ 0 ]];

不使用NSUserDefaults保存密码,使用keyChain来保存密码

更加保险的方法是把密码保存在iOS提供的keychina中,并且删除应用后,密码不会删除,下载安装还能使用。iOS系统提供了一些方法,进行一些简单的封装之后,就可以很方便的使用。

封装后可供使用的几个类
Github-chenhuaizhe-iOS-keychain
你也可以在这里直接下载,更多交流可以关注我的微博:@陈怀哲

下面是封装代码,使用时需要先导入Security.framework:

PassWordTool.h

#import <Foundation/Foundation.h>

@interface PassWordTool : NSObject
/**
 *    @brief    存储密码
 *
 *    @param     password     密码内容
 */
+(void)savePassWord:(NSString *)password;

/**
 *    @brief    读取密码
 *
 *    @return    密码内容
 */
+(id)readPassWord;

/**
 *    @brief    删除密码数据
 */
+(void)deletePassWord;

@end

PassWordTool.m

 import "PassWordTool.h"
 import "KeychainTool.h"
 
 @implementation PassWordTool
 static NSString * const KEY_IN_KEYCHAIN = @"com.chenyuan.app.userid";
 static NSString * const KEY_PASSWORD = @"com.chenyuan.app.password";
 
+(void)savePassWord:(NSString *)password
 {
     NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionary];
     [usernamepasswordKVPairs setObject:password forKey:KEY_PASSWORD];
     [KeychainTool save:KEY_IN_KEYCHAIN data:usernamepasswordKVPairs];
 }
 
+(id)readPassWord
 {
     NSMutableDictionary *usernamepasswordKVPair = (NSMutableDictionary *)[KeychainTool load:KEY_IN_KEYCHAIN];
     return [usernamepasswordKVPair objectForKey:KEY_PASSWORD];
 }
 
+(void)deletePassWord
 {
     [KeychainTool delete:KEY_IN_KEYCHAIN];
 }
 @end

KeychainTool.h

#import <Foundation/Foundation.h>
 
@interface KeychainTool : NSObject
 
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service ;
 
+ (void)save:(NSString *)service data:(id)data ;
 
+ (id)load:(NSString *)service ;
 
+ (void)delete:(NSString *)service ;
 
@end

KeychainTool.m

import "KeychainTool.h"

@implementation KeychainTool

  • (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
    service, (__bridge_transfer id)kSecAttrService,
    service, (__bridge_transfer id)kSecAttrAccount,
    (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
    nil];
    }

  • (void)save:(NSString *)service data:(id)data {
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
    }

  • (id)load:(NSString *)service {
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Configure the search setting
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
    @try {
    ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
    } @catch (NSException *e) {
    NSLog(@"Unarchive of %@ failed: %@", service, e);
    } @finally {
    }
    }
    return ret;
    }

  • (void)delete:(NSString *)service {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    }
    @end

#### 服务器密码验证登录请求
验证请求时,最好是不直接把明文密码包含在请求里面。
可以根据一系列字符串生成MD5加密后的签名,根据user-id 和 签名来验证登录。
比如:

NSString *sourceStr = [NSString stringWithFormat:@"attach=iOS&chartset=utf-8&format=json&partner=google&userid=%@&password=%@”,userid,password];
NSString *signStr = [NSString md5String:sourceStr];

这样得到的signStr和userid再作为网络请求的参数传给服务器做验证。

相关文章

  • iOS开发中用户密码应该保存在哪里

    为啥直接把密码存储在NSUserDefault中不安全? iOS中的沙盒 默认情况下,每个沙盒都含有3个文件夹:D...

  • iOS开发中用户密码应该保存在哪里

    版权声明本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd...

  • iOS中使用SFHFKeychainUtils保存用户密码

    iOS中使用SFHFKeychainUtils保存用户密码,有需要的朋友可以参考下。项目中需要保存用户密码,以实现...

  • iOS - Password AutoFill

    密码自动填充 Version - - iOS 11.0 简化登陆流程 保存密码,用户不用记住密码 一、实现原理 将...

  • iOS开发,保存用户敏感信息

    前言 开发中遇到登录及注册需求.需要保存用户密码.为了保护用户安全,我选择了使用SFHFKeychainUtil...

  • iOS加密简介

    网络开发准则 网络开发中不允许传输用户明文隐私数据在本地不允许保存用户明文隐私数据 替换加密 里面密码本进行替换 ...

  • 小程序开发之路---form表单提交

    app开发中,必然会有用户登录过程,之前做iOS开发时,用户名、密码登录部分,只能分别定义属性传值。在小程序中,提...

  • 密码安全

    密码泄露 服务器被入侵,用户信息泄露防御:密码不应该明文保存,使用某种算法加密后保存到数据库中。 密码破解 在前端...

  • 08.Linux用户与用户组

    用户帐号在linux中,/etc目录下,passwd文件保存用户信息,shadow保存用户的密码信息;linux的...

  • go处理用户密码的最佳实践

    保存用户密码的时候切记不用保存密码的明文,要保存密码的hash,这样即便数据库中的用户hash泄露也无伤大雅。 h...

网友评论

  • T_guo:static NSString * const KEY_IN_KEYCHAIN = @"com.xunwei.ios.userid";
    static NSString * const KEY_PASSWORD = @"com.xunwei.ios.password";
    着两个的用处是什么
  • Dicky信徒:从来不存密码
  • 7e5bd9023661:MD5加密不可逆后 我提交服务器 服务器也不认我加密后的密码啊
    这小子:@男神已认证 服务器本来就不应该看到用户的密码的,如果从后台到取到密码明文,前端再怎么加密也没用
    男神已认证:@熙棋 那你这加密还有什么用:joy:
    熙棋:一开始注册的时候你就提交md5加密以后的密码就可以了
  • 经天纬地:如果是本地的信息存入本地沙盒一般都不会被破解吧,别人怎么去破解的沙盒里面的文件?除非是越狱,不过只要手机越狱什么安全都不存在了,这没什么好说的.
  • 我是卖报滴小行家:用MD5加密 密码后,我还想用这个密码,怎么办呐???
    谭冉冉:@我是卖报滴小行家 一般都是保存 token,不建议本地存储密码或者MD5之后的密码
  • d496bf8fb8fe:大神,怎么用啊?
    陈怀哲:@程小白 写的很明白了
  • 郑明明: static NSString * const KEY_IN_KEYCHAIN = @"com.chenyuan.app.userid";
    static NSString * const KEY_PASSWORD = @"com.chenyuan.app.password";
    这两个字符串需要填写对于的APP的bundle identifier吗?
    陈怀哲:@nineteen__ 不用
  • 郑明明:还打广告,老司机😂
  • 郑明明:在学习中,嘿嘿,老司机
  • 超_iOS:学习了
  • jiangamh:用github啊
    陈怀哲:@jiangamh https://github.com/chenhuaizhe/iOS-keychain
    陈怀哲:@jiangamh 就4个小类懒得用Github了,你觉得呢,如果有需要,弄一个也行

本文标题:iOS开发中用户密码应该保存在哪里

本文链接:https://www.haomeiwen.com/subject/bedhkttx.html