Java HTTPS istemci sertifikası kimlik doğrulaması


222

Oldukça HTTPS/SSL/TLSyeniyim ve müşterilerin sertifikalarla kimlik doğrulaması yaparken tam olarak ne sunmaları gerektiği konusunda biraz kafam karıştı.

POSTBelirli bir veri basit yapmak için gereken bir Java istemcisi yazıyorum URL. Bu kısım iyi çalışıyor, tek sorun bunun bitmesi gerekiyor HTTPS. HTTPSBölüm sap oldukça kolaydır (ile ya HTTPclientkullanarak veya Java en yerleşik HTTPSdestek), ama istemci sertifikaları kimlik doğrulaması üzerinde şaşırıp. Zaten kodum ile henüz denemedim burada çok benzer bir soru olduğunu fark ettim (yeterince yakında yapacak). Şu anki sorunum - ne yaparsam yapalım - Java istemcisi hiçbir zaman sertifika göndermez (bunu PCAPdökümlerle kontrol edebilirim ).

Sertifikalarla kimlik doğrulaması yaparken istemcinin sunucuya tam olarak ne sunması gerektiğini bilmek istiyorum (özellikle Java için - bu önemliyse)? Bu bir JKSdosya mı , yoksa PKCS#12? Onlarda ne olması gerekiyordu; sadece istemci sertifikası mı yoksa bir anahtar mı? Varsa, hangi anahtar? Tüm farklı dosya türleri, sertifika türleri ve benzerleri hakkında biraz karışıklık var.

Daha önce de söylediğim gibi, ben de HTTPS/SSL/TLSbazı arka plan bilgilerini takdir ediyorum (bir makale olmak zorunda değil; iyi makalelere bağlantılar için razı olacağım).


nasıl anahtar deposu ve truststore eklemek gerekir belirlemek için istemciden iki sertifika verdik, bu tür sorunu zaten gitti gibi bu sorunu tanımlamak yardımcı olabilir misiniz, bu sorun aslında stackoverflow
henrycharles

Yanıtlar:


233

Sonunda tüm sorunları çözmeyi başardım, bu yüzden kendi sorumu cevaplayacağım. Bunlar, özel sorun (lar) ımı çözmek için kullandığım ayarlar / dosyalar;

Müşterinin deposu bir olduğunu PKCS # 12 biçiminde içeren dosya

  1. İstemcinin genel sertifikası (bu durumda kendinden imzalı bir CA tarafından imzalanmış)
  2. Müşterinin özel anahtarı

Bunu oluşturmak için OpenSSL pkcs12komutunu kullandım, örneğin;

openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"

İpucu: PKCS # 12 dosyalarını düzgün bir şekilde oluşturmanıza izin vermeyen bir hatadan muzdarip olduğu için 0.9.8h sürümünü değil , en son OpenSSL'yi aldığınızdan emin olun .

Bu PKCS # 12 dosyası, sunucu istemciden açıkça kimlik doğrulaması istediğinde istemci sertifikasını sunucuya sunmak için Java istemcisi tarafından kullanılacaktır. İstemci sertifikası kimlik doğrulaması protokolünün gerçekte nasıl çalıştığına genel bir bakış için TLS hakkındaki Wikipedia makalesine bakın (ayrıca burada istemcinin özel anahtarına neden ihtiyacımız olduğunu açıklar).

Müşterinin truststore bir yalındır JKS biçimi içeren dosya kök veya ara CA sertifikalarını . Bu CA sertifikaları, hangi uç noktalarla iletişim kurmanıza izin verileceğini belirler, bu durumda, müşterinizin güven veren mağazanın CA'larından biri tarafından imzalanmış bir sertifikayı sunan herhangi bir sunucuya bağlanmasına izin verir.

Bunu oluşturmak için standart Java tuş takımını kullanabilirsiniz;

keytool -genkey -dname "cn=CLIENT" -alias truststorekey -keyalg RSA -keystore ./client-truststore.jks -keypass whatever -storepass whatever
keytool -import -keystore ./client-truststore.jks -file myca.crt -alias myca

Bu güvenilir mağazayı kullanarak, müşteriniz tarafından belirlenen CA tarafından imzalanmış bir sertifika sunan tüm sunucularla tam bir SSL anlaşması yapmaya çalışacaktır myca.crt.

Yukarıdaki dosyalar kesinlikle sadece müşteri içindir. Bir sunucu kurmak istediğinizde, sunucunun kendi anahtar ve güven deposu dosyalarına ihtiyacı vardır. Bir Java istemcisi ve sunucusu (Tomcat kullanarak) için tam olarak çalışan bir örnek oluşturmak için harika bir gezinti bu web sitesinde bulunabilir .

