[iOS] 간단한 키체인과 해싱으로 보안 강화 (Basic iOS Security: Keychain and Hashing)

[iOS] 간단한 키체인과 해싱으로 보안 강화 (Basic iOS Security: Keychain and Hashing)

민감한 데이터를 저장하고, 저장된 데이터를 안전하게 꺼내어 사용자 인증 하는 과정을 Keychain을 이용하여 구현하는 방법을 소개합니다.

해당 포스트의 원문은 다음과 같습니다 : https://www.raywenderlich.com/129-basic-ios-security-keychain-and-hashing
소스코드 다운로드

AuthViewController.signInButtonPressed()

  • 로그인 버튼이 눌렸을 떄 호출
  • AuthViewController.signIn() 함수 호출

AuthViewController.signIn()

  • 사용자의 입력 종료
  • 이메일, 비밀번호 입력 받은 데이터 검증
  • 디바이스의 이름 가져오기
  • 이름, 이메일, 비밀번호로 User 데이터 만들기
  • AuthController.signIn() 로그인 함수 호출

AuthController.signIn()

class func passwordHash(from email: String, password: String) -> String {
    let salt = "x4vV8bGgqqmQwgCoyXFQj+(o.nUNQhVP7ND"
    return "\(password).\(email).\(salt)".sha256()
  }
  • 입력받은 이메일과 비밀번호를 넘겨줘 AuthController.passwordHash()로 해싱
  • 키체인(Keychain)에서 앱의 데이터를 식별하는데 사용되는 서비스 이름을 상단에 정의
  • KeychainPasswordItem.savePassword()로 암호 키체인에 저장
  • UserDefaults에 현재 유저정보 저장

KeychainPasswordItem(service: serviceName, account: user.email).savePassword(finalHash)

  • 서비스 이름과 입력받은 이메일 그리고 해쉬값을 가지고 기존에 저장 되어있는 암호인지 검사 readPassword()
    • KeychainPasswordItem.keychainQuery()를 통해 쿼리생성
    • 쿼리를 실행해 비밀번호를 암호화 된 상태로 가져옴
    • 비밀번호가 있으면 입력받은 비밀번호의 암호화된 값를 가져옴
  • 새로 입력받은 비밀번호로 키체인 비밀번호 업데이트
  • 비밀번호가 없으면 새로운 아이템을 서비스 이름과 이메일 가지고 생성
  • 새로운 아이템에 비밀번호 저장

AuthController.isSignedIn

static var isSignedIn: Bool {
    // 1
    guard let currentUser = Settings.currentUser else {
      return false
    }
    
    do {
      // 2
      let password = try KeychainPasswordItem(service: serviceName, account: currentUser.email).readPassword()
      return password.count > 0
    } catch {
      return false
    }
  }

위의 코드를 추가하여 앱 컨트롤러에서 인증된 사용자인지 확인한다.

AppController.handleAuthState()

@objc func handleAuthState() {
    if AuthController.isSignedIn {
      rootViewController = NavigationController(rootViewController: FriendsViewController())
    } else {
      rootViewController = AuthViewController()
    }
  }

이제 handleAuthState()가 제대로 동작한다. 하지만 로그인 후 UI를 업데이트 해주기 위해서는 재시작을 해야한다. 이 방법은 불편하기 때문에, 인증과 같은 상태가 변경된 것을 앱에게 알려주는 좋은 방법은 알림(notifications)사용이다.

AuthController.signIn()

  • NotificationCenter.default.post(name: .loginStatusChanged, object: nil) 추

AppController.init()

init() {
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(handleAuthState),
      name: .loginStatusChanged,
      object: nil
    )
  }
  • AppController가 로그인 알림 옵져버로 등록. 알림이 발생할때 handleAuthState가 호출

AuthController.signOut()

  • 현재 유저정보를 확인
  • KeychainPasswordItem(service: serviceName, account: currentUser.email).deleteItem() 키체인에서 삭

FriendsViewController.signOut()

  • signOut기능 추가
@objc private func signOut() {
    // sign out
    try? AuthController.signOut()
  }
donaricano-btn

댓글

이 블로그의 인기 게시물

[IOS] AppDelegate는 뭐하는 녀석이지?

[git] Github 이슈 라벨(issue labels)

[git] git의 upstream과 origin 헷갈리는 사람 손!