Bảo mật là một phần quan trọng trong quá trình phát triển phần mềm. Phần lớn các ứng dụng di động thao tác với thông tin người dùng qua một remote server. Mặc dù công nghệ bảo mật đã có sự phát triển vượt bậc trong thập kỷ qua, nhưng nó vẫn là một chủ để thu hút được nhiều tranh luận.

 

Là một developer không sớm thì muộn bạn cũng sẽ phải đối mặt với vấn đề lưu trữ những dữ liệu nhạy cảm của người dùng. Bài viết này nói về việc sử dụng Keychain để lưu trữ những dữ liệu nhạy cảm đó.

1. Điểm khác nhau giữa iOS keychain và OS X keychain.

Cũng giống như OS X, iOS cũng cung cấp một keychain cho ứng dụng của bạn để có thể lưu trữ tất cả các loại dữ liệu nhạy cảm như mật khẩu của người dùng hay thông tin tài khoản ngân hàng ... Nhưng kaychain của OS X thì phức tạp hơn keychain trên iOS rất nhiều. Đầu tiên trong OSX bất kỳ ứng dụng nào cũng đều có thể yêu cầu quyền truy cập vào bất cứ thông tin nào được lưu trong keychain. Nếu bạn là người dùng OS X, bạn có thể nhớ lại những nhắc nhở thông báo cho bạn rằng ứng dụng nhất định nào đó muốn truy cập vào dữ liệu trong keychain của bạn. Nó trông giống như thế này. 

Khi bạn nhập mật khẩu của bạn. Keychain sẽ mở và lấy dữ liệu vào giao nó cho ứng dụng yêu cầu.

Thứ hai. OS X keychain có thêm một tính năng mà bạn không thể tìm thấy nó ở iOS keychain, và đây là điều làm cho iOS keychain nó đơn giản như vậy. Trong OS X, người dùng có thể tạo ra nhiều hơn một keychain cho những thứ khác nhau. Một giấy chứng nhận, một mật khẩu, một cho bất cứ điều gì khác mà có thể cho là nhạy cảm (Không nhiều người làm được điều này nhưng tính năng keychain này là có cho những ai cần nó).

Trong iOS, Mỗi ứng dụng có keychain của riêng mình và keychain này không thể bị truy cập bởi bất kỳ ứng dụng nào khác, trừ khi cả hai ứng dụng muốn truy cập vào keychain này do bạn tạo ra và nó được kích hoạt tính năng keychain sharing và cả 2 chúng nằm cùng một Keychain Access Group. Đây là mô hình hoàn toàn khác so với OS X keychain, do đó các ứng dụng khác không thể làm xáo trộn thông tin keychain của bạn. Ngoài ra mỗi ứng dụng chỉ có một keychain, nơi bạn có thể lưu nhiều mục keychain.

Điểm khác nữa không giống OS X là người sử dụng không nhận thức được sự tồn tại của keychain trong iOS. Khi bạn đang làm việc với iOS keychain người dùng không bao giờ thấy được bất kỳ nhắc nhở và không có cách nào để người sử dụng tương tác với ứng dụng của bạn. Keychain hoàn toàn ẩn với người dùng cuối.

 

​​​iOS keychain: khái niệm và cấu trúc

keychain là kho lưu trữ, bảo mật và được mã hoá, ứng dụng của bạn có thể sử dụng chúng để lưu những thông tin nhạy cảm. Điều quan trọng là ứng dụng của bạn và tất cả các version sau này đều phải liên kết chung một file provisioning profile. Nếu không bạn sẽ gặp nhiều rắc rối sau nay.

keychain item là một đơn vị dữ liệu nhạy cảm được lưu trong keychain. item keychain chứa dữ liệu nhạy cảm và một hoặc nhiều thuộc tính. Các thuộc tính mô tả item keychain và thuộc tính bạn có thể sử dụng phụ thuộc và item class của item keychain. item class là loại của dữ liệu cái mà bạn đang lưu trữ. các item keychain và các thuộc tính của nó được lưu trữ dưới dạng dictionary tức là dạng một cặp gồm "key" và "value"

 

Bắt tay làm demo thôi.

Đầu tiên hãy tải về project khởi đầu tại đây:keychain.zip 

project này chỉ đơn giản là một màn hình login và sau khi login sẽ hiện lên message "Hi!" :D

Giải nén và chạy ứng dụng bạn sẽ thấy nó trông giống thế này:

 

Và bây giờ chúng ta sẽ dùng iOS keychain để lưu username và password của người dùng để mở ứng dụng của chúng ta. Bạn có thể tải lớp keychainwrapper tại đây; Đây là lớp được apple cung cấp tại Keychain Services Programming Guide.

Sau khi tải, giải nén và kéo 2 file KeychainWrapper.h và KeychainWrapper.m vào ứng dụng của bạn như hình dưới

 

Khi popup hiện lên hãy chọn Copy items if needed. Khi bạn thêm file Objective-C và dự án Swift thì Xcode sẽ gợi ý tạo file bridging header – click Create Bridging Header:

Mở file keychain-Bridging-Header.h và import keychain wrapper vào đầu của file

#import "KeychainWrapper.h"

Mở ViewController.swift và thêm những dòng dưới vào trên func viewDidLoad()