Sorunlar / Açıklamalar / İpuçları

  1. İstemci sertifikası kimlik doğrulaması yalnızca sunucu tarafından uygulanabilir.
  2. ( Önemli! ) Sunucu bir istemci sertifikası istediğinde (TLS anlaşmasının bir parçası olarak), sertifika isteğinin bir parçası olarak güvenilir CA'ların bir listesini de sağlar. Kimlik doğrulama için bugüne isteyen istemci sertifikası zaman değil bu CA adlı biri tarafından imzalanmış, (bence, bu garip bir davranıştır, ama emin bunun için bir sebebi var olduğum) Tüm sunulacak olmayacaktır. Karşı tarafın sunucusunu kendinden imzalı istemci sertifikamı kabul edecek şekilde yapılandırmamış olması nedeniyle, sorunumun ana nedeni buydu ve istemcinin istekte düzgün bir şekilde sertifika vermemesi nedeniyle sorunun benim tarafımda olduğunu varsaydık.
  3. Wireshark'ı edinin. Mükemmel SSL / HTTPS paket analizine sahiptir ve hata ayıklama ve sorunu bulma konusunda büyük bir yardımcı olacaktır. Bu benzeyen -Djavax.net.debug=sslama daha yapılandırılmıştır ve (belki) Java SSL ayıklama çıkışı memnun değilsen yorumlamak daha kolay.
  4. Apache httpclient kütüphanesini kullanmak mükemmel bir şekilde mümkündür. Httpclient kullanmak istiyorsanız, hedef URL'yi HTTPS eşdeğeriyle değiştirin ve aşağıdaki JVM bağımsız değişkenlerini ekleyin (HTTP / HTTPS üzerinden veri göndermek / almak için kullanmak istediğiniz kitaplığa bakılmaksızın diğer tüm istemciler için aynıdır) :

    -Djavax.net.debug=ssl
    -Djavax.net.ssl.keyStoreType=pkcs12
    -Djavax.net.ssl.keyStore=client.p12
    -Djavax.net.ssl.keyStorePassword=whatever
    -Djavax.net.ssl.trustStoreType=jks
    -Djavax.net.ssl.trustStore=client-truststore.jks
    -Djavax.net.ssl.trustStorePassword=whatever

6
"Kimlik doğrulaması için sunmak istediğiniz istemci sertifikası bu CA'lardan biri tarafından imzalanmadığında, hiç sunulmaz". İstemciler sunucu tarafından kabul edilmeyeceğini bildiği için sertifikalar sunulmaz. Ayrıca, sertifikanız bir ara CA "ICA" ile imzalanabilir ve sunucu istemcinize kök CA "RCA" sunabilir ve web tarayıcınız yine de RCA tarafından değil ICA tarafından imzalanmış olsa bile sertifikanızı seçmenize izin verir.
Mart'ta KyleM

2
Yukarıdaki yoruma bir örnek olarak, bir kök CA (RCA1) ve iki ara CA (ICA1 ve ICA2) bulunan bir durumu göz önünde bulundurun. RCA1'i güven deposuna alırsanız Apache Tomcat'te web tarayıcınız, güven mağazanızda olmasalar bile ICA1 ve ICA2 tarafından imzalanmış TÜM sertifikaları sunar. Bunun nedeni bireysel certs için önemli olmayan zincir olmasıdır.
Mart'ta KyleM

2
"Bence bu garip bir davranış, ama eminim bunun bir sebebi var". Bunun nedeni, RFC 2246'da söylediği şeydir. Bu konuda garip bir şey yok. İstemcilerin sunucu tarafından kabul edilmeyen sertifikalar sunmalarına izin vermek garip olacak ve zaman ve alan kaybıdır.
Lorne Marquis

1
Yukarıdaki örnekte olduğu gibi, tek bir JVM geniş anahtar deposu (ve truststore!) Kullanmaya karşı şiddetle tavsiye ediyorum. Tek bir bağlantıyı özelleştirmek daha güvenli ve daha esnektir, ancak biraz daha kod yazmanızı gerektirir. SSLContext@ Magnus'un cevabındaki gibi özelleştirmek zorundasınız .
Christopher Schultz

63

Diğer yanıtlar, istemci sertifikalarının küresel olarak nasıl yapılandırılacağını gösterir. Ancak, istemci anahtarını JVM'nizde çalışan her uygulamada global olarak tanımlamak yerine belirli bir bağlantı için programlı olarak tanımlamak istiyorsanız, kendi SSLContext'inizi şu şekilde yapılandırabilirsiniz:

