iOS之数据安全
一、数据安全
术语-----
密钥:密钥是一种参数, 它是在明文转换为密文, 或将密文转换为明文的算法中输入的参数. 密钥分为对称密钥和非对称密钥(也可以根据用途来分为加密密钥和解密密钥)
明文:没有进行加密, 能够直接代表原文含义的信息
密文:经过加密处理之后, 隐藏原文含义的信息
加密:将明文转换成密文的实施过程
解密:将密文转换成明文的实施过程
数据安全-----
数据安全: 是一种主动的包含措施, 数据本身的安全必须基于可靠的加密算法与安全体系,主要是有对称算法与公开密钥密码体系两种(非对称算法), 都包含了数据的加密和解密过程
二、MD5
哈希算法-----
哈希算法:哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值, 这个小的二进制值成为哈希值
哈希值是一段数据唯一且及其紧凑的数值表示形式. 数据的哈希值可以检验数据的完整性. 一般用于快速查找和加密算法
典型的哈希算法就有MD5
MD5-----
MD5:Message Digest Alogorithm MD5 (消息摘要算法第五版) 为计算机安全领域广泛使用的一种散列函数, 用以提供小米的完整性保护MD5算法具有以下特点:
1、压缩性: 任意长度的数据, 算出的MD5值长度都是固定的 (16进制, 32位)
2、容易计算: 从原数据计算出MD5值很容易
3、抗修改性: 对原数据进行任何改动, 哪怕只修改1个字节, 所得到的MD5值都有很大区别
4、强抗碰撞: 已知原数据和其MD5值, 想找到一个具有相同MD5值的数据(伪造数据)是非常困难的
获取字符串MD5值-----引入头文件
#import <CommonCrypto/CommonCrypto.h>
- //1.准备一个字符串用于加密
- NSString *str = @"go ahead";//同一个字符串进行MD5加密出来的内容相同
- #pragma mark - ??????????????一个内容加了const有什么含义
- //2.因为MD5基于C语言, 所以需要将字符串转为C语言的字符串进行编码
- const char *data = [str UTF8String];
- //3.使用字符串数组去存取加密后相关的内容(16进制, 32位)
- //CC_MD5_DIGEST_LENGTH表示长度
- unsigned char result[CC_MD5_DIGEST_LENGTH];
- //4.进行MD5加密
- //参数1: 要加密的内容
- //参数2: 要加密的data的一个长度
- //参数3: MD5
- CC_MD5(data, (CC_LONG)strlen(data), result);
- //5.创建可变字符串, 保存结果
- NSMutableString *mutableString = [NSMutableString string];
- //6.遍历结果数组, 然后添加到可变字符串中
- for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
- //16进制 //%x 16进制, 02不足两位时补0.
- [mutableString appendFormat:@"%02x", result[i]];
- }
- NSLog(@"%@", mutableString);
获取其他对象MD5的值-----
加密NSData
- #pragma mark - 加密NSData
- //需求: 创建一个数组, 数组中存储元素, 将这个数组写入到沙盒里
- //1.创建一个数组
- NSArray *array = @[@"go", @"rose"];
- //2.找沙盒路径
- NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
- //3.拼接路径
- NSString *arrayPath = [documentPath stringByAppendingPathComponent:@"array.plist"];
- //4.写入
- [array writeToFile:arrayPath atomically:YES];
- //从沙盒中取出NSData类型的数据
- NSData *data = [NSData dataWithContentsOfFile:arrayPath];
- NSLog(@"%@", data);
- //NSData类型数据加密过程
- //1.创建MD5对象
- CC_MD5_CTX md5;
- //2.初始化MD5对象
- CC_MD5_Init(&md5);
- //3.准备开始进行数据的加密
- CC_MD5_Update(&md5, data.bytes, (CC_LONG)data.length);
- //4.准备一个字符串数组用来存储结果
- unsigned char result[CC_MD5_DIGEST_LENGTH];
- //5.创建一个可变字符串保存结果
- NSMutableString *string = [NSMutableString string];
- //结束加密
- CC_MD5_Final(result, &md5);
- //6.遍历数组给可变字符串赋值
- for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
- [string appendFormat:@"%02x", result[i]];
- }
- NSLog(@"%@", string);
钥匙串加密-----
苹果iOS和Mac OS X系统自带了一套敏感信息保存方案: "钥匙串"(Keychain)
保存在钥匙串的内容相当于系统对其做了保护, 在设备锁定时进行了加密处理
钥匙串中的条目成为SecItem, 但它是存储在CFDictionary中的 SecItemRef类型并不存在, SecItem有五类:通用密码、互联网密码、证书、密钥、和身份, 在大多数情况下, 我们用到的都是通用密码
钥匙串的使用和字典非常相似
用原生的 Security.framework就可以实现钥匙串的访问、续写, 但是只能在真机上进行, 通常我们使用KeychainItemWrapper来完成钥匙串的加密
引入头文件
#import "KeychainItemWrapper.h"
- /*
- File: KeychainItemWrapper.h
- Abstract:
- Objective-C wrapper for accessing a single keychain item.
- Version: 1.2
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
- Inc. ("Apple") in consideration of your agreement to the following
- terms, and your use, installation, modification or redistribution of
- this Apple software constitutes acceptance of these terms. If you do
- not agree with these terms, please do not use, install, modify or
- redistribute this Apple software.
- In consideration of your agreement to abide by the following terms, and
- subject to these terms, Apple grants you a personal, non-exclusive
- license, under Apple's copyrights in this original Apple software (the
- "Apple Software"), to use, reproduce, modify and redistribute the Apple
- Software, with or without modifications, in source and/or binary forms;
- provided that if you redistribute the Apple Software in its entirety and
- without modifications, you must retain this notice and the following
- text and disclaimers in all such redistributions of the Apple Software.
- Neither the name, trademarks, service marks or logos of Apple Inc. may
- be used to endorse or promote products derived from the Apple Software
- without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or
- implied, are granted by Apple herein, including but not limited to any
- patent rights that may be infringed by your derivative works or by other
- works in which the Apple Software may be incorporated.
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE
- MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
- THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
- AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
- STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
- Copyright (C) 2010 Apple Inc. All Rights Reserved.
- */
- #import <UIKit/UIKit.h>
- /*
- The KeychainItemWrapper class is an abstraction layer for the iPhone Keychain communication. It is merely a
- simple wrapper to provide a distinct barrier between all the idiosyncracies involved with the Keychain
- CF/NS container objects.
- */
- @interface KeychainItemWrapper : NSObject
- {
- NSMutableDictionary *keychainItemData; // The actual keychain item data backing store.
- NSMutableDictionary *genericPasswordQuery; // A placeholder for the generic keychain item query used to locate the item.
- }
- @property (nonatomic, retain) NSMutableDictionary *keychainItemData;
- @property (nonatomic, retain) NSMutableDictionary *genericPasswordQuery;
- // Designated initializer.
- - (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;
- - (void)setObject:(id)inObject forKey:(id)key;
- - (id)objectForKey:(id)key;
- // Initializes and resets the default generic keychain item data.
- - (void)resetKeychainItem;
- @end
- /*
- File: KeychainItemWrapper.m
- Abstract:
- Objective-C wrapper for accessing a single keychain item.
- Version: 1.2
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
- Inc. ("Apple") in consideration of your agreement to the following
- terms, and your use, installation, modification or redistribution of
- this Apple software constitutes acceptance of these terms. If you do
- not agree with these terms, please do not use, install, modify or
- redistribute this Apple software.
- In consideration of your agreement to abide by the following terms, and
- subject to these terms, Apple grants you a personal, non-exclusive
- license, under Apple's copyrights in this original Apple software (the
- "Apple Software"), to use, reproduce, modify and redistribute the Apple
- Software, with or without modifications, in source and/or binary forms;
- provided that if you redistribute the Apple Software in its entirety and
- without modifications, you must retain this notice and the following
- text and disclaimers in all such redistributions of the Apple Software.
- Neither the name, trademarks, service marks or logos of Apple Inc. may
- be used to endorse or promote products derived from the Apple Software
- without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or
- implied, are granted by Apple herein, including but not limited to any
- patent rights that may be infringed by your derivative works or by other
- works in which the Apple Software may be incorporated.
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE
- MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
- THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
- AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
- STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
- Copyright (C) 2010 Apple Inc. All Rights Reserved.
- */
- #import "KeychainItemWrapper.h"
- #import <Security/Security.h>
- /*
- These are the default constants and their respective types,
- available for the kSecClassGenericPassword Keychain Item class:
- kSecAttrAccessGroup - CFStringRef
- kSecAttrCreationDate - CFDateRef
- kSecAttrModificationDate - CFDateRef
- kSecAttrDescription - CFStringRef
- kSecAttrComment - CFStringRef
- kSecAttrCreator - CFNumberRef
- kSecAttrType - CFNumberRef
- kSecAttrLabel - CFStringRef
- kSecAttrIsInvisible - CFBooleanRef
- kSecAttrIsNegative - CFBooleanRef
- kSecAttrAccount - CFStringRef
- kSecAttrService - CFStringRef
- kSecAttrGeneric - CFDataRef
- See the header file Security/SecItem.h for more details.
- */
- @interface KeychainItemWrapper (PrivateMethods)
- /*
- The decision behind the following two methods (secItemFormatToDictionary and dictionaryToSecItemFormat) was
- to encapsulate the transition between what the detail view controller was expecting (NSString *) and what the
- Keychain API expects as a validly constructed container class.
- */
- - (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert;
- - (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert;
- // Updates the item in the keychain, or adds it if it doesn't exist.
- - (void)writeToKeychain;
- @end
- @implementation KeychainItemWrapper
- @synthesize keychainItemData, genericPasswordQuery;
- - (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;
- {
- if (self = [super init])
- {
- // Begin Keychain search setup. The genericPasswordQuery leverages the special user
- // defined attribute kSecAttrGeneric to distinguish itself between other generic Keychain
- // items which may be included by the same application.
- genericPasswordQuery = [[NSMutableDictionary alloc] init];
- [genericPasswordQuery setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
- [genericPasswordQuery setObject:identifier forKey:(id)kSecAttrGeneric];
- // The keychain access group attribute determines if this item can be shared
- // amongst multiple apps whose code signing entitlements contain the same keychain access group.
- if (accessGroup != nil)
- {
- #if TARGET_IPHONE_SIMULATOR
- // Ignore the access group if running on the iPhone simulator.
- //
- // Apps that are built for the simulator aren't signed, so there's no keychain access group
- // for the simulator to check. This means that all apps can see all keychain items when run
- // on the simulator.
- //
- // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
- // simulator will return -25243 (errSecNoAccessForItem).
- #else
- [genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
- #endif
- }
- // Use the proper search constants, return only the attributes of the first match.
- [genericPasswordQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
- [genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
- NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];
- NSMutableDictionary *outDictionary = nil;
- if (! SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) == noErr)
- {
- // Stick these default values into keychain item if nothing found.
- [self resetKeychainItem];
- // Add the generic attribute and the keychain access group.
- [keychainItemData setObject:identifier forKey:(id)kSecAttrGeneric];
- if (accessGroup != nil)
- {
- #if TARGET_IPHONE_SIMULATOR
- // Ignore the access group if running on the iPhone simulator.
- //
- // Apps that are built for the simulator aren't signed, so there's no keychain access group
- // for the simulator to check. This means that all apps can see all keychain items when run
- // on the simulator.
- //
- // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
- // simulator will return -25243 (errSecNoAccessForItem).
- #else
- [keychainItemData setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
- #endif
- }
- }
- else
- {
- // load the saved data from Keychain.
- self.keychainItemData = [self secItemFormatToDictionary:outDictionary];
- }
- [outDictionary release];
- }
- return self;
- }
- - (void)dealloc
- {
- [keychainItemData release];
- [genericPasswordQuery release];
- [super dealloc];
- }
- - (void)setObject:(id)inObject forKey:(id)key
- {
- if (inObject == nil) return;
- id currentObject = [keychainItemData objectForKey:key];
- if (![currentObject isEqual:inObject])
- {
- [keychainItemData setObject:inObject forKey:key];
- [self writeToKeychain];
- }
- }
- - (id)objectForKey:(id)key
- {
- return [keychainItemData objectForKey:key];
- }
- - (void)resetKeychainItem
- {
- OSStatus junk = noErr;
- if (!keychainItemData)
- {
- self.keychainItemData = [[NSMutableDictionary alloc] init];
- }
- else if (keychainItemData)
- {
- NSMutableDictionary *tempDictionary = [self dictionaryToSecItemFormat:keychainItemData];
- junk = SecItemDelete((CFDictionaryRef)tempDictionary);
- NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." );
- }
- // Default attributes for keychain item.
- [keychainItemData setObject:@"" forKey:(id)kSecAttrAccount];
- [keychainItemData setObject:@"" forKey:(id)kSecAttrLabel];
- [keychainItemData setObject:@"" forKey:(id)kSecAttrDescription];
- // Default data for keychain item.
- [keychainItemData setObject:@"" forKey:(id)kSecValueData];
- }
- - (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert
- {
- // The assumption is that this method will be called with a properly populated dictionary
- // containing all the right key/value pairs for a SecItem.
- // Create a dictionary to return populated with the attributes and data.
- NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];
- // Add the Generic Password keychain item class attribute.
- [returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
- // Convert the NSString to NSData to meet the requirements for the value type kSecValueData.
- // This is where to store sensitive data that should be encrypted.
- NSString *passwordString = [dictionaryToConvert objectForKey:(id)kSecValueData];
- [returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];
- return returnDictionary;
- }
- - (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert
- {
- // The assumption is that this method will be called with a properly populated dictionary
- // containing all the right key/value pairs for the UI element.
- // Create a dictionary to return populated with the attributes and data.
- NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];
- // Add the proper search key and class attribute.
- [returnDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
- [returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
- // Acquire the password data from the attributes.
- NSData *passwordData = NULL;
- if (SecItemCopyMatching((CFDictionaryRef)returnDictionary, (CFTypeRef *)&passwordData) == noErr)
- {
- // Remove the search, class, and identifier key/value, we don't need them anymore.
- [returnDictionary removeObjectForKey:(id)kSecReturnData];
- // Add the password to the dictionary, converting from NSData to NSString.
- NSString *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length]
- encoding:NSUTF8StringEncoding] autorelease];
- [returnDictionary setObject:password forKey:(id)kSecValueData];
- }
- else
- {
- // Don't do anything if nothing is found.
- NSAssert(NO, @"Serious error, no matching item found in the keychain.\n");
- }
- [passwordData release];
- return returnDictionary;
- }
- - (void)writeToKeychain
- {
- NSDictionary *attributes = NULL;
- NSMutableDictionary *updateItem = NULL;
- OSStatus result;
- if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr)
- {
- // First we need the attributes from the Keychain.
- updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];
- // Second we need to add the appropriate search key/values.
- [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];
- // Lastly, we need to set up the updated attribute list being careful to remove the class.
- NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData];
- [tempCheck removeObjectForKey:(id)kSecClass];
- #if TARGET_IPHONE_SIMULATOR
- // Remove the access group if running on the iPhone simulator.
- //
- // Apps that are built for the simulator aren't signed, so there's no keychain access group
- // for the simulator to check. This means that all apps can see all keychain items when run
- // on the simulator.
- //
- // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
- // simulator will return -25243 (errSecNoAccessForItem).
- //
- // The access group attribute will be included in items returned by SecItemCopyMatching,
- // which is why we need to remove it before updating the item.
- [tempCheck removeObjectForKey:(id)kSecAttrAccessGroup];
- #endif
- // An implicit assumption is that you can only update a single item at a time.
- result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
- NSAssert( result == noErr, @"Couldn't update the Keychain Item." );
- }
- else
- {
- // No previous item found; add the new one.
- result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
- NSAssert( result == noErr, @"Couldn't add the Keychain Item." );
- }
- }
- @end
- //1.创建钥匙串对象
- //参数1: 标识, 用于识别将要加密的内容(回传标识符)
- //参数2: 分组 一般为nil
- KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]initWithIdentifier:@"myItemWrapper" accessGroup:nil];
- //常用于加密用户名和密码
- //系统提供键值对中的两个键, 非系统的键是没法添加到字典中的
- id kUserName = (__bridge id)kSecAttrAccount;
- id kUserPassword = (__bridge id)kSecValueData;
- [keychainItem setObject:@"MBBoy" forKey:kUserName];
- [keychainItem setObject:@"123456" forKey:kUserPassword];
- //从keychain中获取存储的数据
- //用户名
- NSString *userName = [keychainItem objectForKey:kUserName];
- //密码
- NSString *password = [keychainItem objectForKey:kUserPassword];
KVO加密-----
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- //初始化
- self.array = [NSMutableArray array];
- //第一步: 注册观察者
- //参数1: 添加的观察者对象
- //参数2: 字符串标识的key
- //参数3: 什么时候会触发观察者对象
- //参数4: 文本内容 一般为nil
- [self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew context:nil];
- }
- //第二步: 实现回调方法
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
- NSLog(@"keyPath = %@", keyPath);
- NSLog(@"object = %@", object);
- NSLog(@"change = %@", change);
- //可以进行刷新UI的操作
- }
- //视图将要消失的时候
- - (void)viewWillDisappear:(BOOL)animated {
- //在不要需要观察者的时候需要把它给干掉
- [self removeObserver:self forKeyPath:@"array"];
- }
- //第三步: 触发可变数组进行改变
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- NSArray *subArray = @[@"1", @"2", @"3"];
- //根据keyPath获取到可变数组对象设置数据
- [[self mutableArrayValueForKeyPath:@"array"] setArray:subArray];
- }
iOS之数据安全的更多相关文章
- 保护 iOS 用户数据安全: Keychain 和 Touch ID
原文:How To Secure iOS User Data: The Keychain and Touch ID 作者:Tim Mitra 译者:kmyhy 更新说明:本教程由 Tim Mitra ...
- iOS开发中的数据安全隐患和解决方案
移动互联网的兴起,每天都会涌现大量的app产品,无论公司开发还是个人开发,大家都在追求更快的抢占市场,但是确忽略了打磨产品,也忽略了移动开发中的数据安全隐患,如果我们用Charles工具,很容易截获到 ...
- 苹果系统iOS、macOS应用管理机制
iOS.macOS系统应用管理机制 苹果系统包括:iOS.macOS.watchOS.tvOS.应用软件的生命周期为:开发.上线.安装.使用.卸载.这篇文档将从应用生命周期的各个环节介绍苹果系统对应用 ...
- iOS开发——网络篇——数据安全(MD5),HTTPS,检测网络状态
一.数据安全 1.提交用户的隐私数据一定要使用POST请求提交用户的隐私数据GET请求的所有参数都直接暴露在URL中请求的URL一般会记录在服务器的访问日志中服务器的访问日志是黑客攻击的重点对象之一 ...
- 【原】iOS学习40网络之数据安全
在互联网发展趋势迅猛的今天,数据安全的重要性日趋凸显.也成为我们必须了解的互联网知识. 在移动互联网浪潮下,用户的资金安全.企业的信息安全都是我们实际开发中必须考虑的内容.
- iOS开发网络篇—数据安全
iOS开发网络篇—数据安全 一.简单说明 1.说明 在开发应用的时候,数据的安全性至关重要,而仅仅用POST请求提交用户的隐私数据,还是不能完全解决安全问题. 如:可以利用软件(比如Charles)设 ...
- iOS开发 - 网络数据安全加密(MD5)
提交用户的隐私数据 一定要使用POST请求提交用户的隐私数据GET请求的所有参数都直接暴露在URL中请求的URL一般会记录在服务器的访问日志中服务器的访问日志是黑客攻击的重点对象之一 用户的隐私数据登 ...
- iOS——数据安全
在移动互联网快速发展的今天,iOS应用直接运行在用户的手机上,与运行在服务器后台服务相比,更有可能被黑客攻击. a.网络安全: 1.1 安全地传输用户密码 事先生成一对用于加密的公私钥,客户端登录的时 ...
- iOS 数据安全、数据加密传输
近期接到一个新需求:APP企业版需要接入热更新功能. 热更新需要下发补丁脚本, 脚本下发过程中需要保证脚本传输安全,且需要避免中间人攻击. 需要用到数据加密传输方面的知识,以下是我设计的加密解密流程: ...
随机推荐
- IOI2011ricehub米仓
Description 乡间有一条笔直而长的路称为"米道".沿着这条米道上 R 块稻田,每块稻田的坐标均为一个 1 到 L 之间(含 1 和 L)的整数.这些稻田按照坐标以不减的顺 ...
- appium 1.6.3+Xcode运 For Mac
1. 下载两个版本的Xcode, Xcode 1.7.3 与Xcode 8.2 ,放置在不同的目录下.进入terminal, 选择需要的版本: sudo xcode-select -switch // ...
- Linux启动盘-ultraiso
感觉windos和linux安装系统的启动盘不一样 其实我也不太懂. windos的时候我是用老毛桃 然后安装linux我就选择了ultraios作为启动盘 一: 先在百度下载 ultraios 二 ...
- WINDOWS7(vs2012+wdk7.6) 配置驱动开发环境
合肥程序员群:49313181. 合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q Q:408365330 E-Mail:egojit@qq.com 1.新建C ...
- Best Time to Buy and Sell Stock III [LeetCode]
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- SHAREPOINT 2013 列表之间相互关联
修改内容 1.增加列表设置,隐藏Aid字段操作 SharePoint 列表之间相互关联 例如两张列表之间的父子关系. 思路如下: 列表中新增列表项后会有一个唯一的ID,我们获取到该ID赋予子表即可将两 ...
- css中各种情况下的元素的垂直和水平居中的问题
问题:外边是一个容器,容器中还有一个容器,那么请问怎么让里边的容器垂直水平居中显示?? No1: 外边的容器宽度和高度确认,里边是行内元素 .container{width:200px; height ...
- react native 页面跳转
React Native目前有几个内置的导航器组件,一般来说我们首推Navigator.它使用纯JavaScript实现了一个导航栈,因此可以跨平台工作 场景简单来说其实就是一个全屏的React组件. ...
- js 判断是什么类型浏览器
// firefoxif ( window.sidebar && "object" == typeof( window.sidebar ) && ...
- solution to E: failed to fetch .......
There are some issues today for me that my desktop can't boot as I expected, I installed windows 8.1 ...