iOS的keychain可以說(shuō)是系統(tǒng)里唯一可以做到安全可靠存儲(chǔ)應(yīng)用敏感數(shù)據(jù)并且可以在應(yīng)用卸載或重新安裝時(shí)仍然保留其數(shù)據(jù)的地方。當(dāng)使用itunes進(jìn)行數(shù)據(jù)備份時(shí),每個(gè)應(yīng)用程序在keychain里的數(shù)據(jù)都會(huì)得到備份,而且備份的數(shù)據(jù)是經(jīng)過(guò)加密的,所以無(wú)論數(shù)據(jù)存儲(chǔ)在哪里,都十分安全。鑒于keychain的這些特性,使得它成為開(kāi)發(fā)者存儲(chǔ)應(yīng)用敏感數(shù)據(jù)的選,應(yīng)用程序常見(jiàn)的敏感數(shù)據(jù)通常有密碼,秘鑰等等。
成都創(chuàng)新互聯(lián)公司專(zhuān)注于汕頭企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,商城網(wǎng)站定制開(kāi)發(fā)。汕頭網(wǎng)站建設(shè)公司,為汕頭等地區(qū)提供建站服務(wù)。全流程按需定制,專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)公司專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)然而,開(kāi)發(fā)者面臨的一個(gè)問(wèn)題是,iOS sdk里提供的keychain接口十分隱晦難用,初學(xué)者在理解及應(yīng)用上遇到了不小的麻煩,甚至Apple官方提供的keychain示例代碼GenericKeychain也都十分難讀懂。因此,本文試圖將keychain的使用進(jìn)行一下梳理,讓初學(xué)者能夠了解其基本使用。
準(zhǔn)備工作
準(zhǔn)備使用keychain接口前,首先需要在xcode里加入Security.framework,然后在代碼里加入頭文件 "#import <Security/Security.h>"。注意,如果你使用的是object-c,Security.framework里的接口都是C語(yǔ)言風(fēng)格接口而不是object-c語(yǔ)言風(fēng)格的接口。此外,Security.framework只工作在實(shí)際設(shè)備上,無(wú)法在模擬器上使用。
Keychain概覽
Keychain里可以存儲(chǔ)若干條目(item),每個(gè)條目都屬于某一個(gè)類(lèi)別(class),以下是常見(jiàn)的幾種類(lèi)別:
kSecClassInternetPassword
屬于該類(lèi)別的條目往往用來(lái)存儲(chǔ)上網(wǎng)登錄密碼,遠(yuǎn)程服務(wù)器密碼等
kSecClassGenericPassword
存儲(chǔ)一些通用的密碼,比如數(shù)據(jù)庫(kù)密碼,***連接的密碼等等
kSecClassCertificate, kSecClassKey和kSecClassIdentity
這三類(lèi)條目往往用于建立基于證書(shū),秘鑰和公鑰系統(tǒng)的安全連接。
條目類(lèi)別是一個(gè)條目最基本的屬性,每個(gè)存入keychain的條目,都需要為它制定一個(gè)類(lèi)別。
操作keychain常見(jiàn)的3個(gè)方法:
SecItemAdd
添加新條目到keychain.
SecItemUpdate
修改一個(gè)已存在keychain里的條目
SecItemCopyMatching
查詢(xún)keychain里的條目并且讀取條目信息
下面用一張摘取自蘋(píng)果官方網(wǎng)站的一張圖闡述一下一個(gè)常見(jiàn)keychain的操作流程,該圖以一個(gè)應(yīng)用連接ftp服務(wù)器為例
在上圖中,應(yīng)用大概流程是這樣的:應(yīng)用開(kāi)始連接ftp服務(wù)器,首先查詢(xún)keychain是否存在服務(wù)器密碼,如果存在,那么直接取出密碼登陸;如果不存在,那么應(yīng)用彈出對(duì)話框要求用戶(hù)輸入,然后進(jìn)行登陸,如果登陸成功,那么存儲(chǔ)密碼到keychain。
Keychain接口參數(shù)
所有對(duì)keychain接口的操作,參數(shù)的傳遞基本上都用到字典,將所需要的參數(shù)放入字典,然后將字典傳遞給keychain接口。上面提到的條目類(lèi)別,就是一個(gè)參數(shù),除此之外,操作條目往往還需要條目ID,條目所屬服務(wù)名,條目所屬賬戶(hù)名等。這些參數(shù)的名稱(chēng)如下:
kSecClass:條目類(lèi)別
kSecAttrGeneric:條目id
kSecAttrService:條目所屬服務(wù)
kSecAttrAccount:條目所屬賬戶(hù)名
其中kSecAttrService和kSecAttrAccount在整個(gè)keychain里必須唯一,不能重名。
Keychain條目查詢(xún)
使用SecItemCopyMatching進(jìn)行查詢(xún),查詢(xún)時(shí),我們需要指明要查詢(xún)條目的類(lèi)別(kSecClass),條目的id(kSecAttrGeneric),條目所屬的服務(wù)和賬戶(hù)(kSecAttrService,kSecAttrAccount)。此外,我們還可以設(shè)置其他一些查詢(xún)條件,比如返回條目的數(shù)量(kSecMatchLimit),返回條目的數(shù)據(jù)類(lèi)型,比如:
kSecReturnData:返回條目所存儲(chǔ)的數(shù)據(jù),返回值類(lèi)型是CFDataRef
kSecReturnAttributes:返回該條目的屬性,返回值是字典類(lèi)型CFDictionaryRef
kSecReturnRef:返回條目的引用,根據(jù)條目所屬類(lèi)別,返回值類(lèi)型可能是:SecKeychainItemRef, SecKeyRef,SecCertificateRef, SecIdentityRef.
kSecReturnPersistentRef:返回條目的引用,返回值類(lèi)型是CFDataRef
如下代碼示例用來(lái)查詢(xún)存儲(chǔ)在keychain里的密碼
//建立詞典,用來(lái)傳遞參數(shù) NSMutableDictionary *dictionary = [[NSMutableDictionary dictionary]; //設(shè)置條目類(lèi)別,我們用該條目存儲(chǔ)普通密碼,所以設(shè)置成kSecClassGenericPassword [dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; //設(shè)置條目的id,比如“MyPasswordForFtp",條目id必須時(shí)NSDate,而不是NSString NSString *itemIDString = @"MyPasswordForFtp"; NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding]; [dictionary setObject:itemIDforKey:(id)kSecAttrGeneric]; //設(shè)置條目所屬的服務(wù)和賬戶(hù),為了避免重名,我們使用常見(jiàn)的反轉(zhuǎn)域名規(guī)則,比如com.mykeychain.ftppassword NSString *account = @"com.mykeychain.ftppassword"; NSString *service = @"com.mykeychain.ftppassword"; [dictionary setObject:account forKey:(id)kSecAttrAccount]; [dictionary setObject:service forKey:(id)kSecAttrService]; //設(shè)置查詢(xún)條件,只返回一個(gè)條目 [dictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; //設(shè)置查詢(xún)條件,返回條目存儲(chǔ)的數(shù)據(jù) (kSecReturnData == True) [dictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; //開(kāi)始查詢(xún) NSData *result = nil; OSStatus status = SecItemCopyMatching((CFDictionaryRef)dictionary , (CFTypeRef *)&result);
Keychain條目添加
使用SecItemAdd()進(jìn)行條目添加,我們需要指明新條目的類(lèi)別(kSecClass),新條目的id(kSecAttrGeneric),新條目所屬的服務(wù)和賬戶(hù)(kSecAttrService,kSecAttrAccount),此外,還需要指明該條目所存儲(chǔ)的數(shù)據(jù)(kSecValueData),否則,沒(méi)有數(shù)據(jù)的條目就沒(méi)有任何存入keychain的意義了。
請(qǐng)看如下代碼示例:
//建立詞典,用來(lái)傳遞參數(shù) NSMutableDictionary *dictionary = [[NSMutableDictionary dictionary]; //設(shè)置條目類(lèi)別,我們用該條目存儲(chǔ)普通密碼,所以設(shè)置成kSecClassGenericPassword [dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; //設(shè)置條目的id,比如“MyPasswordForFtp",條目id必須時(shí)NSDate,而不是NSString NSString *itemIDString = @"MyPasswordForFtp"; NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding]; [dictionary setObject:itemIDforKey:(id)kSecAttrGeneric]; //設(shè)置條目所屬的服務(wù)和賬戶(hù),為了避免重名,我們使用常見(jiàn)的反轉(zhuǎn)域名規(guī)則,比如com.mykeychain.ftppassword NSString *account = @"com.mykeychain.ftppassword"; NSString *service = @"com.mykeychain.ftppassword"; [dictionary setObject:account forKey:(id)kSecAttrAccount]; [dictionary setObject:service forKey:(id)kSecAttrService]; //設(shè)置條目數(shù)據(jù),條目數(shù)據(jù)時(shí)NSDate NSString *password = @"123456"; NSData *itemData = [password dataUsingEncoding:NSUTF8StringEncoding]; [dictionary setObject:itemData forKey:(id)kSecValueData]; //添加條目到keychain OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
keychain條目的修改
使用SecItemUpdate()進(jìn)行條目修改,需要傳入兩個(gè)詞典,第一個(gè)詞典用來(lái)查詢(xún)條目,第二個(gè)詞典用來(lái)傳遞修改后的新值。查詢(xún)條目所用的詞典設(shè)置請(qǐng)看上述Keychain條目查詢(xún)章節(jié),更新值所用詞典里設(shè)置要更新的參數(shù)和值。這里請(qǐng)注意的是,查詢(xún)?cè)~典里不能設(shè)置任何查詢(xún)條件,比如kSecMatchLimit和kSecReturnData,kSecReturnAttributes等,否則會(huì)出錯(cuò)。因?yàn)檫@里的查詢(xún)是為了更新數(shù)據(jù),是以寫(xiě)入為目的,不是真正的查詢(xún)和讀取條目,所以設(shè)置這些和讀取有關(guān)的條件是無(wú)意義的,系統(tǒng)會(huì)認(rèn)為是和安全有關(guān)的錯(cuò)誤,會(huì)返回-50(errSecParam)
下面代碼用來(lái)更新密碼,要更新的條目id為“MyPasswordForFtp”的條目
//建立查詢(xún)字典 NSMutableDictionary *searchDictionary = [[NSMutableDictionary dictionary]; //設(shè)置查詢(xún)字典 [searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; NSString *itemIDString = @"MyPasswordForFtp"; NSData *itemID= [itemIDString dataUsingEncoding:NSUTF8StringEncoding]; [searchDictionary setObject:itemIDforKey:(id)kSecAttrGeneric]; NSString *account = @"com.mykeychain.ftppassword"; NSString *service = @"com.mykeychain.ftppassword"; [searchDictionary setObject:account forKey:(id)kSecAttrAccount]; [searchDictionary setObject:service forKey:(id)kSecAttrService]; // 建立更新字典 NSMutableDictionary *updateDictionary = [[NSMutableDictionary dictionary]; // 設(shè)置要更新的新密碼 NSString* newPassword = @"654321"; NSData *passwordData = [newPassword dataUsingEncoding:NSUTF8StringEncoding]; [updateDictionary setObject:passwordData forKey:(id)kSecValueData]; //進(jìn)行更新 OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary, (CFDictionaryRef)updateDictionary);
keychain接口常見(jiàn)錯(cuò)誤
SecItemUpdate 返回-50(errSecParam):請(qǐng)檢查查詢(xún)?cè)~典里是否存在讀取條件,比如kSecReturnData,kSecMatchLimit等
SecItemAdd 返回-25299 (errSecDuplicateItem: 請(qǐng)檢查kSecAttrAccount和kSecAttrService是否已經(jīng)存在于keychain中,請(qǐng)嘗試設(shè)置其他值避免重復(fù)
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。
網(wǎng)站欄目:談?wù)刬OSKeychain的使用-創(chuàng)新互聯(lián)
網(wǎng)站URL:http://vcdvsql.cn/article18/jijgp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、關(guān)鍵詞優(yōu)化、用戶(hù)體驗(yàn)、網(wǎng)站建設(shè)、微信公眾號(hào)、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
網(wǎng)頁(yè)設(shè)計(jì)公司知識(shí)