String keyPassphrase = "";

KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("cert-key-pair.pfx"), keyPassphrase.toCharArray());

SSLContext sslContext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, null)
        .build();

HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
HttpResponse response = httpClient.execute(new HttpGet("https://example.com"));

Kullanmak zorunda kaldım sslContext = SSLContexts.custom().loadTrustMaterial(keyFile, PASSWORD).build();. Ben çalışamadım loadKeyMaterial(...).
Conor Svensson

4
@ConorSvensson Güven malzemesi uzak sunucu sertifikasına güvenen istemci içindir, anahtar malzeme istemciye güvenen sunucu içindir.
Magnus

1
Bu kısa ve anında cevabı gerçekten seviyorum. İnsanların ilgilenmesi durumunda, burada derleme talimatları ile çalışılmış bir örnek veriyorum. stackoverflow.com/a/46821977/154527
Alain O'Dea

3
Günümü kurtardın! Sadece bir ekstra değişiklik yapmam gerekiyordu, şifreyi de loadKeyMaterial(keystore, keyPassphrase.toCharArray())kod olarak gönder '!
AnandShanbhag

1
@peterh Evet, Apache http'ye özeldir. Her HTTP kitaplığının kendi yapılandırma yöntemi olacaktır, ancak çoğunda bir şekilde bir SSLContext.
Magnus

30

JKS dosyası sadece sertifikalar ve anahtar çiftleri için bir kaptır. İstemci tarafı kimlik doğrulama senaryosunda, anahtarların çeşitli bölümleri burada bulunur:

  • Müşterinin 's mağaza müşterinin içerecektir özel ve kamu anahtar çifti. Buna anahtar deposu denir .
  • Sunucunun 's mağaza müşterinin içerecektir kamu anahtarı. Buna truststore denir .

Güven deposunun ve anahtar deposunun ayrılması zorunlu değildir, ancak önerilir. Aynı fiziksel dosya olabilirler.

İki deponun dosya sistemi konumlarını ayarlamak için aşağıdaki sistem özelliklerini kullanın:

-Djavax.net.ssl.keyStore=clientsidestore.jks

ve sunucuda:

-Djavax.net.ssl.trustStore=serversidestore.jks

İstemcinin sertifikasını (ortak anahtar) bir dosyaya vermek için, sunucuya kopyalayabilmeniz için şunu kullanın:

keytool -export -alias MYKEY -file publicclientkey.cer -store clientsidestore.jks

İstemcinin ortak anahtarını sunucunun anahtar deposuna içe aktarmak için şunu kullanın (belirtilen poster olarak, bu zaten sunucu yöneticileri tarafından yapılmıştır)

keytool -import -file publicclientkey.cer -store serversidestore.jks

Muhtemelen sunucu üzerinde hiçbir kontrole sahip olmadığımı söylemeliyim. Sunucu genel sertifikamızı içeri aktardı. Bu sistemin yöneticileri tarafından, el sıkışma sırasında gönderilebilmesi için sertifikasını açıkça sağlamam gerektiği söylendi (sunucuları bunu açıkça istiyor).
tmbrggmn

JKS dosyası olarak genel sertifikanız (sunucu tarafından bilinen) için genel ve özel anahtarlara ihtiyacınız olacaktır.
sfussenegger

Örnek kod için teşekkürler. Yukarıdaki kodda, "mykey-public.cer" tam olarak nedir? Bu istemci genel sertifikası mı (kendinden imzalı sertifikalar kullanıyoruz)?
tmbrggmn

Evet, kod snippet'lerindeki dosyaları buna göre yeniden adlandırdım. Umarım bu açıklığa kavuşur.
mhaller

Righto, teşekkürler. Görünüşe göre "anahtar" ve "sertifika" birbirinin yerine kullanıldığından, kafam karışıyor.
tmbrggmn

10

Maven pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>some.examples</groupId>
    <artifactId>sslcliauth</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>sslcliauth</name>
    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.4</version>
        </dependency>
    </dependencies>
</project>

Java kodu:

package some.examples;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.entity.InputStreamEntity;

