【问题标题】:How to make a server request call from android secure like google api with sha1?如何使用 sha1 像 google api 一样从 android 安全地进行服务器请求调用?
【发布时间】:2018-02-07 06:04:59
【问题描述】:

我正在制作一个总是调用服务器来加载数据(JSON 数据)的应用程序。 像 google api 一样,我如何确保 POST 请求是否来自我的 android 应用程序。 如何确保这一点?

我总是向 php 服务器发送 POST 请求的代码如下所示

下面的代码发送了手机和密码等数据来登录 但是,如果有人从我的 android 应用程序中复制此内容并在他们的应用程序中使用。然后服务器将被黑。如何防止它只接受来自我的 android 应用程序而不是来自任何其他来源的 POST 请求。

StringRequest stringRequest = new StringRequest(Request.Method.POST, REQ_URL, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

            Toast.makeText(HomeActivity.this, "" + response , Toast.LENGTH_LONG).show();


        }

    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

            String message = null;
            if (error instanceof TimeoutError || error instanceof NoConnectionError) {
                message=("Network Timeout Error");}
            else if (error instanceof AuthFailureError) {
                message=("Authentication Failure");}
            else if (error instanceof ServerError) {
                message=("Server Error");}
            else if (error instanceof NetworkError) {
                message=("Network Error");}
            else if (error instanceof ParseError) {
                message=("Network Timeout Error");}
            error.printStackTrace();
            Toast.makeText(HomeActivity.this, "" + message , Toast.LENGTH_LONG).show();

        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
 Map<String, String> params = new HashMap<>();
            params.put("reqtype", "login");
            params.put("phone", phone);
            params.put("pass", password);
            return params;
        }
    };

    int socketTimeout = 15000;//30 seconds - change to what you want
    RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
    stringRequest.setRetryPolicy(policy);
    ServerRequest.getInstance(HomeActivity.this).addtoRequestQue(stringRequest);

【问题讨论】:

    标签: php android


    【解决方案1】:

    所以需要先学习安卓的SSL,并且需要在服务器端创建SSL证书。

    概念

    在典型的 SSL 使用场景中,服务器配置有 包含公钥和匹配私钥的证书。 作为 SSL 客户端和服务器之间握手的一部分,服务器 通过签署其证书来证明它拥有私钥 public-key密码学。

    For more info read link

    以下示例将使这些概念更加具体。 在命令行下面的 sn-p 中,openssl 工具的 s_client 命令查看 Wikipedia 的服务器证书信息。它 指定端口 443,因为这是 HTTPS 的默认值。命令 将 openssl s_client 的输出发送到 openssl x509,其格式为 有关符合 X.509 标准的证书的信息。 具体来说,该命令会询问主题,其中包含 服务器名称信息,以及标识 CA 的颁发者。

    $ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer
    subject= /serialNumber=sOrr2rKpMVP70Z6E9BT5reY008SJEdYv/C=US/O=*.wikipedia.org/OU=GT03314600/OU=See www.rapidssl.com/resources/cps (c)11/OU=Domain Control Validated - RapidSSL(R)/CN=*.wikipedia.org
    issuer= /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
    

    不,您需要在最后编写代码,如下所示:-

    public static SSLContext getSSLContextObject() {
        if (sslContext == null) {
            InputStream certificateInputStream = null;
            CertificateFactory certificateFactory = null;
            Certificate certificate = null;
            String keyStoreType = null;
            KeyStore keyStore = null;
            String trustManagerAlgorithm = null;
            TrustManagerFactory trustManagerFactory = null;
            try {
                certificateFactory = CertificateFactory.getInstance("X.509");
    
                certificateInputStream = new BufferedInputStream(FliplearnApp
                        .getInstance().getAssets().open("certificateName.any.crt"));
    
                try {
                    certificate = certificateFactory
                            .generateCertificate(certificateInputStream);
                } finally {
                    certificateInputStream.close();
                }
                // Create a KeyStore containing our trusted CAs
                keyStoreType = KeyStore.getDefaultType();
                keyStore = KeyStore.getInstance(keyStoreType);
                keyStore.load(null, null);
                keyStore.setCertificateEntry("certificate", certificate);
                // Create a TrustManager that trusts the CAs in our KeyStore
                trustManagerAlgorithm = TrustManagerFactory
                        .getDefaultAlgorithm();
                trustManagerFactory = TrustManagerFactory
                        .getInstance(trustManagerAlgorithm);
                trustManagerFactory.init(keyStore);
                // Create an SSLContext that uses our TrustManager
                sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustManagerFactory.getTrustManagers(),
                        null);
    
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (CertificateException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
        }
        return sslContext;
    }
    

    您不需要使用 SSL 上下文对象编写代码,如下所示:-

    public class Api {
    
        private SSLContext sslContext;
        private int lastResponseCode;
    
        public int getLastResponseCode() {
            return lastResponseCode;
        }
    
        public Api(AuthenticationParameters authParams) throws Exception {
    
            File clientCertFile = authParams.getClientCertificate();
    
            sslContext = getSSLContextObject();
    
            CookieHandler.setDefault(new CookieManager());
        }
    
    
        public String doGet(String url)  throws Exception {
            String result = null;
    
            HttpURLConnection urlConnection = null;
            try {
                URL requestedUrl = new URL(url);
                urlConnection = (HttpURLConnection) requestedUrl.openConnection();
                if(urlConnection instanceof HttpsURLConnection) {
                    ((HttpsURLConnection)urlConnection).setSSLSocketFactory(sslContext.getSocketFactory());
                }
                urlConnection.setRequestMethod("GET");
                urlConnection.setConnectTimeout(1500);
                urlConnection.setReadTimeout(1500);
    
                lastResponseCode = urlConnection.getResponseCode();
                result = IOUtil.readFully(urlConnection.getInputStream());
    
            } catch(Exception ex) {
                result = ex.toString();
            } finally {
                if(urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
            return result;
        }
    }
    

    现在您需要将上述代码集成到您的 volley 中。

    【讨论】:

    • 但是 SSL 只能在这方面提供帮助吗?我需要验证请求调用是否来自我的应用程序,请帮助我
    • 因此服务器生成证书 .crt 并将此证书放入您的资产文件夹中。当你调用 api 并为服务器创建 ssl 上下文时。
    【解决方案2】:

    您可以将设备类型甚至设备 ID 作为网络调用的标头参数发送。因此,在服务器端,您可以验证标头中发送的设备和 id 是否是 android 或其他,因此是否可以访问。这有帮助吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-22
      • 2016-01-21
      • 2014-01-20
      • 2015-05-15
      • 2020-09-11
      • 1970-01-01
      • 2017-06-04
      相关资源
      最近更新 更多