Security with HTTPS and SSL

The Secure Sockets Layer (SSL)—now technically known as Transport Layer Security (TLS)—is a common building block for encrypted communications between clients and servers. It’s possible that an application might use SSL incorrectly such that malicious entities may be able to intercept an app’s data over the network. To help you ensure that this does not happen to your app, this article highlights the common pitfalls when using secure network protocols and addresses some larger concerns about using Public-Key Infrastructure (PKI).
安全套接字层(SSL)-现在技术上称为传输层安全(TLS)-是一个常见的客户端和服务器之间的加密通信的构造块模块。一个应用程序可能错误使用SSL,使得恶意程序能够在网络上截取一个应用程序的数据。为了帮助您确保这不会发生在你的应用程序中,本文着重介绍了使用安全的网络协议常见的陷阱和使用公钥私钥解决一些更严重的问题。

Concepts


In a typical SSL usage scenario, a server is configured with a certificate containing a public key as well as a matching private key. As part of the handshake between an SSL client and server, the server proves it has the private key by signing its certificate with public-key cryptography.
使用SSL的典型情况是,服务器会配置一个包含和私钥匹配的公钥的证书。作为SSL客户端和服务器之间的握手的一部分,通过给公钥证书进行签名,服务器证明它具有签名证书的私钥。

However, anyone can generate their own certificate and private key, so a simple handshake doesn’t prove anything about the server other than that the server knows the private key that matches the public key of the certificate. One way to solve this problem is to have the client have a set of one or more certificates it trusts. If the certificate is not in the set, the server is not to be trusted.
但是,任何人都可以生成自己的证书和私钥,所以一个简单的握手,除了能证明服务器知道该证书的公钥匹配的私钥以外,并不能证明服务器其他任何东西。解决这个问题的一种方法是在客户端有一个或多个可信任的证书集合。如果证书不在集合中,服务器是不可信任的。

There are several downsides to this simple approach. Servers should be able to upgrade to stronger keys over time (“key rotation”), which replaces the public key in the certificate with a new one. Unfortunately, now the client app has to be updated due to what is essentially a server configuration change. This is especially problematic if the server is not under the app developer’s control, for example if it is a third party web service. This approach also has issues if the app has to talk to arbitrary servers such as a web browser or email app.
对于这种简单的方法,有几个缺点。随时间的推移服务器可能升级到更强的key(这就是“密钥轮换”),一个新的key的产生将替换证书中的公共密钥。不幸的是,这样的话由于本质上服务器配置的变化,客户端应用程序必须进行更新。如果该服务器不是在应用程序开发者的控制下,这是有问题的,例如,如果它是一个第三方web服务。如果该应用程序和任意服务器,如Web浏览器或电子邮件应用程序,进行交互,这种方法也有问题。

In order to address these downsides, servers are typically configured with certificates from well known issuers called Certificate Authorities (CAs). The host platform generally contains a list of well known CAs that it trusts. As of Android 4.2 (Jelly Bean), Android currently contains over 100 CAs that are updated in each release. Similar to a server, a CA has a certificate and a private key. When issuing a certificate for a server, the CA signs the server certificate using its private key. The client can then verify that the server has a certificate issued by a CA known to the platform.
为了解决这些缺点,服务器通常配置从称为证书机构(CA)的公共的发行人发行的证书。主机平台通常含有被信任的CA的列表。好比Android 4.2(果冻豆)目前包含了100多家的CAs。类似于服务器,CA也具有一个证书和私钥。CA颁发一个服务器证书,CA使用其私有密钥签名服务器证书。然后,客户机就可以验证具有由平台已知的CA颁发的证书服务器了。

However, while solving some problems, using CAs introduces another. Because the CA issues certificates for many servers, you still need some way to make sure you are talking to the server you want. To address this, the certificate issued by the CA identifies the server either with a specific name such as gmail.com or a wildcarded set of hosts such as *.google.com.
然而,使用的CA虽然解决了一些问题,但引入了另一个问题。因为CA为的许多的服务器颁发证书,你还需要一些方法来确保你所连接的服务器就是你想要的服务器。为了解决这个问题,由CA发放证书不但标识服务器而且具有特定域名如 gmail.com 或包含通配符的主机集合如* .google.com。