public class SSLCliAuthExample {

private static final Logger LOG = Logger.getLogger(SSLCliAuthExample.class.getName());

private static final String CA_KEYSTORE_TYPE = KeyStore.getDefaultType(); //"JKS";
private static final String CA_KEYSTORE_PATH = "./cacert.jks";
private static final String CA_KEYSTORE_PASS = "changeit";

private static final String CLIENT_KEYSTORE_TYPE = "PKCS12";
private static final String CLIENT_KEYSTORE_PATH = "./client.p12";
private static final String CLIENT_KEYSTORE_PASS = "changeit";

public static void main(String[] args) throws Exception {
    requestTimestamp();
}

public final static void requestTimestamp() throws Exception {
    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(
            createSslCustomContext(),
            new String[]{"TLSv1"}, // Allow TLSv1 protocol only
            null,
            SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(csf).build()) {
        HttpPost req = new HttpPost("https://changeit.com/changeit");
        req.setConfig(configureRequest());
        HttpEntity ent = new InputStreamEntity(new FileInputStream("./bytes.bin"));
        req.setEntity(ent);
        try (CloseableHttpResponse response = httpclient.execute(req)) {
            HttpEntity entity = response.getEntity();
            LOG.log(Level.INFO, "*** Reponse status: {0}", response.getStatusLine());
            EntityUtils.consume(entity);
            LOG.log(Level.INFO, "*** Response entity: {0}", entity.toString());
        }
    }
}

public static RequestConfig configureRequest() {
    HttpHost proxy = new HttpHost("changeit.local", 8080, "http");
    RequestConfig config = RequestConfig.custom()
            .setProxy(proxy)
            .build();
    return config;
}

public static SSLContext createSslCustomContext() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
    // Trusted CA keystore
    KeyStore tks = KeyStore.getInstance(CA_KEYSTORE_TYPE);
    tks.load(new FileInputStream(CA_KEYSTORE_PATH), CA_KEYSTORE_PASS.toCharArray());

    // Client keystore
    KeyStore cks = KeyStore.getInstance(CLIENT_KEYSTORE_TYPE);
    cks.load(new FileInputStream(CLIENT_KEYSTORE_PATH), CLIENT_KEYSTORE_PASS.toCharArray());

    SSLContext sslcontext = SSLContexts.custom()
            //.loadTrustMaterial(tks, new TrustSelfSignedStrategy()) // use it to customize
            .loadKeyMaterial(cks, CLIENT_KEYSTORE_PASS.toCharArray()) // load client certificate
            .build();
    return sslcontext;
}

}

Belgeyi belirli bir JVM yüklemesi kullanan tüm uygulamalar için kullanmayı tercih ediyorsanız, bunun yerine bu yanıtı izleyin .
ADTC

configureRequest()projesinin proxy'sini ayarlama yöntemi doğru mu?
shareef

evet, http istemci yapılandırması ve bu durumda proxy yapılandırması
kinjelom

belki aptalca bir sorum var, ama cacert.jks dosyasını nasıl oluşturabilirim? "Main" iş parçacığında özel durum var java.io.FileNotFoundException:. \ Cacert.jks (Sistem belirtilen dosyayı bulamıyor)
Patlatus

6

Yalnızca iki yönlü bir kimlik doğrulaması (sunucu ve istemci sertifikaları) ayarlamak isteyenler için, bu iki bağlantının bir kombinasyonu sizi oraya götürür:

İki yönlü kimlik doğrulama kurulumu:

https://linuxconfig.org/apache-web-server-ssl-authentication

Belirttikleri openssl yapılandırma dosyasını kullanmanıza gerek yoktur; sadece kullan

  • $ openssl genrsa -des3 -out ca.key 4096

  • $ openssl req -yeni -x509 -gün 365 -key ca.key -out ca.crt

kendi CA sertifikanızı oluşturmak ve ardından sunucu ve istemci anahtarlarını oluşturmak ve imzalamak için:

  • $ openssl genrsa -des3 -out server.key 4096

  • $ openssl req -new -key server.key -out server.csr

  • $ openssl x509 -req -gün 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 100 -out sunucu.crt

ve

  • $ openssl genrsa -des3 -out client.key 4096

  • $ openssl req -new -key client.key -out client.csr

  • $ openssl x509 -req -gün 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 101 -out client.crt

Geri kalanı için bağlantıdaki adımları izleyin. Chrome sertifikalarını yönetmek, belirtilen firefox örneğiyle aynı şekilde çalışır.

Ardından, sunucuyu şu yolla kurun:

https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04

Sunucunun .crt ve .key dosyalarını oluşturduğunuzu ve bu adımı artık yapmak zorunda olmadığınızı unutmayın.


1
Sunucu CSR nesil adımda yazım hatası var düşünün: kullanmalıdır server.keydeğilclient.key
the.Legend

0

