आईओएस और एंड्रॉइड में क्लाइंट एसएसएल प्रमाणपत्रों का उपयोग करके प्राधिकरण

सिक्योर सॉकेट्स लेयर (एसएसएल) प्रोटोकॉल, सुरक्षित डेटा ट्रांसफर प्रदान करने के अलावा, आपको SSL क्लाइंट प्रमाणपत्रों का उपयोग करके क्लाइंट प्रमाणीकरण को लागू करने की अनुमति भी देता है। यह लेख IOS और Android पर मोबाइल अनुप्रयोगों में इस प्रकार के प्राधिकरण को लागू करने के लिए एक व्यावहारिक मार्गदर्शिका है।

इस प्रकार के प्राधिकरण प्रदान करने वाले सर्वर के संचालन को व्यवस्थित करने की प्रक्रिया को लेख में नहीं माना गया है, हालांकि, इस विषय के लिंक अंत में प्रदान किए गए हैं।

प्राधिकरण की प्रक्रिया इस प्रकार है। जब कोई ग्राहक किसी बंद क्षेत्र में जाता है, तो सर्वर क्लाइंट से प्रमाणपत्र के लिए पूछता है; यदि चेक सफल होता है, तो ग्राहक बंद सामग्री तक पहुंच प्राप्त करता है, अन्यथा, क्लाइंट को " कोई आवश्यक SSL प्रमाणपत्र नहीं भेजा गया " त्रुटि प्राप्त हो सकती है।

कनेक्शन को व्यवस्थित करने के लिए, हमने एक क्लाइंट प्रमाणपत्र तैयार किया, और एक प्रमाण पत्र पर हस्ताक्षर करने के लिए एक अनुरोध भी बनाया, जिसके परिणामस्वरूप हमें client.csr फ़ाइल प्राप्त हुई। इसके बाद, हमने इस फ़ाइल को सेवा प्रदाता को भेज दिया और दूरस्थ सर्वर पर प्रमाणीकरण के लिए आवश्यक हमारे हस्ताक्षरित क्लाइंट प्रमाणपत्र प्राप्त किया।

कनेक्शन परीक्षण कर्ल उपयोगिता का उपयोग करके किया जा सकता है।

कर्ल सर्टिफ़िकेट। क्लाइंट प्रमुख क्लाइंट.की k someserive.com

हालांकि, यह ध्यान देने योग्य है कि OS X में कर्ल 7.30.0 के नवीनतम संस्करण में यह टूटा हुआ है और इसका उपयोग परीक्षण ( http://curl.haxx.se/mail/archive-2013-10/0036.html ) को व्यवस्थित करने के लिए नहीं किया जा सकता है।

क्लाइंट प्रमाणपत्र को स्थानांतरित करने के लिए, हम PKCS # 12 प्रारूप में फ़ाइल का उपयोग करेंगे। PKCS # 12 फाइलें निजी कुंजी और प्रमाणपत्र (एन्क्रिप्टेड रूप में) दोनों को संग्रहीत करती हैं। PKCS # 12 फ़ाइल का एक उदाहरण संगठन दिखाया गया है।



आप निम्न आदेश का उपयोग करके अपने client.crt को PKCS # 12 प्रारूप फ़ाइल में बदल सकते हैं:

ग्राहक में .sk pkcs12 का निर्यात करता है

PKCS # 12 प्रारूप में फ़ाइल प्राप्त करने के बाद, हम अपने मोबाइल एप्लिकेशन के विकास और परीक्षण के लिए आगे बढ़ सकते हैं। आईओएस से शुरू करते हैं।

1. हम एप्लिकेशन के iOS संस्करण को लागू करते हैं

अपने Security.Framework प्रोजेक्ट से जुड़ा होना चाहिए
अनुरोध को पूरा करने के लिए, हमें PKCS # 12 और संबंधित निजी कुंजी (SecIdentityRef) से एक डिजिटल प्रमाणपत्र निकालना होगा। इस ऑब्जेक्ट की उपस्थिति हमें संबंधित NSURLCredential प्राप्त करने की अनुमति देगा।
तो हम फंक्शन एक्सट्रैक्टइंडिटीएंडट्रस्ट को लागू करते हैं।

OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity) { OSStatus securityError = errSecSuccess; CFStringRef password = CFSTR(""); const void *keys[] = { kSecImportExportPassphrase }; const void *values[] = { password }; CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import(inP12data, options, &items); if (securityError == 0) { CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0); const void *tempIdentity = NULL; tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity); *identity = (SecIdentityRef)tempIdentity; } if (options) { CFRelease(options); } return securityError; } 

