12/08/2018, 13:04

Thiết lập kết nối an toàn trong Android

Các bạn đọc trược tiếp trên Android Developer hiểu rõ hơn về SSL Click view Tóm tắt The Secure Sockets Layer (SSL)—now technically known as Transport Layer Security (TLS)—is a common building block for encrypted communications between clients and servers. It's possible that an ...

Các bạn đọc trược tiếp trên Android Developer hiểu rõ hơn về SSL Click view

Tóm tắt

The Secure Sockets Layer (SSL)—now technically known as Transport Layer Security (TLS)—is a common building block for encrypted communications between clients and servers. It's possible that an application might use SSL incorrectly such that malicious entities may be able to intercept an app's data over the network. To help you ensure that this does not happen to your app, this article highlights the common pitfalls when using secure network protocols and addresses some larger concerns about using Public-Key Infrastructure (PKI).

Như các bạn đã biết khi sử dụng browser để duyệt web đôi lúc truy cập vào trang web (https) các bạn nhận được thông báo "Không xác thực được chứng chỉ". đó có thể là 1 trang web dả mạo, cũng có thể thời gian hệ thống mình không chính xác và cũng có thể key ssl của server đã hết hạn.

Vấn đề SSL trong Android để làm gì ?

Hầu hết mình thấy khi thiết lập kết nối giữa client(Android) và Server. Các giao thức này thường các Dev mình không để ý (mặc định) ssl hoặc loại bỏ check SSL

Thiết lập mặc định

nếu bạn kệ mặc định xác thực trong một số trường hợp bạn sẽ gặp lỗi như

  • Không thể bắt tay giữa Client và Server
  • Không thể xác định được SSL
  • Không thể mã hóa dữ liệu
  • Và đôi lúc kết nối giữa client và server gặp trục trặc
  • .....

Chắc chắn các anh em chúng ta sẽ search google và chọn ngay giải pháp đó là thiết lập lại httpclient bỏ qua xác thực SSL.

Tùy chọn bỏ qua xác thực SSL

okHttpClient.setHostnameVerifier(new HostnameVerifier() {

                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true; // Luôn luôn đúng
                }
});

Việc này như kiểu fix ngay các lỗi ở thiết lập mặc định. ok chạy pull code ^^

Vấn đề ?

Vấn đề phát sinh ở đây đó là một hacker nào đó có thể thiết lập một mạng Lan, đổi DNS để chuyển hướng domain server mình sang một server khác mà hacker thiết lập sẵn để giả dạng mạo danh server mình để thay đổi kết quả trả về. cũng như lấy được nội dung gửi đi từ client. Từ đó có thể thao túng nhiều điều ^^

Ký xác thực rồi sẽ ra sao ?

Khi bạn đã tạo một keystore từ file cer thì khi client kết nối đến server. Trong bước bắt tay giữa client và server thì client nhận thấy hai public key là không giống nhau, từ đó trả về lỗi. Nếu giống nhau thì lúc đó client nhận ra ồ đó là server của mình

Thiết lập trong Android

Bước 1: Tạo file cert

Nếu đã có rồi thì bỏ qua nếu chưa có bạn cần liên hệ phí server để lấy. Một họ sẽ gửi cho bạn một file cert hai là sẽ gửi cho bạn một đoạn text mã hóa Base64 và theo kiểu X.509

