【问题标题】:SSL Pinning With VolleySSL Pinning 与 Volley
【发布时间】:2017-07-26 00:47:14
【问题描述】:

我编写了一个通用的 GsonRequest 类,通过扩展 Volley 的请求来获取和解析来自服务器的 JSON 数据。我的 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 调用中。 我无法将它开箱即用地添加到 Volley 的 Request 类中。 在这篇博客http://blog.ostorlab.co/2016/05/ssl-pinning-in-android-networking.html 中,他们解释了如何在 Volley 中添加 SSL Pinning。但他们已将其添加到 RequestQueue 中。但是我已经实现了 Volley 的 Request 类。有人用 Request 类而不是 RequestQueue 破解了它,或者我需要单独调用 API 来验证证书。

【问题讨论】:

    标签: android ssl ssl-certificate android-volley


    【解决方案1】:

    据我所知,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);

    【讨论】:

    • 无需在 Manifest 中添加任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 2014-03-30
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    相关资源
    最近更新 更多