हम SecPKCS12Import फ़ंक्शन का उपयोग करके निकालते हैं, हम प्रमाणपत्र के लिए पासवर्ड निर्दिष्ट करना याद करते हैं।
अगला, हम canAuthenticateAgainstProtectionSpace प्रतिनिधि को लागू करते हैं, इस प्रतिनिधि को बुलाकर हमें सर्वर के गुणों को निर्धारित करने की अनुमति मिलती है, अर्थात् प्रोटोकॉल, प्राधिकरण तंत्र। इस प्रतिनिधि का हमारा कार्यान्वयन सरल होगा, हम इंगित करते हैं कि हम सर्वर द्वारा प्रस्तुत किसी भी प्रमाणीकरण विधि को संसाधित कर रहे हैं।

 - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { return YES; } 

हम संभावित त्रुटियों को संसाधित करते हैं:

 - (void)connection:(NSURLConnection*) connection didFailWithError:(NSError *)error { NSLog(@"Did recieve error: %@", [error localizedDescription]); NSLog(@"%@", [error userInfo]); } 

अब सीधे प्रमाणीकरण तंत्र को लागू करने के लिए आगे बढ़ते हैं। ड्रेडेक्यूएथेंटिफिकेशन कल्जेन प्रतिनिधि को लागू करें:

 - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { NSLog(@"Authentication challenge"); // load cert NSString *path = [[NSBundle mainBundle] pathForResource:@"keystore" ofType:@"p12"]; NSData *p12data = [NSData dataWithContentsOfFile:path]; CFDataRef inP12data = (__bridge CFDataRef)p12data; SecIdentityRef myIdentity; OSStatus status = extractIdentityAndTrust(inP12data, &myIdentity); SecCertificateRef myCertificate; SecIdentityCopyCertificate(myIdentity, &myCertificate); const void *certs[] = { myCertificate }; CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL); NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence: NSURLCredentialPersistenceForSession]; [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } 

हम अपने प्रमाण पत्र को लोड करते हैं, हमें जो डेटा चाहिए, उससे निकालते हैं, एक NSURLCredential बनाते हैं, आवश्यक जानकारी स्थानांतरित करते हैं, और केवल वर्तमान सत्र के संदर्भ में प्रमाणीकरण डेटा को बचाते हैं।

खैर, पूर्णता के लिए, मैं NSURLConnection की तैयारी करने वाला कोड दूंगा:

 NSString *key = @"test"; NSError *jsonSerializationError = nil; NSMutableDictionary *projectDictionary = [NSMutableDictionary dictionaryWithCapacity:1]; [projectDictionary setObject:key forKey:@"test"]; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:projectDictionary options:nil error:&jsonSerializationError]; NSURL *requestUrl = [[NSURL alloc] initWithString:@"https://your_service"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; [request setHTTPMethod:@"POST"]; [request setValue:@"UTF-8" forHTTPHeaderField:@"content-charset"]; [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [request setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"]; [request setHTTPBody: jsonData]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [connection start]; 


मैं didReceiveData प्रतिनिधि का कार्यान्वयन नहीं दूंगा।

2. हम एप्लिकेशन के एंड्रॉइड संस्करण को लागू करते हैं

मैं कोड के साथ तुरंत शुरू करूँगा:

 KeyStore keystore = KeyStore.getInstance("PKCS12"); keystore.load(getResources().openRawResource(R.raw.keystore), "".toCharArray()); SSLSocketFactory sslSocketFactory = new AdditionalKeyStoresSSLSocketFactory(keystore); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); HttpProtocolParams.setUseExpectContinue(params, true); final SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sslSocketFactory, 3123)); ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry); DefaultHttpClient httpclient = new DefaultHttpClient(manager, params); HttpPost httpPostRequest = new HttpPost("https://your_service"); // datas - array which contains data to send to server StringEntity se = new StringEntity(datas[0].toString(), HTTP.UTF_8); // Set HTTP parameters httpPostRequest.setEntity(se); httpPostRequest.setHeader("Accept", "application/json"); httpPostRequest.setHeader("Content-Type", "application/json"); HttpResponse response = httpclient.execute(httpPostRequest); 

