AppCanOpenSource / appcan-android

appcan-android

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

html 页面中无法展示 https 的图片

yorkvolvo opened this issue · comments

问题描述

我在页面中设置 img src 属性的时候,如果图片设置成我们服务器的 https 链接,那么图片就不会显示。代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
	<title>Title Here</title>
	<script type="text/javascript"></script>
</head>
<body>

<div class="uwh-bg umar-r-ect uwh-bg-img" id="imgtest">
	<img class="upimg" id="imgtesta" src="https://172.28.1.209/image......" width="100px" height="100px"/>
</div>

</body>
</html>

不能正确显示来自服务器的图片:

image

我排查后发现这是 https 证书配置问题,错误日志:

I/X509Util: Failed to validate the certificate chain, error: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

页面中的 https 请求都是没问题的:

appcan.ajax({
            type:"POST",
            url:baseUrl+url,
            data:data
            offline:false,
            expire:1000,
            timeout : 30000,
            dataType: 'json',
            beforeSend:function(xhr){
            },
            success:function(ret,status,xhr){           
            },
           error:function(xhr,type){  
        }
     });

尝试的解决办法

我试着在修改引擎代码,不要去做证书校验,在 org.zywx.wbpalmstar.platform.certificates.Http 中忽略证书校验:

public class Http {

    public static HashMap<String, KeyStore> KEY_STORE = new HashMap<String, KeyStore>();
    public static String algorithm = "X509";
    public static String keyType = "pkcs12";
    /**
     * 是否检查https证书为可信机构颁发
     */
    private static boolean isCheckTrustCert = false;

    private static InputStream getInputStream(String cPath, Context ctx)
            throws IOException, FileNotFoundException {
        InputStream inStream;
        String assertFile = "file:///android_asset/";
        String sdcardFile = "/sdcard/";
        String wgtFile = "widget/";
        String file = "file://";
        if (cPath.contains(assertFile)) {
            cPath = cPath.substring(assertFile.length());
            AssetManager asset = ctx.getAssets();
            inStream = asset.open(cPath);
        } else if (cPath.contains(sdcardFile)) {
            if (cPath.contains(file)) {
                cPath = cPath.substring("file://".length());
            }
            inStream = new FileInputStream(cPath);
        } else if (cPath.startsWith(wgtFile)) {
            AssetManager asset = ctx.getAssets();
            inStream = asset.open(cPath);
        } else {
            inStream = new FileInputStream(cPath);
        }
        return inStream;
    }

    public static javax.net.ssl.SSLSocketFactory getSSLSocketFactoryWithCert(String cPassWord, String cPath, Context ctx) {
        Log.e("httptest", "httptest == getSSLSocketFactoryWithCert(String cPassWord, String cPath, Context ctx)");

        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        TrustManager[] tm = {new HX509TrustManager()};
        try {
            sslContext.init(null, tm, new java.security.SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslContext.getSocketFactory();
    }

    public static javax.net.ssl.SSLSocketFactory getSSLSocketFactory() {
        Log.e("httptest", "httptest == getSSLSocketFactory()");
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        TrustManager[] tm = {new HX509TrustManager()};
        try {
            sslContext.init(null, tm, new java.security.SecureRandom());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslContext.getSocketFactory();
    }

    public static HttpsURLConnection getHttpsURLConnection(URL url) throws Exception {
        Log.e("httptest", "httptest == getHttpsURLConnection(URL url)");
        HttpsURLConnection mConnection = null;
        mConnection = (HttpsURLConnection) url.openConnection();
        javax.net.ssl.SSLSocketFactory ssFact = null;
        ssFact = Http.getSSLSocketFactory();
        ((HttpsURLConnection) mConnection).setSSLSocketFactory(ssFact);
        if (!isCheckTrustCert()) {
            ((HttpsURLConnection) mConnection)
                    .setHostnameVerifier(new HX509HostnameVerifier());
        } else {
            ((HttpsURLConnection) mConnection)
                    .setHostnameVerifier(new HX509HostnameVerifier());
        }
        return mConnection;
    }

    public static HttpsURLConnection getHttpsURLConnection(String urlString) throws Exception {
        URL url=new URL(urlString);
        HttpsURLConnection mConnection = getHttpsURLConnection(url);
        return mConnection;
    }

    public static HttpsURLConnection getHttpsURLConnectionWithCert(URL url,
            String cPassWord, String cPath, Context ctx) throws Exception {
        HttpsURLConnection mConnection = null;
        mConnection = (HttpsURLConnection) url.openConnection();
        javax.net.ssl.SSLSocketFactory ssFact = null;
        ssFact = Http.getSSLSocketFactoryWithCert(cPassWord, cPath, ctx);
        ((HttpsURLConnection) mConnection).setSSLSocketFactory(ssFact);
        if (!isCheckTrustCert()) {
            ((HttpsURLConnection) mConnection)
                    .setHostnameVerifier(new HX509HostnameVerifier());
        } else {
            ((HttpsURLConnection) mConnection)
                    .setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
        }
        return mConnection;
    }

    public static boolean isCheckTrustCert() {
        return isCheckTrustCert;
    }

    public static void setCheckTrustCert(boolean isCheckTrustCert) {
        Http.isCheckTrustCert = isCheckTrustCert;
    }
}

但是这并没有解决我们的问题,我在网上搜索之后发现 appcan 类似的问题:https自定义证书如何能通过安全认证,但是也是一直没有解决。

可能的解决方案

网上搜索发现在 onReceivedSslError 方法中接受证书就可以解决问题。

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
        handler.proceed();
    }
});

问题

  1. 我该如何在 appcan 项目中配置 https 证书呢?

  2. 或者我该如何让我的 appcan 项目里全局请求网络的时候忽略校验证书呢?

PS:项目已整体迁移到 Android Studio 中了。

@sandy1108 , 能帮忙看下这个 issue 吗?

@sandy1108 , 能帮忙看下这个 issue 吗?

你的问题说的可真详细啊。你说的里面不是写了吗,onReceivedSslError这个方法改写一下就可以了。忽略证书校验后,对于一些安全检测的机构来说,这是不安全的。所以可能没有把这个代码合并到主干中。