質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

1回答

5043閲覧

WKWebViewの表示について(SSL認証)

qwerty1

総合スコア6

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2016/12/22 10:17

###前提・実現したいこと
p12ファイルを利用して認証が必要なサイトをWKWebViewで表示をさせたく
いろいろなサイトを調べてみましたが、以下のようにBad Requestエラーが発生しています。

原因が全くわかっておらず、「こういう所を確認したのか?」などの
ヒントとなるような情報でも構いませんのでコメントよろしくお願い致します。

情報が不足していたら、その点も指摘して頂ければと思います。

###発生している問題・エラーメッセージ
WKWebView上では下記のエラーメッセージが表示されています。
[400 Bad Request No required SSL certificate was sent]
XCode上にはエラーログはありませんでした。

###該当のソースコード
【info.plist】(一部抜粋)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>XXX.YYY.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

【ViewController.swift】
import UIKit
import WebKit

class ViewController: UIViewController , WKNavigationDelegate {
var webView: WKWebView!
// 接続先URL
let URL_TEST : String = "https://XXX.YYY.com/"

override func viewDidLoad() { super.viewDidLoad() self.webView = WKWebView(frame: self.view.frame) self.webView.navigationDelegate = self self.view.addSubview(webView) self.loadWebView() } func loadWebView() { // 接続先のURL let url = NSURL(string: URL_TEST) // 認証するためのURL let request = NSMutableURLRequest(URL: url!) // webViewのロードを開始 self.webView.loadRequest(request) } // MARK: - WKNavigationDelegate methods func webView(webView: WKWebView, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { let challengeStr : NSString = challenge.protectionSpace.authenticationMethod if challengeStr == (NSURLAuthenticationMethodServerTrust) { let urlCredential:NSURLCredential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!) completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential); } else if challengeStr == NSURLAuthenticationMethodClientCertificate{ let identityAndTrust:IdentityAndTrust = self.extractIdentity(); let urlCredential:NSURLCredential = NSURLCredential( identity: identityAndTrust.identityRef, certificates: identityAndTrust.certArray as? [AnyObject], persistence: NSURLCredentialPersistence.ForSession); completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential); } } /** * 読み込み開始時 */ func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation) { print("webView:(webView) didStartProvisionalNavigation:(navigation)") } // MARK: - p12ファイル関連 struct IdentityAndTrust { var identityRef:SecIdentityRef var trust:SecTrustRef var certArray:AnyObject } func extractIdentity() -> IdentityAndTrust { var identityAndTrust:IdentityAndTrust! var securityError:OSStatus = errSecSuccess // p12ファイル作成 let path: String = NSBundle.mainBundle().pathForResource("XXXXXXXXXX", ofType: "p12")! let PKCS12Data = NSData(contentsOfFile:path)! let key : NSString = kSecImportExportPassphrase as NSString let options : NSDictionary = [key : "password"] var items : CFArray? securityError = SecPKCS12Import(PKCS12Data, options, &items) if securityError == errSecSuccess { print(" --- p12ファイルの読み込み成功 --- ") let certItems:CFArray = items as CFArray!; let certItemsArray:Array = certItems as Array let dict:AnyObject? = certItemsArray.first; if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> { // grab the identity let identityPointer:AnyObject? = certEntry["identity"]; let secIdentityRef:SecIdentityRef = identityPointer as! SecIdentityRef!; // grab the trust let trustPointer:AnyObject? = certEntry["trust"]; let trustRef:SecTrustRef = trustPointer as! SecTrustRef; // grab the cert let chainPointer:AnyObject? = certEntry["chain"]; identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!); } } else { print(" --- p12ファイルの読み込み失敗 --- ") } return identityAndTrust; }

}

###試したこと
Bad Requestが発生している事からp12ファイルの設定や読み込み周りを調査してみましたが、解決には至ってはおりません。

また処理の流れをデバッグで確認してみたところ、
WKWebViewをloadRequestした後に認証のdelegateメソッド(didReceiveAuthenticationChallenge)が実行されたいたので、
didStartProvisionalNavigation にて、再度表示を試してみたのですが、問題は解消されませんでした。

NSURLSessionでの疎通確認は取れています。

###補足情報(言語/FW/ツール等のバージョンなど)
XCode 8.1
Swift 2
iOS9, iOS10
WebKit.framework追加済み

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

直接関係あるか分かりませんが、接続先がATSに対応しているかを確認してみてはいかがでしょうか?

接続先がATS (App Transport Security)に対応しているか、または例外の設定をnscurlコマンドで簡単に調べる

NSURLSessionでの疎通確認は取れています。

と書かれていますが、こちらはどのようなコードでアクセスの確認をしたのでしょうか?
そちらでも認証の様な処理をしているのですか?

投稿2016/12/25 00:39

_Kentarou

総合スコア8490

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

qwerty1

2016/12/26 04:08

ご回答ありがとうございます。 回答頂いた内容に対しての返信と、調査事項を追記します。 回答に対する返信 >> 接続先がATSに対応しているかを確認してみてはいかがでしょうか? nscurl --ats-diagnostics --verbose https://XXX.YYY.com/ にて調査した結果、接続先はATSに対応はしていませんでした。 クライアント側の設定でATSの設定をOFFにしているので、問題は無いと考えています。 もし違うようであれば、ご指摘ください。 ちなみに、NSAllowsArbitraryLoadsをtrueに設定しても同じ現象が発生しました。 >>NSURLSessionでの疎通確認は取れています。 >と書かれていますが、こちらはどのようなコードでアクセスの確認をしたのでしょうか? >そちらでも認証の様な処理をしているのですか? 下記のコードにてresponseのstatusCodeが200で返却されているのを確認済みです。 class ViewController: UIViewController , WKNavigationDelegate , NSURLSessionDelegate{ // 接続先URL let URL_TEST : String = "https://XXX.YYY.com/" override func viewDidLoad() { super.viewDidLoad() // 通信用のConfigを生成. let config = NSURLSessionConfiguration.defaultSessionConfiguration() // Sessionを生成. let session: NSURLSession = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) // 通信先のURLを生成. let testUrl = NSURL(string: URL_TEST) let request: NSMutableURLRequest = NSMutableURLRequest(URL: testUrl!) // check command : nscurl --ats-diagnostics let dataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) -> Void in if error != nil{ print(" --- Serverへの接続に失敗しました --- ") print(error?.code) print(error?.description) }else{ print(" --- Serverへの接続に成功しました --- ") let str = NSString(data: data!, encoding: NSShiftJISStringEncoding) // let str = NSString(data: data!, encoding: NSUTF8StringEncoding) print(str) print(data) } }) as NSURLSessionTask dataTask.resume() } /* * 認証が必要なサイトにアクセスした場合に実施される。 **/ func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { print("didReceiveChallenge") if challenge.protectionSpace.authenticationMethod == (NSURLAuthenticationMethodServerTrust) { print(".cer形式 認証実施(NSURLSession)") let urlCredential:NSURLCredential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!) completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential); } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate{ print(".p12形式 認証実施(NSURLSession)") let identityAndTrust:IdentityAndTrust = self.extractIdentity(); let urlCredential:NSURLCredential = NSURLCredential( identity: identityAndTrust.identityRef, certificates: identityAndTrust.certArray as? [AnyObject], persistence: NSURLCredentialPersistence.ForSession); completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, urlCredential); } } } ※IdentityAndTrustとextractIdentityは初回投稿時と同じです。 追記事項 ■ didFailProvisionalNavigationのエラーメッセージについて 下記のエラーメッセージが表示されていました。 —————————————————————— didFailProvisionalNavigation:<WKNavigation: 0x7fc0eaa126e0> withError:Error Domain=NSPOSIXErrorDomain Code=54 "Connection reset by peer" UserInfo={_WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x60800003f940>, _kCFStreamErrorCodeKey=54, _kCFStreamErrorDomainKey=1} —————————————————————— こちらのメッセージは調査中です。 ■プロパティ(certificateChain)について WKWebViewのプロパティに証明書の情報を保持する配列があるようですが、確認出来ていません。 @property (nonatomic, readonly, copy) NSArray *certificateChain —————————————————————— (lldb) po self.webView.certificateChain 0 elements —————————————————————— ■ NSAllowsArbitraryLoadsInWebContentのバグについて (今回の問題とは直接関係はありませんが、参考まで) 調査中、下記のサイトでのバグに該当するかと思いましたが、違いました。 【Apple iOS ATS】一部サイトではPV減も。NSAllowsArbitraryLoads とその InWebContent は違う件。 http://niwatako.hatenablog.jp/entry/2016/12/12/210026 iOS10からの設定項目[NSAllowsArbitraryLoadsInWebContent]の設定をしているにも関わらず ATS未対応のサイトを表示出来ないようです。 但し、NSAllowsArbitraryLoadsを設定していれば、表示出来るとの事です。 問題解決には至っておりませんが、引き続きよろしくお願い致します。
_Kentarou

2016/12/26 04:22 編集

> 接続先はATSに対応はしていませんでした。 これが原因かもしれません、、、iPhone側でATSを全部許可にしていてもサーバーが対応していなくて通信できないという事が自分も有りました。 今後のことも考えてサーバーをちゃんと通信できるようにするのが良いと思います。
qwerty1

2016/12/26 05:31

素早い回答ありがとうございます。 サーバ側の設定はすぐに対応出来ない為、確認が出来ないのですが 設定を変更するように対応方針を変えてみます。 色々と情報ありがとうございました。
_xi_

2018/01/30 09:47

https://forums.developer.apple.com/thread/67651 上記の記事にもURLSessionを用いてp12認証は通るが、 WKWebViewを使用した場合は上手くいかないようなことが記載されていました。 また、記事内でappleスタッフがWKWwebViewを用いたクライアント認証の動作に問題があって、 正常に動作しないような事を書いていました。 今回の内容に当てはまるかは分かりませんが、ご参考になればと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問