The following example will make these concepts a little more concrete. In the snippet below from a command line, the openssl tool’s s_client command looks at Wikipedia’s server certificate information. It specifies port 443 because that is the default for HTTPS. The command sends the output of openssl s_client to openssl x509, which formats information about certificates according to the X.509 standard. Specifically, the command asks for the subject, which contains the server name information, and the issuer, which identifies the CA.
下面的例子将使这些概念更具体点。在下面一个命令行的代码片段中,使用 OpenSSL 工具的 s_client 命令可以查看维基百科的服务器证书信息。它指定了端口是443,因为这是HTTPS默认端口。该命令将 OpenSSL 的s_client 的输出发送到 OpenSSL X​​509,该格式是根据X.509标准格式化证书信息。具体而言,该命令要求打印证书包含的服务器名称和发行人的信息。

$ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer

subject=/serialNumber=sOrr2rKpMVP70Z6E9BT5reY008SJEdYv/C=US/O=.wikipedia.org/OU=GT03314600/OU=See www.rapidssl.com/resources/cps (c)11/OU=Domain Control Validated - RapidSSL(R)/CN=.wikipedia.org
issuer= /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
这里写图片描述

An HTTPS Example


Assuming you have a web server with a certificate issued by a well known CA, you can make a secure request with code as simple this:
假设你有一个由著名的CA颁发的证书的Web服务器,您可以用下面简单代码产生一个安全性请求:

URL url = new URL("https://wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

Yes, it really can be that simple. If you want to tailor the HTTP request, you can cast to an HttpURLConnection. The Android documentation for HttpURLConnection has further examples about how to deal with request and response headers, posting content, managing cookies, using proxies, caching responses, and so on. But in terms of the details for verifying certificates and hostnames, the Android framework takes care of it for you through these APIs. This is where you want to be if at all possible. That said, below are some other considerations.
是的,它真的可以这么简单。如果你想定制这个 HTTP 请求,你可以强制转换为 HttpURLConnection。Android开发者文档有关于HttpURLConnection的如何处理请求和响应头,提交内容,管理cookies,使用代理服务器,缓存响应等进一步使用的例子。但在验证证书和主机名的细节方面,Android的框架通过为你提供这些API来关心它。这是你想成为,如果在所有可能的。这就是说,下面是一些其他方面的考虑。

Common Problems Verifying Server Certificates


Suppose instead of receiving the content from getInputStream(), it throws an exception:
从getInputStream()接收来自服务器的内容时它抛出一个异常:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
at libcore.net.http.HttpsURLConnectionImpl HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)atlibcore.net.http.HttpsURLConnectionImpl HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

This can happen for several reasons, including:

  1. The CA that issued the server certificate was unknown
  2. The server certificate wasn’t signed by a CA, but was self signed
  3. The server configuration is missing an intermediate CA

这种情况可能有以下几个原因,其中包括:

  1. 颁发服务器证书的CA未知
  2. 服务器证书不是由CA签名,但自签名
  3. 服务器配置缺少中间CA

The following sections discuss how to address these problems while keeping your connection to the server secure.
以下各节讨论当你想要安全连接到服务器时如何解决这些问题。

Unknown certificate authority

In this case, the SSLHandshakeException occurs because you have a CA that isn’t trusted by the system. It could be because you have a certificate from a new CA that isn’t yet trusted by Android or your app is running on an older version without the CA. More often a CA is unknown because it isn’t a public CA, but a private one issued by an organization such as a government, corporation, or education institution for their own use.
在这种情况下, 会发送 SSLHandshakeException,因为你拥有的是不被系统信任的CA。 这可能是因为你有从一个新的尚未被android系统信任的CA颁发的证书或你的应用程序是在没有该CA的旧版本上运行,更多的时候一个CA是未知的,因为它不是一个公共CA,而是由一个组织发布的私有的CA,如政府,公司或教育机构自己使用的私有的CA。

Fortunately, you can teach HttpsURLConnection to trust a specific set of CAs. The procedure can be a little convoluted, so below is an example that takes a specific CA from an InputStream, uses it to create a KeyStore, which is then used to create and initialize a TrustManager. A TrustManager is what the system uses to validate certificates from the server and—by creating one from a KeyStore with one or more CAs—those will be the only CAs trusted by that TrustManager.
幸运的是,你可以教 HttpsURLConnection 信任一组特定的CA。 该过程可有点难理解,所以下面就是一个从 InputStream 中接受一个特定的CA例子,用它来创建一个 KeyStore,然后将其用于创建和初始化TrustManager 。 TrustManager是什么系统用来验证从服务器传递过来的证书的,通过创建一个包含一个或者多个那些可被TrustManage 信任的CA的 KeyStore。

