How do I perform an insecure URLSession query in iOS - ios

I'm trying to perform a query to a website that I run. However, currently, this website's certificate is invalid (for a valid reason for now).
I'm trying to query it with this code:
private static func performQuery(_ urlString: String) {
guard let url = URL(string: urlString) else {
return
}
print(url)
URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else {
return
}
do {
let productDetails = try JSONDecoder().decode([ProductDetails].self, from: data)
DispatchQueue.main.async {
print(productDetails)
}
} catch let jsonError {
print(jsonError)
}
}.resume()
}
However, I get:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
The certificate for this server is invalid. You might be connecting to a server that is pretending to be “mydomain.com” which could put your confidential information at risk.
How can I make an insecure URLSession query (equivalent to -k in CURL)?
I've tried setting these:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>mydomain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
And yes I don't intend to release this to the App Store with insecure access, but I need to get the code tested and right now we can't get a valid certificate, so this is purely for development purposes.

First, set the delegate of the session to your class which conforms to URLSessionDelegate like :
let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue.main)
Add the implementation of didReceiveChallenge method in your class which conforms to URLSessionDelegate protocol
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
This will allow insecure connection by trusting the server.
WARNING : DO NOT use this code in production apps, this is a potential security risk.

Try these exceptions:
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>

Related

System.Net.WebException: An SSL error has occurred and a secure connection to the server cannot be made

Already found the same thread here, but that not resolved my problem.
I have added NSAppTransportSecurity and NSAllowsArbitraryLoads in info.plist.
Screenshot:
Added the below codes from this article.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>pm-admin.smartwcm.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowInsecureHTTPSLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
<key>NSThirdPartyExceptionAllowInsecureHTTPSLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
</dict>
</dict>
</dict>
I am using HTTP REST APIs. When running the project I am getting the following exception:
System.Net.WebException: An SSL error has occurred and a secure connection to the server cannot be made. ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?
Am I missing something or do anything wrong?
Cause: Since iOS 9, iOS will only allow your application to communicate with servers that implement best-practice security by default. Values must be set in Info.plist to enable communication with insecure servers.It seems that you only AllowInsecureHTTPSLoads but forget to add AllowsInsecureHTTPLoads
Solution: Add the following code in your info.plist to trust your domain.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>pm-admin.smartwcm.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
......
</dict>
</dict>
Here is a similar issue that you can refer.
Because you must to use certificate.
class ViewController: UIViewController, URLSessionDelegate,URLSessionTaskDelegate {
var urlSession: Foundation.URLSession!
override func viewDidLoad() {
super.viewDidLoad()
urlSession = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let serverTrust = challenge.protectionSpace.serverTrust
let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)
let policies = NSMutableArray();
policies.add(SecPolicyCreateSSL(true, (challenge.protectionSpace.host as CFString)))
SecTrustSetPolicies(serverTrust!, policies);
var result: SecTrustResultType = SecTrustResultType(rawValue: 0)!
SecTrustEvaluate(serverTrust!, &result)
let isServerTrusted:Bool = (result == SecTrustResultType.unspecified || result == SecTrustResultType.proceed)
let remoteCertificateData:NSData = SecCertificateCopyData(certificate!)
let pathToCert = Bundle.main.path(forResource: "certificateName", ofType: "crt")
let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!
let credential:URLCredential = URLCredential(trust: serverTrust!)
completionHandler(.useCredential, credential)
}
}

Swift - AVPlayer load failed with error Error Domain=NSURLErrorDomain Code=-999 "cancelled"

I try to play a video from url string. But I have get some error as question title.
I try this code in below. videoPath is a url string.
let videoURL = URL(string: videoPath)
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
Below is error log :
load failed with error Error Domain=NSURLErrorDomain Code=-999
"cancelled" UserInfo={NSErrorFailingURLStringKey=http://b...a.mp4,
NSErrorFailingURLKey=http://b...a.mp4,
_NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <841B2FFA-479B-4E5A-9BD3-D9207EAA0D32>.<2>" ), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <841B2FFA-479B-4E5A-9BD3-D9207EAA0D32>.<2>,
NSLocalizedDescription=cancelled} [-999]
I set the info.plist --
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>www.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
NOTE: The problem is occured with 10 minutes longer videos. Is it a normal ?
Are you trying to present the AVPlayerViewController inside viewDidLoad? If so you could try presenting it after the view controller's view is added to the window hierarchy - viewDidAppear for example. Keep in mind that viewDidAppear will be called when you navigate back to the controller and the modal presentation will be triggered again.
Does the URL require cookies to be set ? I faced the same issue with missing cookies.
You can check by trying to open the url in an incognito-window. If it still plays fine then perhaps you can debug this by -
Creating an AVURLAsset object with the URL eg -
AVURLAsset(url: <URL>, options:[]) and set the resourceLoader delegate to self.
Like urlAsset?.resourceLoader.setDelegate(self, queue: .main)
and implement the functions
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
return true
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForRenewalOfRequestedResource renewalRequest: AVAssetResourceRenewalRequest) -> Bool {
return true
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel loadingRequest: AVAssetResourceLoadingRequest) {
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForResponseTo authenticationChallenge: URLAuthenticationChallenge) -> Bool {
return true
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel authenticationChallenge: URLAuthenticationChallenge) {
}
But if it does require cookies - Set them in the AVURLAsset object eg
let asset = AVURLAsset(url: videoURL, options: ["AVURLAssetHTTPHeaderFieldsKey": ["Cookie": "<YOUR TOKEN>"]])
The reason could be wrong metadata in the video. Take a look at this thread which I answered: AVPlayer HLS live stream IOS
The transcoded video needs to have profile baseline in order to be played in AVPlayer. Take look at the ffmpeg transcoding command for details:
https://gist.github.com/chung-nguyen/d88e73e3cc8788878f5ffb8c232b4729
NSErrorFailingURLKey=http://b...a.mp4
The url with "http" prefix always fails irrespective of what ATS you have.
please visit my answer here

