SSL与Volley固定

时间:2017-03-06 08:22:39

标签: android ssl ssl-certificate android-volley

我通过扩展Request of Volley来获取和解析来自server的JSON数据,编写了一个通用的GsonRequest类。我的Volley请求的泛型类如下:

public class GsonRequest<T> extends Request<T> {
    private final Gson gson = new Gson();
    private final Class<T> clazz;
    private final Map<String, String> headers;
    private final Listener<T> listener;

    /**
     * Make a GET request and return a parsed object from JSON. Assumes
     * {@link Method#GET}.
     * 
     * @param url
     *            URL of the request to make
     * @param clazz
     *            Relevant class object, for Gson's reflection
     * @param headers
     *            Map of request headers
     */
    public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, Listener<T> listener, ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.clazz = clazz;
        this.headers = headers;
        this.listener = listener;
    }

    /**
     * Like the other, but allows you to specify which {@link Method} you want.
     * 
     * @param method
     * @param url
     * @param clazz
     * @param headers
     * @param listener
     * @param errorListener
     */
    public GsonRequest(int method, String url, Class<T> clazz, Map<String, String> headers, Listener<T> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.clazz = clazz;
        this.headers = headers;
        this.listener = listener;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return headers != null ? headers : super.getHeaders();
    }

    @Override
    protected void deliverResponse(T response) {
        listener.onResponse(response);
    }

    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }
}

现在我想从我的应用程序添加SSL Pinning到我的所有API调用。 我无法将它从开箱即用的Feed类中添加到Volley中。 在此博客http://blog.ostorlab.co/2016/05/ssl-pinning-in-android-networking.html中,他们已经解释了如何在Volley中添加SSL Pinning。但是他们在RequestQueue中添加了它。但是我已经实现了Volley的Request类。任何人都使用Request类而不是RequestQueue破解它或者我需要进行单独的API调用来验证证书。

1 个答案:

答案 0 :(得分:2)

据我所知,Volley是一个功能强大的网络库,文档非常有限。

不知怎的,我找到了我想要的答案,希望这会对某人有所帮助。

private RequestQueue getPinnedRequestQueue(Context context) throws CertificateException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

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

    // Generate the certificate using the certificate file under res/raw/cert.cer
    InputStream caInput = new BufferedInputStream(context.getResources().openRawResource(R.raw.your_ssl_cert));
    final Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

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

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

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

    SSLSocketFactory sf = sslContext.getSocketFactory();

    HurlStack hurlStack = new HurlStack(null, sf) {
        @Override
        protected HttpURLConnection createConnection(URL url) throws IOException {
            LogUtil.info(TAG, "Before createConnection");
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);
            LogUtil.info(TAG, "After createConnection");
            httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {

                @DebugLog
                @Override
                public boolean verify(String hostName, SSLSession sslSession) {
                    String certificateDomainName = ((X509Certificate) ca).getSubjectDN().toString();
                    LogUtil.info(TAG, "Index : " + certificateDomainName.indexOf("CN=") + " Len : " + certificateDomainName.codePointCount(certificateDomainName.indexOf("CN="), certificateDomainName.indexOf(",")));
                    String certificateName = certificateDomainName.substring(certificateDomainName.indexOf("CN="), certificateDomainName.codePointCount(certificateDomainName.indexOf("CN="), certificateDomainName.indexOf(",")));
                    certificateName = certificateName.replace("CN=", "");
                    LogUtil.info(TAG, "hostName : " + hostName + " certificateName : " + certificateName);
                    if (certificateName.isEmpty())
                        return false;
                    return certificateName.equals(hostName);
                }
            });
            return httpsURLConnection;
        }
    };

    return new Volley().newRequestQueue(context, hurlStack);
}

而不是使用requestQueue = new Volley().newRequestQueue(context);

使用requestQueue = getPinnedRequestQueue(context);