let MyKeychainWrapper = KeychainWrapper()
let createLoginButtonTag = 0
let loginButtonTag = 1
@IBOutlet weak var loginButton: UIButton!

 

Mở file Main.storyboard Nhấn Ctrl và kéo từ  Login View Controller đén button Login, Như hình dưới:

và sau đó chọn loginButton 

Tiếp theo bạn cần handle 2 trường hợp khi nhấn nút đó là tạo mới acc nếu chưa tồn tại và login nếu đã có acc. Mở file ViewController.swift và thêm những dòng sau 

func checkLogin(username: String, password: String ) -> Bool {
        if password == MyKeychainWrapper.myObjectForKey("v_Data") as? String &&
            username == NSUserDefaults.standardUserDefaults().valueForKey("username") as? String {
            return true
        } else {
            return false
        }
    }
    
    @IBAction func login(sender: AnyObject){
        // 1.
        if (username!.text == "" || password!.text == "") {
            let alertView = UIAlertController(title: "Login Problem",
                                              message: "Wrong username or password." as String, preferredStyle:.Alert)
            let okAction = UIAlertAction(title: "Foiled Again!", style: .Default, handler: nil)
            alertView.addAction(okAction)
            self.presentViewController(alertView, animated: true, completion: nil)
            return;
        }
        
        // 2.
        username!.resignFirstResponder()
        password!.resignFirstResponder()
        
        // 3.
        if sender.tag == createLoginButtonTag {
            
            // 4.
            let hasLoginKey = NSUserDefaults.standardUserDefaults().boolForKey("hasLoginKey")
            if hasLoginKey == false {
                NSUserDefaults.standardUserDefaults().setValue(self.username!.text, forKey: "username")
            }
            
            // 5.
            MyKeychainWrapper.mySetObject(password!.text, forKey:kSecValueData)
            MyKeychainWrapper.writeToKeychain()
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: "hasLoginKey")
            NSUserDefaults.standardUserDefaults().synchronize()
            loginButton.tag = loginButtonTag
            
            let helloViewController = self.storyboard!.instantiateViewControllerWithIdentifier("helloController") as! HelloViewController
            helloViewController.userName = username!.text!
            
            self.navigationController!.pushViewController(helloViewController, animated: true)
        } else if sender.tag == loginButtonTag {
            // 6.
            if checkLogin(username!.text!, password: password!.text!) {
                let helloViewController = self.storyboard!.instantiateViewControllerWithIdentifier("helloController") as! HelloViewController
                helloViewController.userName = username!.text!
                
                self.navigationController!.pushViewController(helloViewController, animated: true)
            } else {
                // 7.
                let alertView = UIAlertController(title: "Login Problem",
                                                  message: "Wrong username or password." as String, preferredStyle:.Alert)
                let okAction = UIAlertAction(title: "Foiled Again!", style: .Default, handler: nil)
                alertView.addAction(okAction)
                self.presentViewController(alertView, animated: true, completion: nil)
            }
        }
    }

 

Đây là những gì xãy ra trong code:

  1. nếu username hay password rỗng, thì hiễn thị thông báo lỗi và thoát khỏi function.
  2. Ẩn keyboard.
  3. Nếu tag của button login là createLoginButtonTag, Thì xữ lý tạo mới acc.
  4. Tiếp theo bạn đọc hasLoginKey từ NSUserDefaults Nó cho biết password đã được lưu trong keychain hay chưa. nếu trường username trông và hasLoginKey cho thấy chưa có đăng nhập được lưu lại, thì bạn lưu username vào NSUserDefaults.
  5. Bạn sử dụng mySetObject và writeToKeychain để lưu nội dung password vào Keychain. Tiếp theo bạn lưu hasLoginKey trong NSUserDefaults thành true để báo hiệu password đã được lưu trong keychain. bạn set tag của button login thành loginButtonTag để báo cho người dùng phải login ở lần sử dụng app tiếp theo chứ không phải tạo acc lần nữa, Cuối cùng push view HelloViewController.
  6. Nếu người dùng đã login, bạn gọi checkLogin(_:password:) để xác nhận username và password; nếu nó đúng thì cho qua view HelloViewController.
  7. Nếu login sai thông tin thì thông báo lỗi cho người dùng.

Tiếp theo bạn thêm đoạn code sau vào viewdidload trên đoạn gọi super

         // 1.
        let hasLogin = NSUserDefaults.standardUserDefaults().boolForKey("hasLoginKey")
        // 2.
        if hasLogin {
            loginButton.setTitle("Login", forState: UIControlState.Normal)
            loginButton.tag = loginButtonTag
        } else {
            loginButton.setTitle("Create", forState: UIControlState.Normal)
            loginButton.tag = createLoginButtonTag
        }
        
        // 3.
        if let storedUsername = NSUserDefaults.standardUserDefaults().valueForKey("username") as? String {
            username!.text = storedUsername as String
        }

Và thêm function viewWillAppear để reset trường password khi trở lại view login

override func viewWillAppear(animated: Bool) {
        password!.text = "";
        super.viewWillAppear(animated)
    }

Chúc mừng bạn đã thêm được bước xác thực thông qua keychain


Leave a Comment

Fields with * are required.