Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to add SSL Certificate pinning in Parse Configuration (Parse SDK iOS) #1587

Open
amitpristyn opened this issue Dec 29, 2020 · 10 comments
Open
Labels
type:feature New feature or improvement of existing feature

Comments

@amitpristyn
Copy link

There is no option to add certificate pinning and verify can you please help

@amitpristyn amitpristyn changed the title How to add SSL Certificate pinning in PARSE SDK How to add SSL Certificate pinning in Parse Configuration Dec 29, 2020
@amitpristyn amitpristyn changed the title How to add SSL Certificate pinning in Parse Configuration How to add SSL Certificate pinning in Parse Configuration (Parse SDK iOS) Dec 29, 2020
@amitpristyn amitpristyn reopened this Dec 29, 2020
@cbaker6
Copy link
Contributor

cbaker6 commented Jan 4, 2021

This type of functionality could be added if you want to take on the task. My initial thoughts are you conform to the didReceiveChallenge delegate method here:

///--------------------------------------
#pragma mark - NSURLSessionDataDelegate
///--------------------------------------
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {
completionHandler(nil); // Prevent any caching for security reasons
}

Then you need to pass the completionHandler block back through the SDK and expose it to the developer (like some of the other delegates are doing). The developer should handle the challenge, save certs through the Keychain, etc. They simply complete the handler with their desired choice.

@cbaker6 cbaker6 added Enhancement type:feature New feature or improvement of existing feature labels Jan 4, 2021
@amitpristyn
Copy link
Author

amitpristyn commented Jan 5, 2021

This type of functionality could be added if you want to take on the task. My initial thoughts are you conform to the didReceiveChallenge delegate method here:

///--------------------------------------
#pragma mark - NSURLSessionDataDelegate
///--------------------------------------
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
PFURLSessionDataTaskDelegate *delegate = [self _taskDelegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {
completionHandler(nil); // Prevent any caching for security reasons
}

Then you need to pass the completionHandler block back through the SDK and expose it to the developer (like some of the other delegates are doing). The developer should handle the challenge, save certs through the Keychain, etc. They simply complete the handler with their desired choice.

I don't know where I use this

please check my code given below

 class func setParserClientConfigAndInit() {
        
//        let session = URLSession(
//        configuration: URLSessionConfiguration.ephemeral,
//        delegate: URLSessionPinningDelegate(),
//        delegateQueue: nil)
        
        let configuration = ParseClientConfiguration {
            $0.applicationId = KAPI.applicationId
            $0.clientKey = ""
            $0.server = KAPI.applicationServer
            $0.urlSessionConfiguration.httpAdditionalHeaders = setParseHeader()
            #if DEBUG
            // not used
            #else
//            $0.urlSessionConfiguration = session.configuration
            #endif
        }
        
        //Parse initilize
        Parse.initialize(with: configuration)
        
    }

I don't know where I pass or where I use it on the given

    class NSURLSessionPinningDelegate: NSObject, URLSessionDelegate {

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {

        // Adapted from OWASP https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS

        if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
            if let serverTrust = challenge.protectionSpace.serverTrust {
                let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil)

                if(isServerTrusted) {
                    if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
                        let serverCertificateData = SecCertificateCopyData(serverCertificate)
                        let data = CFDataGetBytePtr(serverCertificateData);
                        let size = CFDataGetLength(serverCertificateData);
                        let cert1 = NSData(bytes: data, length: size)
                        let file_der = Bundle.main.path(forResource: "certificateFile", ofType: "der")

                        if let file = file_der {
                            if let cert2 = NSData(contentsOfFile: file) {
                                if cert1.isEqual(to: cert2 as Data) {
                                    completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust))
                                    return
                                }
                            }
                        }
                    }
                }
            }
        }

        // Pinning failed
        completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
    }

}

@cbaker6
Copy link
Contributor

cbaker6 commented Jan 5, 2021

You have the right idea, but the code you listed is what you would use as a developer. You need to open a PR, add the delegate method I mentioned and add the new configuration parameter. You can use what I did in ParseSwift as a reference https://github.com/parse-community/Parse-Swift/pull/45/files Though the structure is different.

@cbaker6
Copy link
Contributor

cbaker6 commented Jan 5, 2021

You will also need to do more If you want to pass in your own headers. You won't be able to use your own delegate because Parse already has one. You should only need to respond to the challenge and maybe pass in headers which can be two different parameters that can be passed into the config assuming you add the capability to the SDK.

@amitpristyn
Copy link
Author

You will also need to do more If you want to pass in your own headers. You won't be able to use your own delegate because Parse already has one. You should only need to respond to the challenge and maybe pass in headers which can be two different parameters that can be passed into the config assuming you add the capability to the SDK.

Any method to add SSL pinning certificate in parse request and response handle like an error in parse query

@amitpristyn
Copy link
Author

You will also need to do more If you want to pass in your own headers. You won't be able to use your own delegate because Parse already has one. You should only need to respond to the challenge and maybe pass in headers which can be two different parameters that can be passed into the config assuming you add the capability to the SDK.

Any method to add SSL pinning certificate in parse request and response handle like an error in parse query

I am working as an iOS developer and I don't know how to add a certificate in Parse initialization SDK because for security purpose any middle attack all data is exposed in front of Charles or any other so the client requirement is to add a certificate in parse request

in Android, it is used in request but no any option in iOS SWIFT

@cbaker6
Copy link
Contributor

cbaker6 commented Jan 5, 2021

The links and comments I posted are in reference to how to do it. iOS allows it via URLSession, the iOS SDK uses URLSession, but currently doesn't expose what's needed to enable this for Parse. You can use what I posted for direction on how to add the feature to the iOS SDK for everyone to use, but you have to modify the SDK itself to expose what's needed. There's no way I know of jumping in front of the dedicated URLSession Parse uses to intercept authentication challenges. The Parse URLSession is doing a ton of things, adding the feature will also allow it to authenticate

@cbaker6
Copy link
Contributor

cbaker6 commented Jan 21, 2021

dup #1103

@gytiskv
Copy link

gytiskv commented Jan 25, 2021

#1598
Here we have implemented the SSL pinning for our application. This is still not ready for PR - need to add some tests and documentation.

@stale
Copy link

stale bot commented Jul 21, 2021

This issue has been automatically marked as stale because it has not had recent activity. If you believe it should stay open, please let us know! As always, we encourage contributions, check out the Contributing Guide

@stale stale bot added the Stale label Jul 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:feature New feature or improvement of existing feature
Projects
None yet
Development

No branches or pull requests

4 participants