大部分中文應用彈出的默認鍵盤是簡體中文輸入法鍵盤布轿,在輸入用戶名和密碼的時候哮笆,如果使用簡體中文輸入法鍵盤,輸入英文字符和數(shù)字字符的用戶名和密碼時汰扭,會自動啟動系統(tǒng)輸入法自動更正提示稠肘,然后用戶的輸入記錄會被緩存下來。
系統(tǒng)鍵盤緩存最方便拿到的就是利用系統(tǒng)輸入法自動更正的字符串輸入記錄萝毛。 緩存文件的地址是:
/private/var/mobile/Library/Keyboard/dynamic-text.dat
導出該緩存文件启具,查看內容,欣喜的發(fā)現(xiàn)一切輸入記錄都是明文存儲的珊泳。因為系統(tǒng)不會把所有的用戶輸入記錄都當作密碼等敏感信息來處理鲁冯。 一般情況下拷沸,一個常規(guī) iPhone 用戶的 dynamic-text.dat 文件,高頻率出現(xiàn)的字符串就是用戶名和密碼薯演。
所以撞芍,一般銀行客戶端 app 輸入密碼時都不使用系統(tǒng)鍵盤,而使用自己定制的鍵盤跨扮,原因主要有 2 個:
1)避免第三方讀取系統(tǒng)鍵盤緩存
2)防止屏幕錄制 (自己定制的鍵盤按鍵不加按下效果)
那么序无,如何實現(xiàn)自定義安全鍵盤呢?大致思路如下:
1)首先捕獲系統(tǒng)鍵盤的彈出衡创、收回通知
2)創(chuàng)建一個更高級別的 window 擋住系統(tǒng)鍵盤
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