Android HttpClient Digest Authentication Authoriza

2019-05-30 14:56发布

问题:

We try to send several requests to target server in one HttpClient (one session). The target server will first authenticate all requests with digest authentication (based on MD5-sess). The result shows that only first access is successful. The following accesses are rejected by server because server treats later accesses as replay attack as the "nc" value is always "00000001".

It seems Android HttpClient hard-coded digest authorization header attirbute "nc" to "00000001"?

Any way for client to increase this value when new request is sent? Thanks.

public class HttpService {

private static final HttpService instance = new HttpService();
private HttpService() {
    client = getHttpClient();
}

public static HttpService getInstance() {
    return instance;
}

private DefaultHttpClient getHttpClient() {
    HttpParams params = new BasicHttpParams();
    HttpConnectionParams.setStaleCheckingEnabled(params, false);
    HttpConnectionParams.setConnectionTimeout(params, 15 * 1000);
    HttpConnectionParams.setSoTimeout(params, 15 * 1000);
    HttpConnectionParams.setSocketBufferSize(params, 8192);
    HttpProtocolParams.setUserAgent(params, USER_AGENT);

    SchemeRegistry schemeRegistry = new SchemeRegistry();
    Scheme httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
    Scheme httpsScheme = new Scheme("https", SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, null), 443);
    schemeRegistry.register(httpScheme);
    schemeRegistry.register(httpsScheme);
    ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);

    //create client
    DefaultHttpClient httpClient = new DefaultHttpClient(manager, params);

    httpClient.getCredentialsProvider().setCredentials(new AuthScope(address, port),
                new UsernamePasswordCredentials(username, password));
}

}

回答1:

Android ships with an extremely outdated (pre-BETA) fork of Apache HttpClient. There has been a countless number of changes in the stock version of HttpClient since 4.0 ALPHA, also in the Digest auth area.

The best thing you can do is to copy the DigestScheme from the stock version of Apache HttpClient and configure your application to use the copy instead of the default implementation.

http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java

For that end you will have to register a custom DigestSchemeFactory instance with the auth scheme registry.

http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestSchemeFactory.java



回答2:

It seems you are right. This is from Digest.java:

//TODO: supply a real nonce-count, currently a server will interprete a repeated request as a replay
private static final String NC = "00000001"; //nonce-count is always 1

You should file a bug at http://b.android.com. You have a few options:

  • calculate the digest and create the header yourself, then set it on every request. You could add a HttpRequestInterceptor to make this authomatic (don't set the credentials to the credential provider)
  • AFAIK authentication schemes should be pluggable, so implement digest auth properly and configure your client to use it.
  • use another HTTP client library.

EDIT: Since it's fixed in the stock version, there is another alternative:

Another alternative:

  • change the Apache HttpClient package name using jarjar, package it with the app, and don't use the Android system one at all.