iOS video not playing (play button crossed out)

I'm trying to play a video from URL, but when I run the code, all I can see is the play button crossed out.
here is the code:
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
#IBAction func playVideo(_ sender: Any) {
let videoURL = URL(string: "http://techslides.com/demos/sample-videos/small.mp4")
let player = AVPlayer(url: videoURL!)
let playerControler = AVPlayerViewController()
playerControler.player = player
present(playerControler, animated: true) {
player.play()
}
}
Xcode 9.1
Swift 4
Any idea what is wrong?
You need to edit your .plist file to be able to get video by given http URL
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
Add this code to your .plist xml, or simply try to load https: video:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>

Code will run in playground, but fails when executed in application simulator

I am attempting to get the HTML of a URL with the NSURL function. The code runs well and the HTML is properly returned when executed from the playground, however when I implement it into a button from the storyboard the app crashes. I changed the App Transport Security in the Info.plist file, however I am still encountering a crash. Here is my Info.plist: http://imgur.com/a/BB3KF. The error message also says that there is a nil value, however I have tested the variables in the function and everything seems to be != nil.
Playground code:
let myUrl = NSURL(string: "http://www.google.com")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
self.testLabel.text = "\(responseString)"
if error != nil {
print("Error: \(error)")
}
}
task.resume()
XCode code:
import UIKit
import Foundation
class ViewController: UIViewController {
#IBOutlet weak var testLabel: UILabel!
#IBAction func testButton(sender: UIButton) {
let myUrl = NSURL(string: "http://www.google.com")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
self.testLabel.text = "\(responseString)"
if error != nil {
print("Error: \(error)")
}
}
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Error message:
2015-10-29 10:20:36.127 testProject[1263:49414] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
The error occurs because iOS9 connections to the servers must be secure (https ) to allow the use of http add the following into info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
You need to set the NSAppTransportSecurity value in info.plist as the following:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
change localhost to your actual server
App Transport Security has blocked a cleartext HTTP resource

UIWebView Issue in Swift [duplicate]

This question already has answers here:
How do I load an HTTP URL with App Transport Security enabled in iOS 9? [duplicate]
(8 answers)
Closed 7 years ago.
My UIWebView will not load and I am extremely confused why.The webview was working a few weeks ago. The site that it linked to got updated. But for some reason now any link I send to it doesn't work. I tried clearing the cache. I am a little lost to why this wont appear. Internet on my phone works fine. Everything in the storyboard is connected properly.
The activity indicator keeps spinning. And my alert comes up from the didFailLoadWithError, which is supposed to happen, but it would be nice to figure out why it won't connect.. Any help would be great, thank you.
class CommunityViewController: UIViewController, UIWebViewDelegate {
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var communityWeb: UIWebView!
var refreshControl:UIRefreshControl!
let url = "http://www.google.com"
override func viewWillAppear(animated: Bool) {
NSURLCache.sharedURLCache().removeAllCachedResponses()
NSURLCache.sharedURLCache().diskCapacity = 0
NSURLCache.sharedURLCache().memoryCapacity = 0
}
override func viewDidLoad() {
super.viewDidLoad()
self.communityWeb.delegate = self
let requestURL = NSURL(string:url)
let request = NSURLRequest(URL: requestURL!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 3.0)
communityWeb.loadRequest(request)
self.refreshControl = UIRefreshControl()
self.refreshControl.attributedTitle = NSAttributedString(string: "")
self.refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.communityWeb.scrollView.addSubview(refreshControl)
}
func refresh(sender:AnyObject)
{
let requestURL = NSURL(string:url)
let request = NSURLRequest(URL: requestURL!)
communityWeb.loadRequest(request)
refreshControl.endRefreshing()
}
func webViewDidStartLoad(webView: UIWebView) // here show your indicator
{
self.activityIndicator.startAnimating()
}
func webViewDidFinishLoad(webView: UIWebView) {
self.activityIndicator.stopAnimating()
self.activityIndicator.hidesWhenStopped = true
self.communityWeb.scrollView.contentSize.width = self.communityWeb.frame.size.width
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {
let alertView = SIAlertView(title: "Internet Connection", andMessage: "Connect to the internet to receive latest updates from the Community")
alertView.addButtonWithTitle("OK", type: SIAlertViewButtonType.Default, handler:
{alertView in
NSLog("pressed")
})
alertView.transitionStyle = SIAlertViewTransitionStyle.Fade
alertView.show()
}
I think you forgot to update your info.plist file.
Add this key into your file:
The lazy option is:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Or you can directly add that into your info.plist and it will look like:
And you can add a specific domain like:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourserver.com</key>
<dict>
<!--Include to allow subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--Include to allow HTTP requests-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!--Include to specify minimum TLS version-->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>

Resources