Android:如何使用证书进行HttpPost

Android:如何使用证书进行HttpPost,android,paypal,http-post,Android,Paypal,Http Post,我有一个执行HttpPost的应用程序 现在,我需要向post添加一个证书,以便接收HttpPost的服务器接受该证书 请问我该怎么办? 非常感谢您的任何建议 HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("https://svcs.sandbox.paypal.com/AdaptivePayments/Preapproval"); try {

我有一个执行HttpPost的应用程序

现在,我需要向post添加一个证书,以便接收HttpPost的服务器接受该证书

请问我该怎么办?

非常感谢您的任何建议

HttpClient httpclient = new DefaultHttpClient();

    HttpPost httppost = new HttpPost("https://svcs.sandbox.paypal.com/AdaptivePayments/Preapproval");
    try {

        httppost.addHeader("X-PAYPAL-SECURITY-USERID", "maurizio.pietrantuono_api1.db.com");
        httppost.addHeader("X-PAYPAL-SECURITY-PASSWORD", "1395657583");
        httppost.addHeader("X-PAYPAL-SECURITY-SIGNATURE", "A0GgTivJ6ivBB8QDTl.cZfiYK5d9AZwsFixwIUdUhJc4JXTriwpfU2zw");
        httppost.addHeader("X-PAYPAL-REQUEST-DATA-FORMAT", "NV");
        httppost.addHeader("X-PAYPAL-RESPONSE-DATA-FORMAT", "NV");
        httppost.addHeader("X-PAYPAL-APPLICATION-ID", "APP-80W284485P519543T");

        StringEntity se=new StringEntity("cancelUrl=http://your_cancel_url"+
"&currencyCode=USD"+
"&endingDate=2015-03-29T08%3A00%3A00.000Z"+
"&maxAmountPerPayment=200.00"+
"&maxNumberOfPayments=30"+
"&maxTotalAmountOfAllPayments=1500.00"+
"&pinType=NOT_REQUIRED"+
"&requestEnvelope.errorLanguage=en_US"+
"&returnUrl=http://www.google.com"+
"&startingDate=2014-04-29T07%3A00%3A00.000Z"+
"&senderEmail=mauriziop-facilitator@hotmail.it");
        httppost.setEntity(se);

        HttpResponse response = httpclient.execute(httppost);

在Java和Android这样的平台上,您可能面临着最合乎逻辑但最复杂的事情之一。事实证明,没有一种简单直接的方法可以实现这一点,因为有很多种类的证书,也没有一种方法可以对所有证书进行HTTP调用,因为其中一些证书可能由未知的CA签名,其他证书需要中间包才能使证书有效,等等

可能有一种方法可以帮助您将证书存储到用户的密钥库中,这样您就可以发出HTTPS请求,因为他们已经信任目标SSL证书。在这种情况下,您将创建一个新的
密钥库
,导入证书,然后发出HTTPS请求:

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

// Some of these exist in more than one package, be careful to include these
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

// This would reference to your KeyStore to store the certificate
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);             // This will make a new store
// In the next line, specify the file path
// You can also export the destination certificate (in your case, Paypal's)
// put it as a hardcoded `String` and work with it.
InputStream is = ...;
BufferedInputStream bis = new BufferedInputStream(is);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

while (bis.available() > 0) {
  Certificate cert = cf.generateCertificate(bis);
  trustStore.setCertificateEntry("myAlias" + bis.available(), cert);
}
之后,应该可以向SSL服务器发出HTTP请求

----编辑---

您不需要为站点生成证书,因为该站点已经有了证书。您必须导入其已存在的证书。我给你展示了一个如何做的例子,它是在Firefox和西班牙语下完成的,但我想你会用你的语言推断出关键词

转到要导出其证书的站点。在这个例子中,我正在做
Paypal
,但是你可以为任何站点做。还要考虑到一个站点可能有许多证书,这意味着,例如,
https://www.paypal.com
有一个和
https://sandbox.paypal.com
还有另一种完全不同的方法。你需要检查一下这个

在地址栏的左侧,单击绿色文本,上面写着
Paypal,Inc(美国)
(宣布该站点拥有SSL证书)

您将看到如下屏幕:

单击
更多信息
按钮,您将看到如下内容:

单击
查看证书
(或类似)按钮,现在您将看到此屏幕:

单击
详细信息
选项卡,在列表中逐个选择站点(在本例中,首先是
VeriSign Class 3公共初级认证机构-g5
,然后是
VeriSign Class 3扩展验证SSL CA
,最后是
www.paypal.com
),然后,单击该屏幕底部的
Export…
。您将被要求导出
PEM
证书

您刚才所做的是导出整个证书链,但现在必须将其全部放在一起。只需打开一个文本文件,将刚下载的三个证书按下载顺序依次添加到,并特别注意不要添加额外的空格

这是您必须在代码中导入的证书。在我包含的代码片段中,有一个地方需要放置文件的路径,就是这个。由于您可能希望为所有客户机包含该代码,您可能需要做两件事:

  • 将证书作为项目的一部分导入。这将使运行您的应用程序的任何客户端都将拥有该证书,这样您就可以使用上面的代码而无需任何修改,但当Paypal更改该证书时,您需要小心(它们通常在一段时间后过期,需要替换为新的有效证书-您可以在证书的属性中看到证书的过期时间)

  • 如上所述导出证书,将其放在公共场所(例如,web服务器)每次用户运行你的应用程序时,下载它并验证密钥库中的证书是否与你刚刚读取的证书相同。如果它不存在,只需第一次导入它。如果它存在且不匹配,则更新它。否则,你不需要做任何事


好的,那么您要做的就是将服务器的证书链导入到您的应用程序中

首先,您必须下载整个证书链。您可以使用任何web浏览器进行下载。假设您有chrome:

  • 打开服务器URL “”
  • 单击URL左侧的锁定图标
  • 连接-->证书信息-->证书路径
  • 你必须下载所有这三个元素
既然你有了证书,你就必须把它们放进密钥库。我建议你使用BKS密钥库,因为它在android内部是受支持的

  • 下载bouncycastle。请务必使用1.46版本,因为Android使用的是1.46版本
  • 使用此命令导入密钥:(此处密码不重要,因为我们使用密钥库只是存储密钥)

    keytool-list-keystore“my_keystore_path/mykeystore.bks”-provider org.bouncycastle.jce.provider.BouncyCastleProvider-provider路径“provider_path/bcprov jdkxx xxx.jar”-storetype bks-storepass“my_password”

将密钥库添加到应用程序中。您可以将其放在资产中,甚至可以将其作为原始资源。 在此之后,您必须创建一个ClientConnectionmanager供您的HttpClient使用

public ClientConnectionManager createClientConnectionManager() {
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    // Register for port 443 our SSLSocketFactory with our keystore
    // to the ConnectionManager
    registry.register(new Scheme("https", newSslSocketFactory(), 443));
    return new SingleClientConnManager(getParams(), registry);
}

public SSLSocketFactory newSslSocketFactory() {
    try {
        // Get an instance of the Bouncy Castle KeyStore format
        KeyStore trusted = KeyStore.getInstance("BKS");
        // Get the raw resource, which contains the keystore with
        // your trusted certificates (root and any intermediate certs)
        InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
        try {
            // Initialize the keystore with the provided trusted certificates
            // Also provide the password of the keystore
            trusted.load(in, "my_password".toCharArray());
        } finally {
            in.close();
        }
        // Pass the keystore to the SSLSocketFactory. The factory is responsible
        // for the verification of the server certificate.
        SSLSocketFactory sf = new SSLSocketFactory(trusted);
        // Hostname verification from certificate
        // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
        sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
        return sf;
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}
并以这种方式使用它:

HttpClient c = new DefaultHttpClient(createClientConnectionManager(), new DefaultHttpClient().getParams());
请注意,如果使用此ClientConnectionManager,则只接受其整个证书路径位于密钥库中的站点。如果要通过此ClientConnectionManager与其他站点建立安全连接,则必须导入其他站点的证书

下面是关于如何通过扩展DefaultHttpClient来实现这一点的详细教程,这样您就不必使用那个复杂的构造函数


首先,你把你的用户名和密码放在上面的代码里,这是很危险的!!(如果不是假的话就修改!)

其次,请提供
X509TrustManager manager = null;
FileInputStream fs = null;

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

try
{
    fs = new FileInputStream(System.getProperty("javax.net.ssl.trustStore")); 
    keyStore.load(fs, null);
}
finally
{
    if (fs != null) { fs.close(); }
}

trustManagerFactory.init(keyStore);
TrustManager[] managers = trustManagerFactory.getTrustManagers();

for (TrustManager tm : managers)
{
    if (tm instanceof X509TrustManager) 
    {
        manager = (X509TrustManager) tm;
        break;
    }
}