【问题标题】:iOS first app, accept untrusted certificate for hello worldiOS 第一个应用程序,接受 hello world 的不受信任的证书
【发布时间】:2016-02-14 01:50:39
【问题描述】:

我正在制作一个基本的“hello world”iOS 应用。我在云中有一个 ubuntu 服务器,我想从 iOS 应用程序中查询它。我了解服务器需要安全,即需要通过https请求访问,并且服务器上的证书需要“信任”。

现在我想做的是覆盖这个要求。我有一个自签名证书,适用于我的服务器上的 https。当我使用 iOS 应用程序发出请求时,它给了我一些关于 NSURLErrorFailingURLPeerTrustErrorKey 的错误,甚至返回一行:NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?

我知道这是一个常见问题,并且该网站上有很多关于如何处理它的帖子。我尝试了来自this post 的一段代码。我将这段代码添加到我的代码中:

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust{
            let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,credential);
        }
    }

我的整个 ViewController 代码都在这里:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate, NSURLSessionDelegate {
    // MARK: Properties
    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var mealNameLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Handle the text field’s user input through delegate callbacks.
        nameTextField.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: UITextFieldDelegate
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        // Hide the keyboard.
        textField.resignFirstResponder()
        return true
    }

    func textFieldDidEndEditing(textField: UITextField) {
        mealNameLabel.text = nameTextField.text
    }

    // MARK: Actions
    @IBAction func setDefaultLabelText(sender: UIButton) {
        mealNameLabel.text = "Default Text"
        post_request()
    }

    func post_request(){
        let request = NSMutableURLRequest(URL: NSURL(string: "https://54.164.XXX.XX/post_script.php")!)
        request.HTTPMethod = "POST"
        let postString = "id=13&name=Jack"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil {
                print("error=\(error)")
                return
            }

            print("response = \(response)")

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("responseString = \(responseString)")
        }
        task.resume()
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust{
            let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,credential);
        }
    }

}

看起来这个想法是从连接中获取challenge 事件,并告诉它“是的,我想继续”。但是那段代码似乎没有被调用。发布请求已发送,但我收到有关不受信任证书的错误消息。有人可以帮我修复我的代码,以便我可以从我的服务器接受此证书吗?

【问题讨论】:

  • 仅供参考,我最终只是购买了 SSL 证书,所有本机软件都可以完美地与任何解决方法配合使用。

标签: ios swift http-post


【解决方案1】:

您不能使用共享会话来获取这些委托方法。您必须实例化一个新的NSURLSession 并将自己声明为委托人。

// Delegate methods won't be callend
let task = NSURLSession.sharedSession()...

// Use this to get delegate calls
let task = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), 
                        delegate: self, 
                        delegateQueue: /* make a queue */)...

使用 iOS 9,您还需要查看 NSAppTransportSecurity 并将这些键添加到您的 plist。在 iOS 9 中需要这些以允许 SSL 连接。

【讨论】:

  • 我对代表的意思还是有新的理解。 /* 排个队 */.就像我的代码的上下文一样,我怎么能将数据发布到我的 IP、接受证书并获得响应?
  • Delegate 是一个实现某些方法的对象,一个对象会调用。在这种情况下,您说方法 func URLSession(_:task:didReceiveChallenge:completionHandler:) -> Void) 没有被调用。那是因为你不是代表。当您初始化该对象并将自己设置为委托时,该方法将被调用并接受证书,就像您拥有的代码一样。 make a queue 部分意味着创建一个后台队列。或者,如果您很懒惰,请使用NSOperationQueue.mainQueue()
【解决方案2】:

您需要让您的 ViewController NSURLSessionDelegate 接收回调并将会话的委托设置为您的控制器,如下所示:

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
...
let task = session.dataTaskWithRequest(request) { data, response, error in

}

task.resume()

【讨论】:

  • @keithbhunter 打败了我。应用程序传输安全性也是有用的评论
  • 我明白你在说什么,我正在努力理解。但是在您的回答中,它显示了如何接受证书并从服务器获取响应?
  • 我已经在这里用你的代码行创建了会话,但它仍然因为证书而拒绝连接
  • 您接受证书的部分:completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,credential)。像@keithbhunter 说的那样检查 AppTransportSecurity,如果证书无效,这可能会阻止应用程序工作
猜你喜欢
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 2019-05-20
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-13
相关资源
最近更新 更多