Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

iOS の通信における認証の種類とその取り扱い

6,517 views

Published on

WKNavigationDelegate
 の - webView:didReceiveAuthenticationChallenge:completionHandler:

 や、 NSURLSessionDelegate の
URLSession:didReceiveChallenge:completionHandler: 、
そして NSURLConnectionDelegate の - connection:didReceiveAuthenticationChallenge: (Deprecated) の取り扱いを解説します。
認証の種類は NSURLProtectionSpace Authentication Methods に定義されているので、これらの定義が何を表すか、そして認証時にデリゲートではそれぞれどのような手続きが必要か調べました。

Published in: Mobile
  • Be the first to comment

iOS の通信における認証の種類とその取り扱い

  1. 1. NSURLProtectionSpace Authentication Methods iOSにおける認証の種類とその取り扱い
  2. 2. @ niwatako
  3. 3. NSURLProtectionSpace Authentication Methods iOSにおける認証の種類とその取り扱い 一部調査段階の内容を含むので
 必要に応じて動作確認の上、ご利用ください 2016/03/05 yidev 第22回勉強会 : ATND https://atnd.org/events/74803 にて
 より詳細な内容で発表したいと思っています。
  4. 4. 認証を制御する通信周りの Delegate WKNavigationDelegate
 - webView:didReceiveAuthenticationChallenge:completionHandler:
 
 NSURLSessionDelegate - URLSession:didReceiveChallenge:completionHandler: NSURLConnectionDelegate - connection:didReceiveAuthenticationChallenge: (Deprecated)
  5. 5. Ops!
 (これはWKWebViewで認証が必要なページをロードした様子です) ちゃんと実装していないと中断して何も表示されない!
  6. 6. これらのDelegateの基本的な取り扱い方 WKNavigationDelegate
 - webView:didReceiveAuthenticationChallenge:completionHandler:
 
 NSURLSessionDelegate - URLSession:didReceiveChallenge:completionHandler: NSURLConnectionDelegate - connection:didReceiveAuthenticationChallenge: (Deprecated)
  7. 7. 認証に必要な認証情報を持った NSURLCredential を作って返す。 func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let credential: NSURLCredential /* credential = ... 適切な内容で NSURLCredential を作る */ completionHandler(.UseCredential, credential) }
  8. 8. NSURLCredential には、
 各種認証の種類に合わせて3つのイニシャライザが用意されている。 • - initWithUser:password:persistence:
 ユーザー名とパスワード • - initWithTrust:
 サーバー証明書 • - initWithIdentity:certificates:persistence:
 クライアント証明書
  9. 9. func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let credential: NSURLCredential /* credential = ... 適切な内容で NSURLCredential を作る */ completionHandler(.UseCredential, credential) } 認証の種類を確認して、

  10. 10. func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let credential: NSURLCredential /* credential = ... 適切な内容で NSURLCredential を作る */ completionHandler(.UseCredential, credential) } challenge.protectionSpace.authenticationMethod 認証の種類を確認して、

  11. 11. func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let credential: NSURLCredential /* credential = ... 適切な内容で NSURLCredential を作る */ completionHandler(.UseCredential, credential ) } challenge.protectionSpace.authenticationMethod 認証の種類を確認して、
 必要なNSURLCredential を作って返す。
  12. 12. NSURLProtectionSpace Authentication Methods 認証の種類がいっぱいあってわからん!
  13. 13. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String 全部チェックしてみます。
  14. 14. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String といいつつ
 一旦、1つ飛ばして 2つ目からご説明します
  15. 15. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String HTTPBasic
  16. 16. Basic認証
  17. 17. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String そして1つ目に戻ります
  18. 18. NSURLAuthenticationMethodDefault • その昔はBasic認証の時呼ばれたみたい • Basic認証は現在
 NSURLAuthenticationMethodHTTPBasic
 が呼ばれる • とつぜん
 NSURLAuthenticationMethodHTTPBasic
 が呼ばれるようになって困った人の悲鳴が観測された
  19. 19. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  20. 20. Digest認証 (Basic認証のセキュリティ強度少し強い版)
  21. 21. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  22. 22. NSURLAuthenticationMethodHTMLForm • HTMLForm認証なんて聞いたことない!と思ったら… • 通常のURLロードでは発生しないダミーの認証方式 • ユーザーカスタマイズ用 • 認証情報をNSURLCredentialStorageで管理して
 保存・取り出したい時用の分類
  23. 23. こういう機能を独自実装するとき用?
  24. 24. // 【A】カスタムの認証情報(例:ユーザー名とパスワード)を作成 let credential = NSURLCredential( user: "niwatako", password: "jellyfish", persistence: .ForSession ) // 【B】カスタム認証情報保存用の NSURLProtectionSpace (認証の掛かった通信先を表す) を作成 let HTMLFormSpace = NSURLProtectionSpace( host: "niwatako.tako", port: 443, `protocol`: "https", realm: nil, // realm... Digest認証などで必要、サーバー側のAuthNameにあたる authenticationMethod: NSURLAuthenticationMethodHTMLForm ) // CredentialStorage へ、【B】 に紐付ける形で【A】を保存 let credentialStorage = NSURLCredentialStorage.sharedCredentialStorage() credentialStorage.setCredential(credential, forProtectionSpace: HTMLFormSpace) /* —————————————————————————————————————————————————————————————————————————————— */ // CredentialStorage から、【B】 を指定して【A】を取り出し if let credentials = credentialStorage.credentialsForProtectionSpace(HTMLFormSpace) { for case let (username, credential) in credentials { print("(username)'s password is (credential.password ?? "NULL")") } } ※上記の方法でID情報を保存できるとしても、
  表示中のWebサイトのログイン情報の保存や自動入力は
  独自にWebサイトのフォームを解析して実装する必要がありそうです。
  25. 25. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  26. 26. Kerberos認証
  27. 27. NSURLAuthenticationMethodNegotiate • Windowsサーバの認証機能 • ユーザー名とパスワードの認証
  28. 28. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  29. 29. NSURLAuthenticationMethodNTLM • Windowsサーバの認証機能 • ユーザー名とパスワードの認証 • 堅牢性はKerberos認証に劣る
  30. 30. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  31. 31. クライアント認証
  32. 32. NSURLAuthenticationMethodClientCertificate • https:// のクライアント認証 • https の(相手の信頼性を確認し経路を暗号化する)通信は
 大抵、サーバーの証明書をクライアントがチェックするが
 これはクライアント側が証明書をインストールしておき、
 サーバーの方がクライアントの持つ証明書をチェックする
  33. 33. クライアント認証
 (iOSもメール等に証明書を添付すればインストールして使える)
  34. 34. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  35. 35. NSURLAuthenticationMethodServerTrust • よくある https:// から始まる SSL/TLS認証
 サーバーの証明書を確認し、安全性を確かめる • “ユーザー名&パスワード認証” 系と性質が異なり
 クライアント側が「サーバーは信頼できるか?」チェックする立場 • 認証失敗でも接続確立(強制的にサーバーを信頼)することは可能で、
 実際、続行して接続確立したい場合がある • 社内サーバー等の自己署名証明書
 (=信頼できる第三者機関発行でない証明書) • ドメインに証明書が発行されたサイトにIPで接続する時 • 証明書の有効期限切れ …etc
  36. 36. SSL/TLS認証 - 安全なサーバーに接続できた時
  37. 37. SSL/TLS認証 - サーバーの安全性を確認できなかった時
  38. 38. SSL/TLS認証 - サーバーの安全性を確認できなかった時 たとえ認証に失敗しても
 そのサーバーとの接続を確立するかどうかは
 クライアント側が決められる
  39. 39. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String コンプリートしました!
  40. 40. 整理すると?
  41. 41. 通信を行うクラスは
 通信時に発生した認証を取り扱うためのデリゲートを持つ WKNavigationDelegate
 - webView:didReceiveAuthenticationChallenge:completionHandler:
 
 NSURLSessionDelegate - URLSession:didReceiveChallenge:completionHandler: NSURLConnectionDelegate - connection:didReceiveAuthenticationChallenge: (Deprecated)
  42. 42. 認証時のデリゲートでは 必要な認証情報を持った NSURLCredential を作って返す func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let credential: NSURLCredential /* credential = ... 適切な内容で NSURLCredential を作る */ completionHandler(.UseCredential, credential) }
  43. 43. • - initWithUser:password:persistence:
 ユーザー名とパスワード • - initWithTrust:
 サーバー証明書 • - initWithIdentity:certificates:persistence:
 クライアント証明書 NSURLCredential には3種類のイニシャライザが有り、 必要な認証情報によって使い分ける
  44. 44. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String 認証の種類 (NSURLAuthenticationMethod) 毎の 必要になる認証情報は?
  45. 45. 4つに分けられますね!   let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String
  46. 46. 実際のURLリクエストでは発生しない、カスタマイズ用 let NSURLAuthenticationMethodHTMLForm: String let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String 除外 4つに分けられますね!
  47. 47. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String let NSURLAuthenticationMethodClientCertificate: String let NSURLAuthenticationMethodServerTrust: String NSURLCredential = 認証情報 どのタイプの認証情報を作ればよいのか? ユーザー名とパスワード クライアント証明書 サーバー証明書
  48. 48. completionHandler( .UseCredential, NSURLCredential( user: "niwatako", password: "password", persistence: .ForSession ) ) let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String ユーザー名とパスワード
  49. 49. let NSURLAuthenticationMethodDefault: String let NSURLAuthenticationMethodHTTPBasic: String let NSURLAuthenticationMethodHTTPDigest: String let NSURLAuthenticationMethodNegotiate: String let NSURLAuthenticationMethodNTLM: String 必要に応じてアラートで
 ユーザー名とパスワードの 入力を求めるなどする completionHandler( .UseCredential, NSURLCredential( user: "niwatako", password: "password", persistence: .ForSession ) ) ユーザー名とパスワード
  50. 50. let NSURLAuthenticationMethodClientCertificate: String クライアント証明書
  51. 51. let NSURLAuthenticationMethodClientCertificate: String これはまた別の機会に。。。 m(_ _ )m 検証用サーバー作っただけで終わりました クライアント証明書
  52. 52. let NSURLAuthenticationMethodServerTrust: String サーバー証明書
  53. 53. let NSURLAuthenticationMethodServerTrust: String completionHandler( .PerformDefaultHandling, nil ) サーバー証明書
  54. 54. let NSURLAuthenticationMethodServerTrust: String completionHandler( .PerformDefaultHandling, nil ) OSに任せることが出来る “PerformDefaultHandling”
 サーバー証明書に問題がない限りはこれで接続が確立可能 サーバー証明書
  55. 55. let NSURLAuthenticationMethodServerTrust: String 信頼されていない証明証でも
 アクセスしたい?
 (自己署名証明書を使いたい / IPで接続したい / 有効期限切れ etc) サーバー証明書
  56. 56. guard let serverTrust = challenge.protectionSpace.serverTrust else { // 証明書が取得できなかった時はデフォルト処理 completionHandler(.PerformDefaultHandling, nil) return } var result = SecTrustResultType(kSecTrustResultInvalid) let status: OSStatus = SecTrustEvaluate(serverTrust, &result); guard status == noErr && result == SecTrustResultType(kSecTrustResultRecoverableTrustFailure) else { // 検証自体に失敗した時か、 // 検証結果がkSecTrustResultRecoverableTrustFailure以外は // デフォルト処理 completionHandler(.PerformDefaultHandling, nil) return } /* kSecTrustResultRecoverableTrustFailure の時は
 サーバーの証明書から作った NSURLCredential を返すと強制的に信頼できる */ completionHandler( .UseCredential, NSURLCredential(forTrust: serverTrust) ) let NSURLAuthenticationMethodServerTrust: String サーバー証明書が認証失敗でも接続を続行 →ここはAlertを出してユーザーに確認したり →SecTrustEvaluate で自分で証明書を検証 →検証失敗、または正しい証明書、
 または強制的な接続続行が不可の時、Defaultに任せる
  57. 57. let NSURLAuthenticationMethodServerTrust: String let alert = UIAlertController( title: "Could not Verify Server Identity", message: "Trust?", preferredStyle: .Alert ) alert .addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (UIAlertAction) -> Void in completionHandler(.CancelAuthenticationChallenge, nil) })) alert .addAction(UIAlertAction(title: "Continue", style: .Cancel, handler: { (UIAlertAction) -> Void in completionHandler(.UseCredential, NSURLCredential(forTrust: serverTrust)) /* NSAppTransportSecurity > NSAllowsArbitraryLoads = YES */ }))
 self.presentViewController(alert, animated: true, completion: nil) →接続させない時は CancelAuthenticationChallenge 接続を続行するか確認するアラート
  58. 58. 5分ではこのくらいまで  🙇
  59. 59. まだお話すべきこと • ClientCertificateの使い方は? • 実際にサーバーを用意してテストしたい • NSURLSessionのデリゲートと適切な認証処理の箇所 • iOS8とiOS9で気をつけること
  60. 60. #yidev yidev 第22回勉強会 : ATND https://atnd.org/events/74803 try! Swift 翌日にお話します!

×