Friday, July 21, 2017

SSL pinning in iOS Swift code



SSL (Secure Socket Layer) pinning is used to prevent Man In The Middle attack.
This is generally used for secure end-to-end communication. Most the apps that requires secure communication such as Banking apps uses this mechanism.

You can implement this using Alamofire as below:

1. Ask Middleware team to implement SSL certificate on Server
2. They will give you .crt file
3. Now, convert this .crt file to .der online using https://www.sslshopper.com/ssl-converter.html
4. Add this .der file to your Xcode (Make sure that you checkmark copy items if needed on dialog box)
5. Now use below code for SSL Pinning in file where you make service calls:

var serverTrustPolicy:ServerTrustPolicy?
var serverTrustPolicies:[String: ServerTrustPolicy]?
var afManager: Alamofire.SessionManager?

if self.configureAlamoFireSSLPinning() == false {
            DispatchQueue.main.async() {
                let alert = UIAlertView(title: "", message: sslConfigurationError, delegate: nil, cancelButtonTitle: "OK")
                alert.show()                
            }
            return
        }


func configureAlamoFireSSLPinning() -> Bool {
        let githubCert = “APPNAME.COMPANYNAME.COM" // This name would be same as that of .der file
        let pathToCert = Bundle.main.path(forResource: githubCert, ofType: "der")
        let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!
        
        self.serverTrustPolicy = ServerTrustPolicy.pinCertificates(
            certificates: [SecCertificateCreateWithData(nil, localCertificate)!],
            validateCertificateChain: true,
            validateHost: true
        )
        
        self.serverTrustPolicies = [
            "github.com": self.serverTrustPolicy!
        ]
        
        let objConfiguration = URLSessionConfiguration.default
        objConfiguration.timeoutIntervalForResource = 600.0
        objConfiguration.timeoutIntervalForRequest = 30.0
        objConfiguration.urlCache = nil // Clear app cache
        
        self.afManager = Alamofire.SessionManager (
            configuration: objConfiguration,
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: self.serverTrustPolicies!)
        )
        
        if self.afManager == nil {
            return false
        }
        
         return true
    }


6. Now make sure that you change the endpoint to https://

Wednesday, March 8, 2017

How to fetch IP address in Swift 3

You can fetch IP address using below code :
Note : I’ve used reachability so that it captures new IP address in case WiFi is changed to another

1. Podfile file  pod 'ReachabilitySwift' and then install pod

2. AppDelegate.swift file import ReachabilitySwift 
Note : If it prompts an error that Could not find ReachabilitySwift module then simply copy and paste this. It works!

3. didFinishLaunchingOptions function :

// Register to receive notification
        NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
        
        do{
            try reachability.startNotifier()
        }
        catch {
            print("could not start reachability notifier")
        }

4. Then copy paste below code in AppDelegate file 

func reachabilityChanged(note: NSNotification) {
        
        let reachability = note.object as! Reachability
        
        if reachability.isReachable {
            if reachability.isReachableViaWiFi {
                print("Reachable via WiFi")
            } else {
                print("Reachable via Cellular")
            }
            
            setIPAddress()
        } else {
            ipAddress = "" // No IP captures
            print("Network not reachable")
        }
    }
    
    func setIPAddress() {
        if let addr = self.getWiFiAddress() {
            print("ipAddress : \(addr)")
            ipAddress = addr
        } else {
            ipAddress = "" // No IP captures
            print("No WiFi address")
        }
    }
    
    // Return IP address of WiFi interface (en0) as a String, or `nil`
    func getWiFiAddress() -> String? {
        var address : String?
        
        // Get list of all interfaces on the local machine:
        var ifaddr : UnsafeMutablePointer<ifaddrs>?
        guard getifaddrs(&ifaddr) == 0 else { return nil }
        guard let firstAddr = ifaddr else { return nil }
        
        // For each interface ...
        for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
            let interface = ifptr.pointee
            
            // Check for IPv4 or IPv6 interface:
            let addrFamily = interface.ifa_addr.pointee.sa_family
            if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
                
                // Check interface name:
                let name = String(cString: interface.ifa_name)
                if  name == "en0" {
                    
                    // Convert interface address to a human readable string:
                    var addr = interface.ifa_addr.pointee
                    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                    getnameinfo(&addr, socklen_t(interface.ifa_addr.pointee.sa_len),
                                &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST)
                    address = String(cString: hostname)
                }
            }
        }
        freeifaddrs(ifaddr)
        
        return address
    }

5. Add this in Bridging-Header file 
#include <ifaddrs.h>

In case you don’t have this file then you can create it http://stackoverflow.com/a/37295090/1753005

6.
func applicationWillEnterForeground(_ application: UIApplication) {
        // Post notification
        NotificationCenter.default.post(name: ReachabilityChangedNotification, object: reachability)
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

7. Use this to remove observer

//Stop Reachability Notifier
         reachability.stopNotifier()

         NSNotificationCenter.defaultCenter().removeObserver(self,name: ReachabilityChangedNotification,object: reachability)