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é