Spring Boot ile iki yönlü SSL (istemci ve sunucu sertifikası) ile bankaya bağlandım. Burada tüm adımlarımı açıklayın, umarım birisine yardımcı olur (en basit çalışma çözümü, buldum):

  1. Sertifika isteği oluşturun:

    • Özel anahtar oluştur:

      openssl genrsa -des3 -passout pass:MY_PASSWORD -out user.key 2048
    • Sertifika isteği oluştur:

      openssl req -new -key user.key -out user.csr -passin pass:MY_PASSWORD

    Tut user.keySertifikamı (ve şifrele) ve sertifika isteğini user.csrbankaya gönder

  2. 2 sertifika al: istemci kök sertifikam clientId.crt ve banka kök sertifikam:bank.crt

  3. Java anahtar deposu oluşturun (anahtar şifresini girin ve anahtar deposu şifresini ayarlayın):

    openssl pkcs12 -export -in clientId.crt -inkey user.key -out keystore.p12 -name clientId -CAfile ca.crt -caname root

    Çıktıya dikkat etmeyin: unable to write 'random state' . Java PKCS12 keystore.p12oluşturuldu.

  4. Anahtar deposuna ekle bank.crt (basitlik için bir anahtar deposu kullandım):

    keytool -import -alias banktestca -file banktestca.crt -keystore keystore.p12 -storepass javaops

    Anahtar deposu sertifikalarını şu şekilde kontrol edin:

    keytool -list -keystore keystore.p12
  5. Java kodu için hazır :) RestTemplateAdd org.apache.httpcomponents.httpcorebağımlılığı ile Spring Boot kullandım :

    @Bean("sslRestTemplate")
    public RestTemplate sslRestTemplate() throws Exception {
      char[] storePassword = appProperties.getSslStorePassword().toCharArray();
      URL keyStore = new URL(appProperties.getSslStore());
    
      SSLContext sslContext = new SSLContextBuilder()
            .loadTrustMaterial(keyStore, storePassword)
      // use storePassword twice (with key password do not work)!!
            .loadKeyMaterial(keyStore, storePassword, storePassword) 
            .build();
    
      // Solve "Certificate doesn't match any of the subject alternative names"
      SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    
      CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
      HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);
      RestTemplate restTemplate = new RestTemplate(factory);
      // restTemplate.setMessageConverters(List.of(new Jaxb2RootElementHttpMessageConverter()));
      return restTemplate;
    }

Her şeyi tuş takımı ile yapabilirsiniz. Bu konuda hiç OpenSSL'ye gerek yok.
Lorne Marquis

0

Hem sertifikayla hem de özel anahtarla (örneğin, openssl tarafından oluşturulan) bir p12 dosyası verildiğinde, aşağıdaki kod belirli bir HttpsURLConnection için bunu kullanır:

    KeyStore keyStore = KeyStore.getInstance("pkcs12");
    keyStore.load(new FileInputStream(keyStorePath), keystorePassword.toCharArray());
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, keystorePassword.toCharArray());
    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(kmf.getKeyManagers(), null, null);
    SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();

    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    connection.setSSLSocketFactory(sslSocketFactory);

SSLContextBunu önbelleğe isteyebilirsiniz böylece, initialize biraz zaman alır.


-1

Ben burada düzeltme anahtar deposu türü olduğunu düşünüyorum, pkcs12 (pfx) her zaman özel anahtar var ve JKS türü özel anahtar olmadan var olabilir. Kodunuzda belirtmedikçe veya tarayıcı aracılığıyla bir sertifika seçmedikçe, sunucunun diğer tarafta bir istemciyi temsil ettiğini bilmenin bir yolu yoktur.


1
PKCS12 formatı geleneksel olarak privatekey-AND-cert için kullanıldı, ancak Java, 2014'te 8'den beri (bu cevaptan bir yıldan fazla), privatekey (ler) olmadan PKCS12 içeren sertifikaları destekledi. Anahtar deposu biçiminden bağımsız olarak, istemci yetkilendirmesi özelleştirme-VE-sertifikası gerektirir. Ben senin ikinci cümle anlamıyorum, ama Java istemci olabilir en azından bir uygun giriş kullanılabilir veya bir KeyManager eğer otomatik olarak bir istemci sertifika-ve-anahtar seçin edebilir belirli bir birini kullanmak üzere yapılandırılabilir.
dave_thompson_085

İkinci cümleniz tamamen yanlış. Sunucu güvenilir imzalayanlarını sağlar ve istemci ölür veya bu kısıtlamayı sağlayan bir sertifika sağlamaz. Otomatik olarak 'kodunuzda' değil. Yani bir sunucunun 'bir müşteri temsil ediyor bilmenin yolu'.
Lorne Marquis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.