使用swift 3发送帖子请求(自签名证书问题)

时间:2017-02-06 00:18:38

标签: ios swift3

我正在尝试将用户将选择的一些数据发送到位于不同网络上的LAMP服务器上的mysql数据库。最近我在自己的机器上下载了一台服务器,一切都很好。应用程序中的操作发送到服务器中的php文件然后当然是php处理将其发送到mysql数据库。最近我被授权访问我们需要使用的服务器。现在当我尝试做同样的事情时,我得到一个错误,说该服务器的证书无效。我知道之前我正在处理http,现在它需要是https,但我不清楚我应该如何改变它以使其正常工作。我在这里看到了很多关于如何做到这一点的不同反应,但是他们经常被评论如“这是一种解决方法”或“应用程序可能被拒绝”等等。

这是我目前的职能:

func sendToServer(firstEntry: String, secondEntry: String, serverAddr: String){

let uid = firstEntry
let gender = secondEntry
let request = NSMutableURLRequest(url: NSURL(string: serverAddr)! as URL)
request.httpMethod = "POST"
let postString = "UID=\(uid)&Gender=\(gender)"
request.httpBody = postString.data(using: String.Encoding.utf8)

let task = URLSession.shared.dataTask(with: request as URLRequest) {
    data, response, error in

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

    print("response = \(response)")

    let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
    print("responseString = \(responseString)")
}
task.resume()

}

我读过诸如此处不使用共享以使其工作的事情,但我仍然不太清楚这一点。我想要做的就是将这些数据发送到位于服务器上的php。数据本身不敏感,只是简单的性别,是或否答案被发送到数据库。但是,在没有影响用户体验的攻击以及因此不会被拒绝的情况下,我需要这样做足够安全。这里的任何帮助将不胜感激。谢谢

3 个答案:

答案 0 :(得分:5)

你需要做两件事:

  1. 将域异常添加到plist文件中,我将引荐您访问此stackoverflow帖子How do I load an HTTP URL with App Transport Security enabled in iOS 9?

  2. 您需要实现您的URLSessionDelegate。这一种方法是您的https请求的最低要求。您将在URLSessionTaskDelegate上找到几乎精确的方法,该方法用于特定于任务的身份验证,此方法用于会话范围身份验证。从代码中可以看出,关键部分是URLCredential(trust:challenge.protectionSpace.serverTrust!),您可以在其中指定您信任该服务器。

    class RequestDelegate: NSObject, URLSessionDelegate {

    public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
        completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
    }
    

    }

  3. 然后你只需将URLSession(configuration: URLSessionConfiguration.default, delegate: RequestDelegate(), delegateQueue: nil)作为参数作为参数

    对IOS 10进行了测试和处理。

    希望这会有所帮助,这实际上是我在stackoverflow上的第一篇文章,所以Hello World。

答案 1 :(得分:1)

我拥有所有这些(称为SSL Pinning)......

// MARK: URL session delegate
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    //Implementation 1: VERY WEAK METHOD
    /*if challenge.previousFailureCount > 0{
     completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
     }else{
     completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
     }*/

    //Implementation 2:
    var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
    var credential:URLCredential?

    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        //certificate-based server credentials are used when verifying the server’s identity
        credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)

        if (credential != nil) {
            disposition = URLSession.AuthChallengeDisposition.useCredential
        }
        else{
            disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
        }
    }
    else{
        disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
    }
    print("==============",#file.getClass()," ", #function,"  disposition: ", disposition)
    print("==============",#file.getClass()," ", #function,"  disposition: ", credential!)

    //completionHandler(disposition, credential);




    //Implementation 3:
    let serverTrust = challenge.protectionSpace.serverTrust
    let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)

    // Set SSL policies for domain name check
    let policies = NSMutableArray();
    policies.add(SecPolicyCreateSSL(true, (challenge.protectionSpace.host as CFString)))
    SecTrustSetPolicies(serverTrust!, policies);

    // Evaluate server certificate
    var result = SecTrustResultType(rawValue: 0)!
    SecTrustEvaluate(serverTrust!, &result)

    let isServerTrusted:Bool = (result == SecTrustResultType.unspecified || result == SecTrustResultType.unspecified || result == SecTrustResultType.proceed)
    print("==============",#file.getClass()," ", #function,"  isServerTrusted: ", isServerTrusted)
    print("==============",#file.getClass()," ", #function,"  result: ", result.hashValue,"  SecTrustResultType.unspecified: ", SecTrustResultType.unspecified.hashValue,"  SecTrustResultType.proceed: ", SecTrustResultType.proceed.hashValue)
    var certName = ""
    if self.isSimulatingCertificateCorruption {
        certName = corruptedCert
    } else {
        certName = cert
    }

    // Get local and remote cert data
    let remoteCertificateData = SecCertificateCopyData(certificate!) as Data
    let pathToCert            = Bundle.main.path(forResource: certName, ofType: "der")
    let localCertificate      = try! Data(contentsOf: URL(fileURLWithPath: pathToCert!))
    print(" remoteCertificateData: ", remoteCertificateData,"       localCertificate: ", localCertificate, "       serverTrust: ", serverTrust.debugDescription  )

    if ( remoteCertificateData == localCertificate) { //TODO:- this is strictly for tesing puposes, to allow untrusted severs. REMOVE IN PRODUCTION.
        let credential:URLCredential = URLCredential(trust: serverTrust!)
        completionHandler(.useCredential, credential)
    }else if (isServerTrusted && (remoteCertificateData == localCertificate)) {
        let credential:URLCredential = URLCredential(trust: serverTrust!)
        completionHandler(.useCredential, credential)
    } else {
        completionHandler(.cancelAuthenticationChallenge, nil)
    }
}

如果有必要,会解释更多。 该函数应该在带有URLSession的Class中。该类应扩展URLSessionDelegate。

答案 2 :(得分:0)

self.isSimulatingCertificateCorruption实现丢失。