Given the new TrustManager, the example initializes a new SSLContext which provides an SSLSocketFactory you can use to override the default SSLSocketFactory from HttpsURLConnection. This way the connection will use your CAs for certificate validation.
鉴于新建一个 TrustManager ,该示例初始化一个新的 SSLContext,它提供了一个SSLSocketFactory ,你可以用 SSLSocketFactory 来替代HttpsURLConnection 的默认的 SSLSocketFactory。 通过这种方式,连接将使用您的CA来进行证书验证。

Here is the example in full using an organizational CA from the University of Washington:
下面是使用来自华盛顿大学的组织CA的例子:

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

With a custom TrustManager that knows about your CAs, the system is able to validate that your server certificate come from a trusted issuer.
用知道你的CA的自定义TrustManager,系统就能够验证来自受信任的发布者颁发的服务器证书了。

Caution: Many web sites describe a poor alternative solution which is to install a TrustManager that does nothing. If you do this you might as well not be encrypting your communication, because anyone can attack your users at a public Wi-Fi hotspot by using DNS tricks to send your users’ traffic through a proxy of their own that pretends to be your server. The attacker can then record passwords and other personal data. This works because the attacker can generate a certificate and—without a TrustManager that actually validates that the certificate comes from a trusted source—your app could be talking to anyone. So don’t do this, not even temporarily. You can always make your app trust the issuer of the server’s certificate, so just do it.

Self-signed server certificate

The second case of SSLHandshakeException is due to a self-signed certificate, which means the server is behaving as its own CA. This is similar to an unknown certificate authority, so you can use the same approach from the previous section.
第二种导致 SSLHandshakeException 的原因是自签名的证书,这意味着该服务器作为自己的CA. 这类似于一个未知的证书颁发机构,这样你就可以使用上一节相同的方法。

You can create your own TrustManager, this time trusting the server certificate directly. This has all of the downsides discussed earlier of tying your app directly to a certificate, but can be done securely. However, you should be careful to make sure your self-signed certificate has a reasonably strong key. As of 2012, a 2048-bit RSA signature with an exponent of 65537 expiring yearly is acceptable. When rotating keys, you should check for recommendations from an authority (such as NIST) about what is acceptable.
你可以创建自己TrustManager ,这一次直接信任的服务器证书。 这样有所有上面讨论的直接捆绑证书到您的应用程序的缺点,但是是安全的。 然而,你应该小心确保您的自签名证书具有相当强壮的密钥。 截至2012年,2048位RSA签名的65537指数每年到期是可以接受的。 当切换钥匙的时候,你应该从权威机构(如NIST)检查什么样的密钥是可以用的。

Missing intermediate certificate authority

The third case of SSLHandshakeException occurs due to a missing intermediate CA. Most public CAs don’t sign server certificates directly. Instead, they use their main CA certificate, referred to as the root CA, to sign intermediate CAs. They do this so the root CA can be stored offline to reduce risk of compromise. However, operating systems like Android typically trust only root CAs directly, which leaves a short gap of trust between the server certificate—signed by the intermediate CA—and the certificate verifier, which knows the root CA. To solve this, the server doesn’t send the client only it’s certificate during the SSL handshake, but a chain of certificates from the server CA through any intermediates necessary to reach a trusted root CA.

To see what this looks like in practice, here’s the mail.google.com certificate chain as viewed by the openssl s_client command:

$ openssl s_client -connect mail.google.com:443
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=mail.google.com
   i:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
 1 s:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
---

This shows that the server sends a certificate for mail.google.com issued by the Thawte SGC CA, which is an intermediate CA, and a second certificate for the Thawte SGC CA issued by a Verisign CA, which is the primary CA that’s trusted by Android.

However, it is not uncommon to configure a server to not include the necessary intermediate CA. For example, here is a server that can cause an error in Android browsers and exceptions in Android apps:

$ openssl s_client -connect egov.uscis.gov:443
---
Certificate chain
 0 s:/C=US/ST=District Of Columbia/L=Washington/O=U.S. Department of Homeland Security/OU=United States Citizenship and Immigration Services/OU=Terms of use at www.verisign.com/rpa (c)05/CN=egov.uscis.gov
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 International Server CA - G3
---

What is interesting to note here is that visiting this server in most desktop browsers does not cause an error like a completely unknown CA or self-signed server certificate would cause. This is because most desktop browsers cache trusted intermediate CAs over time. Once a browser has visited and learned about an intermediate CA from one site, it won’t need to have the intermediate CA included in the certificate chain the next time.

