Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

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

7 588 vues

Publié le

WKNavigationDelegate
 の - webView:didReceiveAuthenticationChallenge:completionHandler:

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

Publié dans : Mobile
  • Soyez le premier à commenter

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 翌日にお話します!

×