大部分中文應用彈出的預設鍵盤是簡體中文IME鍵盤,在輸入使用者名稱和密碼的時候,如果使用簡體中文IME鍵盤,輸入英文字元和數字字元的使用者名稱和密碼時,會自動啟動系統IME自動校正提示,然後使用者的輸入記錄會被緩衝下來。
系統鍵盤緩衝最方便拿到的就是利用系統IME自動校正的字串輸入記錄。
快取檔案的地址是:/private/var/mobile/Library/Keyboard/dynamic-text.dat
匯出該快取檔案,查看內容,欣喜的發現一切輸入記錄都是明文儲存的。因為系統不會把所有的使用者輸入記錄都當作密碼等敏感資訊來處理。
一般情況下,一個常規iPhone使用者的dynamic-text.dat檔案,高頻率出現的字串就是使用者名稱和密碼。
所以,一般銀行用戶端app輸入密碼時都不使用系統鍵盤,而使用自己定製的鍵盤,原因主要有2個:
1)避免第三方讀取系統鍵盤緩衝
2)防止螢幕錄製 (自己定製的鍵盤按鍵不加按下效果)
那麼,如何?自訂安全鍵盤呢?大致思路如下:
1)首先捕獲系統鍵盤的彈出、收回通知
2)建立一個更進階別的window擋住系統鍵盤
3)需要拋出一個 id<UITextInput>textInput 的弱引用切換焦點
下面給出一個簡單的安全鍵盤模型:
@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