Some sites do this intentionally for secondary web servers used to serve resources. For example, they might have their main HTML page served by a server with a full certificate chain, but have servers for resources such as images, CSS, or JavaScript not include the CA, presumably to save bandwidth. Unfortunately, sometimes these servers might be providing a web service you are trying to call from your Android app, which is not as forgiving.

There are two approaches to solve this issue:

  • Configure the server to include the intermediate CA in the server chain. Most CAs provide documentation on how to do this for all common web servers. This is the only approach if you need the site to work with default Android browsers at least through Android 4.2.
  • Or,treat the intermediate CA like any other unknown CA, and create a TrustManager to trust it directly, as done in the previous two sections.

Common Problems with Hostname Verification


As mentioned at the beginning of this article, there are two key parts to verifying an SSL connection. The first is to verify the certificate is from a trusted source, which was the focus of the previous section. The focus of this section is the second part: making sure the server you are talking to presents the right certificate. When it doesn’t, you’ll typically see an error like this:
正如在本文的开头,有两个关键部分验证SSL连接。 首先是验证证书是否来自可信机构,这是上一节的焦点。 本节的重点是第二部分:确保你所连接到的服务器使用的正确的证书。 如果不是这样,你通常会看到这样的错误:

java.io.IOException: Hostname ‘example.com’ was not verified
at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

One reason this can happen is due to a server configuration error. The server is configured with a certificate that does not have a subject or subject alternative name fields that match the server you are trying to reach. It is possible to have one certificate be used with many different servers. For example, looking at the google.com certificate with openssl s_client -connect google.com:443 | openssl x509 -text you can see that a subject that supports .google.com but also subject alternative names for .youtube.com, *.android.com, and others. The error occurs only when the server name you are connecting to isn’t listed by the certificate as acceptable.

Unfortunately this can happen for another reason as well: virtual hosting. When sharing a server for more than one hostname with HTTP, the web server can tell from the HTTP/1.1 request which target hostname the client is looking for. Unfortunately this is complicated with HTTPS, because the server has to know which certificate to return before it sees the HTTP request. To address this problem, newer versions of SSL, specifically TLSv.1.0 and later, support Server Name Indication (SNI), which allows the SSL client to specify the intended hostname to the server so the proper certificate can be returned.

Fortunately, HttpsURLConnection supports SNI since Android 2.3. Unfortunately, Apache HTTP Client does not, which is one of the many reasons we discourage its use. One workaround if you need to support Android 2.2 (and older) or Apache HTTP Client is to set up an alternative virtual host on a unique port so that it’s unambiguous which server certificate to return.

The more drastic alternative is to replace HostnameVerifier with one that uses not the hostname of your virtual host, but the one returned by the server by default.

Caution: Replacing HostnameVerifier can be very dangerous if the other virtual host is not under your control, because a man-in-the-middle attack could direct traffic to another server without your knowledge.

If you are still sure you want to override hostname verification, here is an example that replaces the verifier for a single URLConnection with one that still verifies that the hostname is at least on expected by the app:

// Create an HostnameVerifier that hardwires the expected hostname.
// Note that is different than the URL's hostname:
// example.com versus example.org
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        HostnameVerifier hv =
            HttpsURLConnection.getDefaultHostnameVerifier();
        return hv.verify("example.com", session);
    }
};

// Tell the URLConnection to use our HostnameVerifier
URL url = new URL("https://example.org/");
HttpsURLConnection urlConnection =
    (HttpsURLConnection)url.openConnection();
urlConnection.setHostnameVerifier(hostnameVerifier);
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);

But remember, if you find yourself replacing hostname verification, especially due to virtual hosting, it’s still very dangerous if the other virtual host is not under your control and you should find an alternative hosting arrangement that avoids this issue.

Warnings About Using SSLSocket Directly


So far, the examples have focused on HTTPS using HttpsURLConnection. Sometimes apps need to use SSL separate from HTTP. For example, an email app might use SSL variants of SMTP, POP3, or IMAP. In those cases, the app would want to use SSLSocket directly, much the same way that HttpsURLConnection does internally.

The techniques described so far to deal with certificate verification issues also apply to SSLSocket. In fact, when using a custom TrustManager, what is passed to HttpsURLConnection is an SSLSocketFactory. So if you need to use a custom TrustManager with an SSLSocket, follow the same steps and use that SSLSocketFactory to create your SSLSocket.

Caution: SSLSocket does not perform hostname verification. It is up the your app to do its own hostname verification, preferably by calling getDefaultHostnameVerifier() with the expected hostname. Further beware that HostnameVerifier.verify() doesn’t throw an exception on error but instead returns a boolean result that you must explicitly check.

