原文来自简书:http://www.jianshu.com/p/4af3b8179136/comments/1294203

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

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

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被破解,或者你的手机被越狱,那么就能轻松拿到这个文件。
那么就能轻松读到存储的信息,密码就会不安全:

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

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

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

如何解决“直接把密码存储在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 利用钥匙串保存密码和获取密码

直接使用Security框架读写钥匙串,参考:http://useyourloaf.com/blog/2010/03/29/simple-iphone-keychain-access.html
 

我们使用第三方类SFHFKeychainUtils来操作钥匙串 ( GitHub代码下载 )

使用方法如下:

1、引入Security.framework框架。

2、引入头文件:#import"SFHFKeychainUtils.h"

3、存密码:

   NSString *SERVICE_NAME=@"demo";
[SFHFKeychainUtils storeUsername:@"dd"
andPassword:@"aa"
forServiceName:SERVICE_NAME
updateExisting:1
error:nil];

4、取密码:

    NSString *passWord =  [SFHFKeychainUtils getPasswordForUsername:@"dd"
andServiceName:SERVICE_NAME
error:nil];
NSLog(@"%@",passWord);

5、删除用户:

[SFHFKeychainUtils deleteItemForUsername:@"dd" andServiceName:SERVICE_NAME error:nil];

iOS:iOS开发中用户密码保存位置的更多相关文章

  1. iOS 应用开发,用户密码存储技术--KeyChain

    文/清雪飘香(简书作者)原文链接:http://www.jianshu.com/p/c41525172aee著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 这次的Xcode 事件,让我 ...

  2. 简单讲解iOS应用开发中的MD5加密的相关使用<转>

    这篇文章主要介绍了iOS应用开发中的MD5加密的相关使用,示例代码基于传统的Objective-C,需要的朋友可以参考下 一.简单说明 1.说明 在开发应用的时候,数据的安全性至关重要,而仅仅用POS ...

  3. 简单讲解iOS应用开发中的MD5加密的相关使用

      简单讲解iOS应用开发中的MD5加密的相关使用   作者:文顶顶 字体:[增加 减小] 类型:转载 时间:2015-12-19 我要评论 这篇文章主要介绍了iOS应用开发中的MD5加密的相关使用, ...

  4. Subversion——密码保存位置

    Subversion——密码保存位置 摘要:本文主要说明了Subversion在电脑上保存密码的位置. 起因 在向本地电脑上的文件夹里下载程序代码的时候,发现输入了地址之后就能直接下载了,并没有提示输 ...

  5. iOS项目开发中的知识点与问题收集整理①(Part 一)

    前言部分 注:本文并非绝对原创 大部分内容摘自 http://blog.csdn.net/hengshujiyi/article/details/20943045 文中有些方法可能已过时并不适用于现在 ...

  6. iOS项目开发中的知识点与问题收集整理①

    前言部分 注:本文并非绝对原创 大部分内容摘自 http://blog.csdn.net/hengshujiyi/article/details/20943045 文中有些方法可能已过时并不适用于现在 ...

  7. IOS程序开发中-跳转到 发送短信界面 实现发短信

    前言:我发现我标题取的不好,谁帮我取个承接上下文的标题?评论一下,我改 项目需求:在程序开发中,我们需要在某个程序里面发送一些短信验证(不是接收短信验证,关于短信验证,传送门:http://www.c ...

  8. Python开发之用户密码存储

    在各种线上应用中,用户名密码是用户身份认证的关键,它的重要性不言而喻.一方面,作为保护用户敏感数据的钥匙来说,一旦被破解,系统将敞开大门完全不设防.另一方面,密码这把钥匙本身就是非常敏感的数据:大多数 ...

  9. node.js中用户密码的加密

    crypro实现用户密码的加密 在实际的项目中,只要涉及到用户的信息,就是十分重要的.设想一下数据库里面存放的用户的密码是明文的形式,后果是有多严重.所以今天给大家分享一下express中怎样实现用户 ...

随机推荐

  1. ARM学习笔记15——串口通信基本原理【转】

    计算机串口基本理论 1.什么是串口? 2,什么是RS-232? 3,什么是RS-422? 4,什么是RS-485? 5,什么是握手? 1,什么是串口? 串口是计算机上一种非常通用的设备通信的协议(不要 ...

  2. [MarsZ]ThinkPHP项目实战总结

    本文原word格式百度云盘下载地址: http://pan.baidu.com/s/1qYqZFkg 综述 2 需求 2 作者 2 系统一览 2 Unity3d客户端 2 PHP后台 4 准备 6 X ...

  3. Android 快捷方式

    1. 需要权限: <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT&quo ...

  4. 制作静态库文件(.a文件)

    制作静态库文件(.a文件) 1.创建静态库工程: 在Xcode中new一个新的project,选择IOS下面的Framework&Library,下面有一个Cocoa Touch Static ...

  5. openstack 集成显卡 对windroye 支持

  6. 近5年133个Java面试问题列表

    Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来越高级,面试官问的问题也更深入. 在我 ...

  7. HDU 4635 多校第四场 1004 强联通

    我还有什么好说,还有什么好说...... 我是SBSBSBSBSBSBSBSBSBSBSBSBBSBSBSBSBSBSBSBSBS........................ 题意 思路什么的都不 ...

  8. PowerShell常用的.Net 、COM对象(New-Object、Assembly)、加载程序集

    #新建随机数对象实例:$Ran = New-Object System.Random$Ran.NextDouble() 有时候,要使用的实例的类保存在独立的库文件中,PowerShell默认未加载,会 ...

  9. poj 1226

    跟3294比较类似,但是不需要输出具体的串,比较简单,只要把串反转连接上去解法就一样了. #include <iostream> #include <cstdio> #incl ...

  10. [MySQL] MySQL的自己主动化安装部署

    有过MySQL运维的人应该都清楚,线上的MySQL一般都採用源代码编译,由于这样才干够依据企业的各自须要选择要编译的功能,尽管MySQL的源代码编译挺简单的,可是试想一下,假设你有几百台server同 ...