프로젝트하면서 개발서버 SSL 인증서가 만료되어 URLSession 문제로 API 접속시 SSL 오류가 발생하는데

WKWebview나 URLSession 사용해서 내가 개발한 소스면 예외처리에 어려움이 없을 겁니다.

 

정말 문제는 3rdParty 라이브러리 내부에서 API 통신을 하는데 소스를 까볼 수도 없고 라이브러리 내부에서 SSL관련 예외처리가 안되어 있다면 당연히 해당 라이브러리 내부에서 사용하는 API 는 실패하게 됩니다.

 

그래서 이런경우 SSLBypass 할 수 있는 방법에 대해서 포스팅 합니다.

 

URLProtocol 상속 받아 설정 하면 됩니다.

import Foundation

class SSLBypassSessionDelegate: NSObject, URLSessionDelegate {
    // 많이 보던 코드죠? SSL 예외처리 코드
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
    	if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let credential = URLCredential.init(trust: challenge.protectionSpace.serverTrust!)
            
            DispatchQueue.global().async {
                completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential)
            }
            
            return
        }
        
        DispatchQueue.global().async {
            completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)
        }
        
        /*if let serverTrust = challenge.protectionSpace.serverTrust {
            completionHandler(.useCredential, URLCredential(trust: serverTrust))
        } else {
            completionHandler(.performDefaultHandling, nil)
        }*/
    }
}

final class SSLBypassURLProtocol: URLProtocol {
    
    override class func canInit(with request: URLRequest) -> Bool {
        // 모든 요청을 가로챕니다.
        return true
    }
    
    override class func canInit(with task: URLSessionTask) -> Bool {
        return true
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        return request
    }

    override func startLoading() {
        // 가로챈 URLSession request 를 SSLBypassSessionDelegate 를 통해서 예외처리 하면됩니다.
        let session = URLSession(configuration: .default, delegate: SSLBypassSessionDelegate(), delegateQueue: .current)
        let task = session.dataTask(with: request) { data, response, error in
            if let data = data {
                self.client?.urlProtocol(self, didLoad: data)
            }
            if let response = response {
                self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            }
            if let error = error {
                self.client?.urlProtocol(self, didFailWithError: error)
            }
            self.client?.urlProtocolDidFinishLoading(self)
        }
        task.resume()
    }

    override public func stopLoading() {
        // 필요 시 중단 작업 처리
    }
}

 

적용방법 (디버그 모드일 경우에만 사용해야 됩니다. 안그러면 배포시 문제 될 수도 있습니다.)

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    			..... 생략 .....
                
#if DEBUG
        setupGlobalSSLBypass()
#endif
    }
}

/* MARK: SSL 인증서 전역 예외 처리
    개발서버 SSL 인증서 없는 경우 외부라이브러리 모듈에서 네트워크 SSL 오류 발생
     - SSL 인증서 전역 예외 처리
 */
func setupGlobalSSLBypass() {
    URLProtocol.registerClass(SSLBypassURLProtocol.self)
    
    let config = URLSessionConfiguration.default
    config.protocolClasses = [SSLBypassURLProtocol.self] + (config.protocolClasses ?? [])
    URLSession.shared.configuration.protocolClasses = config.protocolClasses
}

+ Recent posts