Here is an example showing how you can do this. It shows that when connecting to gmail.com port 443 without SNI support, you’ll receive a certificate for mail.google.com. This is expected in this case, so check to make sure that the certificate is indeed for mail.google.com:

// Open SSLSocket directly to gmail.com
SocketFactory sf = SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sf.createSocket("gmail.com", 443);
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
SSLSession s = socket.getSession();

// Verify that the certicate hostname is for mail.google.com
// This is due to lack of SNI support in the current SSLSocket.
if (!hv.verify("mail.google.com", s)) {
    throw new SSLHandshakeException("Expected mail.google.com, "
                                    "found " + s.getPeerPrincipal());
}

// At this point SSLSocket performed certificate verificaiton and
// we have performed hostname verification, so it is safe to proceed.

// ... use socket ...
socket.close();

Blacklisting


SSL relies heavily on CAs to issue certificates to only the properly verified owners of servers and domains. In rare cases, CAs are either tricked or, in the case of Comodo or DigiNotar, breached, resulting in the certificates for a hostname to be issued to someone other than the owner of the server or domain.

In order to mitigate this risk, Android has the ability to blacklist certain certificates or even whole CAs. While this list was historically built into the operating system, starting in Android 4.2 this list can be remotely updated to deal with future compromises.

Pinning


An app can further protect itself from fraudulently issued certificates by a technique known as pinning. This is basically using the example provided in the unknown CA case above to restrict an app’s trusted CAs to a small set known to be used by the app’s servers. This prevents the compromise of one of the other 100+ CAs in the system from resulting in a breach of the apps secure channel.

Client Certificates


This article has focused on the user of SSL to secure communications with servers. SSL also supports the notion of client certificates that allow the server to validate the identity of a client. While beyond the scope of this article, the techniques involved are similar to specifying a custom TrustManager. See the discussion about creating a custom KeyManager in the documentation for HttpsURLConnection.

Nogotofail: A Network Traffic Security Testing Tool


Nogotofail is a tool gives you an easy way to confirm that your apps are safe against known TLS/SSL vulnerabilities and misconfigurations. It’s an automated, powerful, and scalable tool for testing network security issues on any device whose network traffic could be made to go through it.
Nogotofail是一个安全验证工具,给你一个简单的方法来确认您的应用程序是在防范已知TLS / SSL漏洞和错误配置方面是否安全。这是一个自动化的,强大的,可扩展的工具,用于测试任何网络流量要经​​过它的设备的网络安全问题。

Nogotofail is useful for three main use cases:
Nogotofail有一下三个主要的作用:

  • Finding bugs and vulnerabilities.
  • Verifying fixes and watching for regressions.
  • Understanding what applications and devices are generating what traffic.

Nogotofail works for Android, iOS, Linux, Windows, Chrome OS, OSX, in fact any device you use to connect to the Internet. There’s an easy-to-use client to configure the settings and get notifications on Android and Linux, as well as the attack engine itself which can be deployed as a router, VPN server, or proxy.

You can access the tool at the Nogotofail open source project.

It seems like you are experiencing an issue with pip being configured with locations that require TLS/SSL. This error usually occurs when pip is unable to establish a secure connection to the server. To resolve this issue, you can try the following steps: 1. Update pip: Make sure you have the latest version of pip installed by running the following command: ``` pip install --upgrade pip ``` 2. Check your internet connection: Ensure that you have a stable internet connection and try again. 3. Verify your SSL certificate: Ensure that your SSL certificate is valid and not expired. You can check this by opening a secure website in your browser. 4. Set the SSL certificate path: If you have a custom SSL certificate, you can set the path to it using the `REQUESTS_CA_BUNDLE` environment variable. Here's an example: ``` export REQUESTS_CA_BUNDLE=/path/to/certificate.crt ``` 5. Use a different mirror: Try using a different mirror to download packages. You can specify a mirror using the `-i` flag followed by the mirror URL. For example: ``` pip install -i https://pypi.org/simple package_name ``` 6. Disable SSL verification (not recommended): If none of the above solutions work and you're confident about the security of your network, you can disable SSL verification temporarily. However, this is not recommended as it poses security risks. To disable SSL verification, use the `--trusted-host` flag followed by the package server URL. For example: ``` pip install --trusted-host pypi.python.org package_name ``` If none of these solutions resolve the issue, please provide more details about your environment and any error messages you are receiving so that I can assist you further.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值