-----BEGIN CERTIFICATE-----
MIIE23PDCCAySgAwggdfIBAgIDCssC1JMA0GCSq234GSIb3DQEBCwUAMEcxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdSYXBpZFNTTCBTSEEy
NTYgQ0EgLSBHMzAeFw0xNTExMDkwOTA2NDBaFw0xNzAxMDkxMjU3MjFaMBwxGjAY
BgNVBAMMESouZ2VlZWtzcGxheS5hc2lhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAwUA8TiciVmLc6WDz+A3PuNNOV23yGjCBz9o8mMfxGUeeXCVWpMPI
SlKzQCBt6fP6sAkEUsYdK9QBaXX5lp3JsG4rKHUNW234LKnD6r1XYueNXzelyqft/IV
9cmKk5jsKPQ8Q84Xqn+tFFNRCohk2GTgS/HKg65mo1bsKCXiwkQ7jGhcPHII5Sga7x
+nj2VFi48SLO9h/HURvx8+Jhstau4H/ziZja7LUrDO6LMzFTWPJrLxw4L1wxkAeT/
JEh/YTWZ6IJ8QTXN2XsoLDEVR2UaEx4RUBI6R1mKKSOcGq7tTgpLf8jm7YidQdxs
Wf2731V9/G+QnkkwfzN2sFNbAjV8NsoXBQIDádasdAQABo4IBWjCCAVYwHwYDVR0jBBgw
FoAUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUF
BzABhhNodHRwOi8vZ3Yuc3ltsdsdfsdfasdasY2QuY29tMCYGCCsGAQUFBzAChhpodHRwOi8vZ3Yu
c3ltY2IuY29tL2d2LmNydDAOBgNVHQ8BAf564568EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMC0GA1UdcEQQmMCSCESoucZ2VlZWtzcGxheS5hc2lhgg9n
ZWVla3NwbGF5LdmFzaWEwKwYDVR0fBzzCQwIjAgoB645654gssHIYaaHR0cDovL2d2LnN5bWNi
LmNvbS9ndi5jcmwwDAfgfgdfgYDVR0TAQH/BAIwADBBBgNVHSAEOjA4MDYGBmeBDAECATAs
MCoGCCsGAQUFBwIBFh5odHdfgfdgRwczovL3d3dy5yYXBpZHNzbC5jb20vbGVnYWwwDQYJ
KoZIhvcNAQELBQADggEBAGIVayPMklre0MjWp32haGbkDuNfdfgdfgSwITPuiiQw3kPSHK
7sd9pOAQdfgdfgdd4sB7kp3RbZzUo0Tmbn7pgB7Udfgdfg9XUESqv0MxMnZwZUwcHGcyI1WYeHqL
S5OqSrxsBPgn14SIjx2gLZp9nCY7JblFohJvJm0xGSQ60rj2KdNG0laN3RRzDErI
V0E3BykN+EH2Ft4NgWdgbOcdvPj+1/SVXcAnWxN3v07wjz4m4s+r7Ms/oMEc/Fxs
w4lmJazSoHg2+EEeofc+bFK3gcML51HARRgDzlVYibvQ+oAMEOtC+XhtaifVfYLE
O42KwqNnOhTEucps/FNIScOjHLlN9kDhR9g0cMX+nFE=
-----END CERTIFICATE-----

Lúc này bạn dùng bất cứ text editer nào đó tạo một file mới có tên server.cer chẳng hạn. rồi copy nội dung text đó vào.

Bước 2: Tạo keystore từ file cert

Keystore này khác với keystore dùng để build APK release nhé

Tải BouncyCastle Provider về.

Tiếp đó dùng lệnh keytool để keystore nhưng chú ý bạn đã cài đặt JAVA nhé ^^

keytool -importcert -v -trustcacerts -file "server.cer" -alias IntermediateCA -keystore "severkeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

trong đó mysecret sẽ là một mật khẩu mà bạn đặt thế nào cũng được. Bảo mật nhất hãy lấy keyhash của keystore của bạn

Sau khi tạo xong ta cần check lại

keytool -list -keystore "severkeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret

Kết quả trả ra như này là ok

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Bước 3: Sử dụng keystore

Trước tiên ta copy file severkeystore.bks vào res/raw/

Đối với Apache Httpclient

public class MyHttpClient extends DefaultHttpClient {

    final Context context;

    public MyHttpClient(Context context) {
        this.context = context;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        // Đăng ký port 443 sử dụng SSLSocketFactory với keystore
        registry.register(new Scheme("https", newSslSocketFactory(), 443));
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Tạo keystore kiểu BKS
            KeyStore trusted = KeyStore.getInstance("BKS");
            InputStream in = context.getResources().openRawResource(R.raw.severkeystore);
            try {
                trusted.load(in, "mật khẩu keystore".toCharArray());
            } finally {
                in.close();
            }
            SSLSocketFactory sf = new SSLSocketFactory(trusted);        sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

Đối với các bạn sử dụng Okhttpclient

    public static SSLSocketFactory getSSLSocketFactory(final Context context) {
    	SSLSocketFactory ret = null;

        try {
            final KeyStore ks = KeyStore.getInstance("BKS");
            final InputStream inputStream = context.getResources().openRawResource(R.raw.severkeystore);
            ks.load(inputStream, "mật khẩu".toCharArray());
            inputStream.close();
            ret = new SSLSocketFactory(ks);
        } catch (UnrecoverableKeyException ex) {
            L.d(TAG, ex.getMessage());
        } catch (KeyStoreException ex) {
            L.d(TAG, ex.getMessage());
        } catch (KeyManagementException ex) {
            L.d(TAG, ex.getMessage());
        } catch (NoSuchAlgorithmException ex) {
            L.d(TAG, ex.getMessage());
        } catch (IOException ex) {
            L.d(TAG, ex.getMessage());
        } catch (Exception ex) {
            L.d(TAG, ex.getMessage());
        }

        return ret;
    }

    .............

    OkHttpClient okHttpClient = new OkHttpClient();
    okHttpClient.setSslSocketFactory(getSSLSocketFactory(context));

Nhưng các bạn chú ý dùng các thư viện ngoài như retrofit,picaso.... Thì cũng set lại cái SSLSocketFactory nhé

Nếu có câu hỏi cũng như trao đổi các bạn có thể gửi email cho mình haipq@ymeo.net hoặc comment vào phía dưới nhé

0