Android 中的安全 HTTP Post

Posted

技术标签:

【中文标题】Android 中的安全 HTTP Post【英文标题】:Secure HTTP Post in Android 【发布时间】:2011-01-16 05:16:59 【问题描述】:

我有一个非常基本的帮助程序类,我用它来完成我所有的 Http Get/Post 工作。我正在使用 org.apache.http 库中的 HttpGet、HttpPost 和 HttpClient。我所有的东西都可以通过 HTTP 正常工作,但是一旦我尝试使用通过 HTTPS 工作的服务,执行请求时就会收到 ClientProtocolException。异常中的唯一消息是“服务器未能以有效的 HTTP 响应进行响应”。

为了进行测试,我使用简单的 html 表单从浏览器发送了完全相同的有效负载,并使用 RequestBuilder 发送了 Fiddler2。我已经发送了无效的和空的有效载荷,甚至发送了带有和不带有标头的所有上述内容,以查看对象构建请求的方式是否有问题。

我在测试中使用的所有东西都会给我一个有效的 200 状态 HTTP 响应。如果我给它提供的东西不是它所期望的,该服务只会给我一个描述错误的结构。

我需要向 HttpPost 或 HttpClient 对象添加什么特别的东西来告诉它使用 HTTPS 吗?我必须明确告诉它使用不同的端口吗?

编辑:

我确实为 https 通信注册了错误的套接字工厂。这是我用来创建具有正确套接字工厂的 HttpClient 对象的更新方法,以防将来有人搜索此类问题:

private HttpClient createHttpClient()

    HttpParams params = new BasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true);

    SchemeRegistry schReg = new SchemeRegistry();
    schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);

    return new DefaultHttpClient(conMgr, params);

【问题讨论】:

嗨,Rich,感谢您的帖子,这几乎是谷歌返回的关于 android 上的 https 的唯一内容。您从哪里获得信息来编写您在此处显示的代码?另外,你能解释一下调用 set version、charset 和那个参数的原因吗?他们不是默认分配正常值吗?还有一个问题:您正在导入 org.apache.http.conn.ssl.SSLSocketFactory ,对吗?感谢您清除此问题 我很确定这来自 Apress 上的 Pro Android 书籍。这本书不是很好,但是关于 http 通信的章节对应用程序需要进行大量网络调用时的实用设计进行了很好的讨论。 【参考方案1】:

我不确定您为什么不能处理 HTTPS。我为自己的应用程序编写了一个帮助程序类,并且能够毫无问题地 GET/POST 到 HTTPS。我会把代码贴在这里,也许你可以看看我的代码和你的代码之间是否存在差异。

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.util.Log;

public class HttpRequest

    DefaultHttpClient httpClient;
    HttpContext localContext;
    private String ret;

    HttpResponse response = null;
    HttpPost httpPost = null;
    HttpGet httpGet = null;

    public HttpRequest()
        HttpParams myParams = new BasicHttpParams();

        HttpConnectionParams.setConnectionTimeout(myParams, 10000);
        HttpConnectionParams.setSoTimeout(myParams, 10000);
        httpClient = new DefaultHttpClient(myParams);       
        localContext = new BasicHttpContext();    
    

    public void clearCookies() 
        httpClient.getCookieStore().clear();
    

    public void abort() 
        try 
            if (httpClient != null) 
                System.out.println("Abort.");
                httpPost.abort();
            
         catch (Exception e) 
            System.out.println("Your App Name Here" + e);
        
    

    public String sendPost(String url, String data) 
        return sendPost(url, data, null);
    

    public String sendJSONPost(String url, JSONObject data) 
        return sendPost(url, data.toString(), "application/json");
    

    public String sendPost(String url, String data, String contentType) 
        ret = null;

        httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);

        httpPost = new HttpPost(url);
        response = null;

        StringEntity tmp = null;        

        Log.d("Your App Name Here", "Setting httpPost headers");

        httpPost.setHeader("User-Agent", "SET YOUR USER AGENT STRING HERE");
        httpPost.setHeader("Accept", "text/html,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");

        if (contentType != null) 
            httpPost.setHeader("Content-Type", contentType);
         else 
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
        

        try 
            tmp = new StringEntity(data,"UTF-8");
         catch (UnsupportedEncodingException e) 
            Log.e("Your App Name Here", "HttpUtils : UnsupportedEncodingException : "+e);
        

        httpPost.setEntity(tmp);

        Log.d("Your App Name Here", url + "?" + data);

        try 
            response = httpClient.execute(httpPost,localContext);

            if (response != null) 
                ret = EntityUtils.toString(response.getEntity());
            
         catch (Exception e) 
            Log.e("Your App Name Here", "HttpUtils: " + e);
        

        Log.d("Your App Name Here", "Returning value:" + ret);

        return ret;
    

    public String sendGet(String url) 
        httpGet = new HttpGet(url);  

        try 
            response = httpClient.execute(httpGet);  
         catch (Exception e) 
            Log.e("Your App Name Here", e.getMessage());
        

        //int status = response.getStatusLine().getStatusCode();  

        // we assume that the response body contains the error message  
        try 
            ret = EntityUtils.toString(response.getEntity());  
         catch (IOException e) 
            Log.e("Your App Name Here", e.getMessage());
        

        return ret;
    

    public InputStream getHttpStream(String urlString) throws IOException 
        InputStream in = null;
        int response = -1;

        URL url = new URL(urlString); 
        URLConnection conn = url.openConnection();

        if (!(conn instanceof HttpURLConnection))                     
            throw new IOException("Not an HTTP connection");

        try
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect(); 

            response = httpConn.getResponseCode();                 

            if (response == HttpURLConnection.HTTP_OK) 
                in = httpConn.getInputStream();                                 
                                 
         catch (Exception e) 
            throw new IOException("Error connecting");            
         // end try-catch

        return in;     
    

【讨论】:

谢谢。我自己的代码中有一个错误,用于创建我的 HttpClient 对象(上面发布) @MattC,我没有看到您明确定义在哪里使用 Https 或端口 443...我错过了什么吗?这看起来像一个普通的 HTTP 连接.. @DoctorOreo 我已经很久没有看过那个代码了。我确实记得它正确处理了 HTTPS,但从那时起框架已经发生了很大变化,所以我必须回去验证。抱歉,我无法提供更多帮助。【参考方案2】:

由于有些方法已经被弃用,不应该是这样吗?

  private DefaultHttpClient createHttpClient() 
    HttpParams params = new BasicHttpParams();

    HttpConnectionParams.setConnectionTimeout(params, 10000);
    HttpConnectionParams.setSoTimeout(params, 10000);
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
    HttpProtocolParams.setUseExpectContinue(params, true);

    SchemeRegistry schReg = new SchemeRegistry();
    schReg.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    schReg.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory()));
    ClientConnectionManager conMgr = new PoolingClientConnectionManager(schReg);

    return new DefaultHttpClient(conMgr, params);
  

我是否应该更改其他任何内容,例如 HttpVersion?

【讨论】:

是的。这是两年前发布的,但现在 AndroidHttpClient.newInstance 基本上做了同样的事情

以上是关于Android 中的安全 HTTP Post的主要内容,如果未能解决你的问题,请参考以下文章

如何为小于 24 的 API 添加 Android 网络安全配置

Android安全-数据安全1-代码中的字符串安全

132Android安全机制 Android Permission权限控制机制(转载)

Android安全测试之BurpSuite抓包

关于Android应用开发的一些安全注意事项

Android安全机制