हमें अपने मामले में इसी KeyStore का उदाहरण मिलता है (PKCS12), संसाधनों से हमारा प्रमाण पत्र लोड करें, पासवर्ड को दूसरे तर्क के रूप में निर्दिष्ट करें। अगला, हम SSLSocketFactory का एक उदाहरण बनाते हैं, SSLSocketFactory के अपने स्वयं के कार्यान्वयन का उपयोग करते हुए, जो हमें अपने प्रमाणपत्र का उपयोग करके SSL संदर्भ को आरंभ करने की अनुमति देता है। फ़ैक्टरी कोड नीचे दिखाया गया है। अगला, हम कनेक्शन मापदंडों को कॉन्फ़िगर करते हैं, हमारे कारखाने को पंजीकृत करते हैं, उस पोर्ट को इंगित करते हैं, जिसमें हम अनुरोध भेजेंगे, इसी POST का निर्माण करेंगे और अनुरोध को निष्पादित करेंगे।

फैक्टरी कोड:
 import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.ssl.SSLSocketFactory; /** * Allows you to trust certificates from additional KeyStores in addition to * the default KeyStore */ public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory { protected SSLContext sslContext = SSLContext.getInstance("TLS"); public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(null, null, null, null, null, null); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "".toCharArray()); sslContext.init(kmf.getKeyManagers(), new TrustManager[]{new ClientKeyStoresTrustManager(keyStore)}, new SecureRandom()); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } /** * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager */ public static class ClientKeyStoresTrustManager implements X509TrustManager { protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>(); protected ClientKeyStoresTrustManager(KeyStore... additionalkeyStores) { final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>(); try { // The default Trustmanager with default keystore final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); original.init((KeyStore) null); factories.add(original); for ( KeyStore keyStore : additionalkeyStores ) { final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); additionalCerts.init(keyStore); factories.add(additionalCerts); } } catch (Exception e) { throw new RuntimeException(e); } /* * Iterate over the returned trustmanagers, and hold on * to any that are X509TrustManagers */ for (TrustManagerFactory tmf : factories) for ( TrustManager tm : tmf.getTrustManagers() ) if (tm instanceof X509TrustManager) x509TrustManagers.add( (X509TrustManager) tm ); if ( x509TrustManagers.size() == 0 ) throw new RuntimeException("Couldn't find any X509TrustManagers"); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { for ( X509TrustManager tm : x509TrustManagers ) { try { tm.checkClientTrusted(chain, authType); return; } catch ( CertificateException e ) { } } throw new CertificateException(); } /* * Loop over the trustmanagers until we find one that accepts our server */ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { for ( X509TrustManager tm : x509TrustManagers ) { try { tm.checkServerTrusted(chain, authType); return; } catch ( CertificateException e ) { } } throw new CertificateException(); } public X509Certificate[] getAcceptedIssuers() { final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>(); for ( X509TrustManager tm : x509TrustManagers ) list.addAll(Arrays.asList(tm.getAcceptedIssuers())); return list.toArray(new X509Certificate[list.size()]); } } } 

निष्कर्ष।

हमने एक ग्राहक प्रमाणपत्र का उपयोग करके एसएसएल का उपयोग करके प्रमाणित करने का तरीका जांचा।

उपयोगी जानकारी:
IOS के लिए प्रमाणपत्र, कुंजी और ट्रस्ट सेवा कार्य
PKCS12 का विवरण
क्लाइंट प्रमाणपत्र प्रमाणीकरण के साथ .NET वेब सेवा बनाना
Asp.net में प्रमाणपत्र प्रमाणीकरण
जावा 2-वे टीएलएस / एसएसएल (क्लाइंट सर्टिफिकेट) और पीकेसीएस 12 बनाम जेकेएस कीस्टोर्स

आपका ध्यान के लिए धन्यवाद!

Source: https://habr.com/ru/post/In194530/


All Articles