鍵盤緩存與安全鍵盤
大部分中文應用彈出的默認鍵盤是簡體中文輸入法鍵盤,在輸入用戶名和密碼的時候,如果使用簡體中文輸入法鍵盤,輸入英文字符和數字字符的用戶名和密碼時,會自動啟動系統輸入法自動更正提示,然後用戶的輸入記錄會被緩存下來。
系統鍵盤緩存最方便拿到的就是利用系統輸入法自動更正的字符串輸入記錄。
緩存文件的地址是:/private/var/mobile/Library/Keyboard/dynamic-text.dat
導出該緩存文件,查看內容,欣喜的發現一切輸入記錄都是明文存儲的。因為系統不會把所有的用戶輸入記錄都當作密碼等敏感信息來處理。
一般情況下,一個常規iPhone用戶的dynamic-text.dat文件,高頻率出現的字符串就是用戶名和密碼。
所以,一般銀行客戶端app輸入密碼時都不使用系統鍵盤,而使用自己定制的鍵盤,原因主要有2個:
1)避免第三方讀取系統鍵盤緩存
2)防止屏幕錄制 (自己定制的鍵盤按鍵不加按下效果)
那麼,如何實現自定義安全鍵盤呢?大致思路如下:
1)首先捕獲系統鍵盤的彈出、收回通知
2)創建一個更高級別的window擋住系統鍵盤
3)需要拋出一個 idtextInput 的弱引用切換焦點
下面給出一個簡單的安全鍵盤模型:
@interface WQSafeKeyboard : UIWindow @property (nonatomic, weak, setter = focusOnTextFiled:) UITextField *textFiled; + (WQSafeKeyboard *)deploySafeKeyboard; @end @interface WQSafeKeyboard() @property (nonatomic, strong)WQInterKeyboard *keyboard; @end @implementation WQSafeKeyboard + (WQSafeKeyboard *)deploySafeKeyboard { WQSafeKeyboard *kb = [[WQSafeKeyboard alloc]init]; [kb addObserver]; return kb; } - (instancetype)init { if (self = [super init]) { self.windowLevel = UIWindowLevelAlert; self.frame = CGRectZero; self.rootViewController = self.keyboard; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (WQInterKeyboard *)keyboard { if (!_keyboard) { _keyboard = [[WQInterKeyboard alloc]init]; } return _keyboard; } - (void)focusOnTextFiled:(UITextField *)textFiled { _textFiled = textFiled; self.keyboard.textField = _textFiled; } - (void)addObserver { [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)keyboardWillShow:(NSNotification *)notification { if (![self.textFiled isFirstResponder]) { return; } [self keyboardAnimationWithNotification:notification]; } - (void)keyboardWillHide:(NSNotification *)notification { if (![self.textFiled isFirstResponder]) { return; } [self keyboardAnimationWithNotification:notification]; } - (void)keyboardAnimationWithNotification:(NSNotification *)notification { [self makeKeyAndVisible]; NSDictionary *userInfo = [notification userInfo]; CGRect kbFrame_end,kbFrame_begin; NSTimeInterval animationDuration; UIViewAnimationCurve animationCurve; [userInfo[UIKeyboardFrameEndUserInfoKey] getValue:&kbFrame_end]; [userInfo[UIKeyboardFrameBeginUserInfoKey] getValue:&kbFrame_begin]; [userInfo[UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; self.frame = [self resizeFrameToAdjust:kbFrame_begin]; [UIView animateWithDuration:animationDuration delay:0 options:(animationCurve<<16) animations:^{ self.frame = [self resizeFrameToAdjust:kbFrame_end]; }completion:^(BOOL finished) { }]; if ([notification.name isEqualToString:UIKeyboardWillHideNotification]) { [self resignKeyWindow]; } } - (CGRect)resizeFrameToAdjust:(CGRect)frame { if ([[UIApplication sharedApplication] isStatusBarHidden] ) return frame; if (SYSTEM_VERSION_LESS_THAN(@"7.0")) { frame = CGRectMake(frame.origin.x, frame.origin.y - STATUSBAR_HEIGHT, frame.size.width, frame.size.height); } return frame; } @end