Android:如何使用证书进行HttpPost

时间:2014-03-30 13:25:37

标签: android paypal http-post

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

现在我需要在接收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);

5 个答案:

答案 0 :(得分:3)

这是因为Android应用程序不接受服务器提供的安全证书。有时您可能已经看到浏览器要求允许继续说"网站的安全证书不受信任!"。同样的事情在android中产生异常。因此,您必须要求应用程序接受服务器提供的任何安全证书。这是怎么做的。 http://madurangasblogs.blogspot.com/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html

但我必须告诉你,这对于生产应用来说不是一个好习惯。这违反了获得安全证书的目的。

此外,请尝试这样的事情(您需要让套接字工厂使用此默认信任管理器):

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;
    }
}

来源: http://android.bigresource.com/Android-Issues-with-httppost-Authentication-challenge-is-empty-Gg4BTT7Dr.html Get the authentication from the moodle for a android application

答案 1 :(得分:1)

你可能面临像Java这样的平台上最复杂但最复杂的事情之一,因此也是Android。事实证明,没有一种直接的方法可以实现这一点,因为有很多种证书,并且没有一种方法可以对所有证书进行HTTP调用,因为其中一些可能是由未知的CA签署的,其他的为了使证书有效等,需要中间捆绑

可能有一种方法可以帮助您将证书存储到用户的密钥库中,这样您就可以发出HTTPS请求,因为他们已经信任目标SSL证书。在这种情况下,您将创建一个新的KeyStore,导入证书,然后发出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 (US)的绿色文字(宣布该网站有SSL证书)。

first

你会看到这样一个屏幕:

second

点击More information按钮,您会看到以下内容:

third

点击See certificate(或类似)按钮,现在您将看到此屏幕:

forth

点击列表中的Details标签,逐个选择网站(在这种情况下,首先是VeriSign Class 3 Public Primary Certification Authority - g5,然后是VeriSign Class 3 Extended Validation SSL CA,最后是www.paypal.com),然后,点击该屏幕底部的Export...。系统会要求您导出PEM证书。

您刚刚完成的是导出整个证书链,但现在您必须将它们全部放在一起。只需打开一个文本文件,然后按照您下载的顺序依次附加您刚刚下载的三个证书,并特别注意不包含其他空格

这是您必须在代码中导入的证书。在我收录的代码段中,您需要将路径放到文件中,就是这样。由于您可能希望为所有客户端包含该代码,因此您可能会做两件事:

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

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

答案 2 :(得分:0)

好的,您需要做的是将服务器的证书链导入您的应用程序。

首先,您必须下载整个证书链。您可以使用任何Web浏览器执行此操作。假设你有chrome:

现在,您拥有证书,必须将它们放入密钥库。我建议你使用BKS密钥库,因为它在内部得到了android的支持。

  • 下载bouncycastle。请务必使用1.46版本,因为这是Android使用的版本。 I used this one.
  • 使用此命令导入密钥:(密码在此处无关紧要,因为我们只使用密钥库来存储密钥)

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

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

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来完成此操作的详细教程,因此您不必使用该复杂的构造函数。

http://transoceanic.blogspot.hu/2011/11/android-import-ssl-certificate-and-use.html

答案 3 :(得分:0)

您需要告诉SSLSocketFactory(org.apache.http,而不是javax)关于您的密钥库,并配置您的DefaultHTTPClient以将其用于https连接。

我猜thisthis可以提供帮助。

答案 4 :(得分:-1)

所有的拳头,你把你的userId和密码放在上面的代码中,这很危险!! (改变它,如果它不是假的!)

其次请提供一些日志信息以获得更好的帮助!

PayPal证书是有效证书,这意味着您无需在申请中嵌入证书。 只是一些建议:

1-您可以使用android-async-http库,因为它非常灵活并且有很多选项。

2-我不熟悉PayPal,但你绝对应该使用PayPal REST API