iOS KeyChain ไม่ดึงค่าจากพื้นหลัง


87

ฉันกำลังจัดเก็บชื่อผู้ใช้ (อีเมล) และแฮชอีเมลและรหัสผ่านใน iOS KeyChain ผมใช้รุ่น ARC'ified พบที่นี่

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
[wrapper setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
[wrapper setObject:email forKey:(__bridge id)kSecAttrAccount];
[wrapper setObject:token forKey:(__bridge id)kSecValueData];

ทั้งหมดนี้ใช้งานได้ดีเมื่อฉันต้องการดึงโทเค็นออกสำหรับการโทรเครือข่ายของฉันในขณะที่แอปทำงานอยู่ ใช้สำหรับการเข้าสู่ระบบจากการเริ่มต้นระบบใหม่ทั้งหมดรวมทั้งการโทรในเครือข่าย ปัญหาเริ่มต้นเมื่อแอปทำงานอยู่เบื้องหลัง

โปรดทราบว่าสิ่งนี้จะเกิดขึ้นเป็นระยะ ๆ เท่านั้นและฉันยังไม่ได้ปักหมุดลงใน iOS เวอร์ชันหรืออุปกรณ์ที่เฉพาะเจาะจง

ผู้ใช้เดินทางไปยังตำแหน่งที่ตั้ง (การตรวจสอบภูมิภาค) และฉันต้องการอัปเดตเซิร์ฟเวอร์ด้วยสถานะ ฉันพยายามดึงโทเค็นออกจากพวงกุญแจแบบเดียวกับที่ฉันโทรหาเครือข่ายอื่น ๆ และอัปเดตสถานะ แต่สำหรับผู้ใช้บางรายค่าจะเป็นศูนย์ หากไม่มีฉันจะอัปเดตข้อมูลเครือข่ายไม่ได้ เหตุใดสิ่งนี้จึงใช้ได้ผลกับคนส่วนใหญ่ แต่ไม่ได้ผลเพียงเล็กน้อย

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
NSString *token = [wrapper objectForKey:(__bridge id)kSecValueData];

ฉันกลับไปใช้เครื่องห่อพวงกุญแจเวอร์ชันที่ไม่ใช่ ARC แล้ว แต่ฉันก็ยังได้ผลลัพธ์เหมือนเดิม ฉันจะขอบคุณข้อเสนอแนะใด ๆ เกี่ยวกับเรื่องนี้ เป็นเพียงส่วนเล็ก ๆ ของผู้ใช้ของฉัน แต่เป็นปัญหาที่ฉันต้องการแก้ไขและไม่ต้องกังวล ขอบคุณล่วงหน้า.

นอกจากนี้งานเบื้องหลังทั้งหมดของฉันยังถูกตั้งค่าเป็น backgroundTask เพื่อป้องกันไม่ให้สิ่งต่างๆหมดเวลา ฉันไม่มีปัญหาใด ๆ กับงานที่อยู่รอบ ๆ พวงกุญแจ แต่ฉันไม่ปล่อยให้สิ่งต่างๆดำเนินต่อไปจนกว่าโทเค็นของฉันจะเต็ม

แก้ไข ฉันพบปัญหาของฉันโดยที่พวงกุญแจไม่ดึงค่าจากพื้นหลัง ฉันจะโพสต์คำตอบด้านล่างและยอมรับเพราะฉันรู้สึกว่าคำถามนี้อาจมีค่าสำหรับคนอื่นในภายหลัง

คำตอบ:


110

คำถามของฉันอยู่ใกล้กับเครื่องหมายด้วยเหตุผลว่าทำไม แต่ไม่มาก หลังจากอ่านบล็อกหลังบล็อกการสอนหลังการสอนในที่สุดฉันก็พบสิ่งที่บอกใบ้ถึงสิ่งที่อาจเกิดขึ้น

ล็อกหน้าจอหลัก บทแนะนำของพวงกุญแจจะปล่อยให้การตั้งค่าการช่วยการเข้าถึงสำหรับพวงกุญแจว่างไว้เสมอดังนั้นค่าเริ่มต้นจะเป็นระดับการเข้าถึงที่ต่ำที่สุด / ปลอดภัยที่สุดของ Apple อย่างไรก็ตามระดับนี้ไม่อนุญาตให้เข้าถึงพวงกุญแจหากผู้ใช้มีรหัสผ่านบนหน้าจอล็อก บิงโก! สิ่งนี้อธิบายถึงพฤติกรรมที่เกิดขึ้นเป็นพัก ๆ และเหตุใดสิ่งนี้จึงเกิดขึ้นกับผู้ใช้เพียงไม่กี่เปอร์เซ็นต์

รหัสบรรทัดเดียวแก้ปัญหาทั้งหมด

[wrapper setObject:(__bridge id)kSecAttrAccessibleAlways forKey:(__bridge id)kSecAttrAccessible];

เพิ่มบรรทัดนี้ที่ฉันกำลังตั้งค่าชื่อผู้ใช้และรหัสผ่าน ใช้งานได้เหมือนมีเสน่ห์ หวังว่านี่จะช่วยใครบางคนได้ มันทำให้ฉันสับสนอยู่พักหนึ่งจนกระทั่งฉันสามารถประกอบชิ้นส่วนเข้าด้วยกันได้


1
ขอบคุณ! สิ่งนี้มีประโยชน์มาก
Rich Waters

3
เราจัดการกับเรื่องนี้มาหลายสัปดาห์แล้ว คุณเป็นผู้ช่วยชีวิต!
OC Rickard

15
โปรดหลีกเลี่ยง…AccessibleAlwaysถ้าเป็นไปได้หรือจัดเก็บโทเค็นที่ให้สิทธิ์ จำกัด เท่านั้น (เช่นโทเค็นที่อนุญาตให้คุณอ่านรายการฟีดใหม่ แต่ไม่สามารถโพสต์ได้) คุณกำลังละทิ้งระดับการเข้ารหัสอย่างชัดเจนโดยการทำเช่นนั้น หากแอปของคุณสามารถรอจนกว่าจะมีการปลดล็อกครั้งแรกอาจเป็นการดีที่สุดที่จะใช้…AfterFirstUnlockและสั่งให้ผู้ใช้ปลดล็อกอุปกรณ์ก่อน
millenomi

14
นี่เป็นความคิดที่แย่มากเพราะหมายความว่าข้อมูลรับรองนี้จะไม่ได้รับการปกป้องอีกต่อไป แม้ว่าจะมีงานเพิ่มขึ้นเล็กน้อย แต่การสร้างข้อมูลรับรองอนุพันธ์เป็นสิ่งสำคัญมากกว่าที่จะใช้สำหรับการเข้าถึงแบบ จำกัด ที่คุณคาดว่าจะต้องใช้ในเบื้องหลังและไม่ต้องทำอีกต่อไป ข้อมูลรับรองที่ จำกัด นั้นอาจหมดอายุได้ในระยะเวลาหนึ่งและข้อมูลรับรองใหม่จะสร้างขึ้นทุกครั้งที่เปิดแอปทำให้ข้อมูลรับรองเก่าเป็นโมฆะ สิ่งนี้จะช่วยให้ผู้ใช้ปลอดภัยในกรณีที่ข้อมูลรับรองอนุพันธ์ถูกบุกรุก อ้างถึง WWDC 2013 เซสชัน 204 เพื่อฟังเกี่ยวกับเรื่องนี้
Joey Hagedorn

7
สะท้อน @JoeyHagedorn ที่นี่ - ฟัง WWDC 2013 เซสชัน 204 "มีอะไรใหม่กับมัลติทาสก์" ที่เครื่องหมาย 44:24 และ WWDC 2013 เซสชัน 709 "การปกป้องความลับด้วยพวงกุญแจ" ที่เครื่องหมาย 25:30 น. คุณสามารถดูเนื้อหาข้อความของการพูดคุยเหล่านี้ได้ที่asciiwwdc.com
Shazron

64

ใช้kSecAttrAccessibleAfterFirstUnlockแทนkSecAttrAccessibleAlways.


จากเอกสารของ Apple :

kSecAttrAccessibleAfterFirstUnlock
ไม่สามารถเข้าถึงข้อมูลในรายการพวงกุญแจได้หลังจากรีสตาร์ทจนกว่าผู้ใช้จะปลดล็อกอุปกรณ์หนึ่งครั้ง

หลังจากปลดล็อกครั้งแรกข้อมูลจะยังคงสามารถเข้าถึงได้จนกว่าจะรีสตาร์ทครั้งถัดไป ขอแนะนำสำหรับรายการที่ต้องเข้าถึงโดยแอปพลิเคชันพื้นหลัง รายการที่มีแอตทริบิวต์นี้จะย้ายไปยังอุปกรณ์ใหม่เมื่อใช้การสำรองข้อมูลที่เข้ารหัส


4
คำตอบนี้ควรเป็นความคิดเห็น…
Frizlab

คำตอบนี้ดูเหมือนจะสมบูรณ์แบบเพราะkSecAttrAccessibleAlwaysเลิกใช้แล้ว
Sazzad Hissain Khan

1

ในกรณีของฉัน watchOS2 เข้าถึงข้อมูลพวงกุญแจทางฝั่ง iOS

ในตอนต้นจะใช้ kSecAttrAccessibleWhenUnlockedThisDeviceOnly ฉันสามารถอ่านข้อมูลได้ไม่ว่า iPhone จะล็อกหรือไม่ก็ตาม ฉันสับสนมากที่ฉันจะได้รับข้อผิดพลาดเมื่อนาฬิกาพยายามเข้าถึงพวงกุญแจ:: SecTrustEvaluate [ใบ IssuerCommonName SubjectCommonName]

และบางกรณีมันจะกลายเป็น:: SecOSStatusWith error: [- 25308] Error Domain = NSOSStatusErrorDomain Code = -25308 "ks_crypt: e00002e2 ล้มเหลวในการ 'oe' (คลาส 6, กระเป๋า: 0) การเข้าถึงไอเท็มที่พยายามในขณะที่พวงกุญแจถูกล็อค " UserInfo = {NSDescription = ks_crypt: e00002e2 ล้มเหลวในการ 'oe' รายการ (คลาส 6, กระเป๋า: 0) การเข้าถึงรายการที่พยายามในขณะที่พวงกุญแจถูกล็อค}

ฉันจะอัปเดตคำตอบหากได้รับข่าวสารเพิ่มเติม


0

สิ่งนี้อาจเกิดขึ้นเนื่องจากนโยบายการปกป้องข้อมูลของแอปเปิ้ลซึ่งบางระดับไม่ชัดเจนจากมุมมองของนักพัฒนา วิธีแก้ปัญหาคือเมื่อเปิดแอปตรวจสอบว่าสามารถเข้าถึงพวงกุญแจได้หรือไม่หากไม่สามารถเข้าถึงได้คุณอาจฆ่าแอปของคุณ (ด้วยป๊อปอัปที่เหมาะสม) ขึ้นอยู่กับประเภทแอปของคุณ

+(BOOL) isKeychainAccessible
{
    NSString *keychainTestKey = @"keychainTestKey";
    NSString *keychainTestValue = @"keychainTestValue";
    [self createKeychainValue:keychainTestValue forIdentifier:keychainTestKey];
    NSString *loadedValue = [self keychainStringFromMatchingIdentifier:keychainTestKey];
    [self deleteItemFromKeychainWithIdentifier:keychainTestKey];
    return ([keychainTestValue isEqualToString: loadedValue]);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.