Sunday, July 24, 2016

Vọc thử các ứng dụng ngân hàng trực tuyến

Nhân dịp vấn đề an toàn giao dịch ngân hàng trực tuyến đang nóng, mình làm một vài bài thử nghiệm với các dịch vụ của 5 ngân hàng lớn trong nước: BIDV, Vietcombank, ACB, Techcombank và Sacombank. Các bài thử nghiệm sẽ là (hoặc tua xuống cuối bài để xem nhanh nên xài ngân hàng nào thì an toàn :P):
  1. Trang web
    • TLS: phải bật
    • SSL Server Test: phải từ A trở lên
    • HPKP: phải sử dụng
    • hoặc phải mã hóa tên và mật khẩu bằng Javascript trước khi đăng nhập
  2. Ứng dụng di động: lúc đầu mình tính kiểm tra riêng Android và iOS nhưng thực tế thấy ứng dụng mỗi ngân hàng ở hai nền tảng khá giống nhau nên gom lại chung cho gọn

Giới thiệu

TLS trước đây còn có rào cản về chi phí tuy nhiên gần đây đã có chứng chỉ miễn phí từ Let's Encrypt nên không còn lý do gì nữa để không làm việc này. TLS là bước cơ bản nhất để bảo mật thông tin giữa ngân hàng và người sử dụng.

SSL Server Test là bài kiểm tra máy chủ web bao gồm phần mềm, cấu hình TLS và chứng chỉ. Bài kiểm tra này sẽ cho điểm trang web, tối đa là điểm A. Điểm càng cao càng tốt.

HPKP là một phần mở rộng cho HTTP cho phép các trang web bảo vệ mình khỏi các cuộc tấn công dạng MITM (man in the middle / người trung gian). Cách tấn công này nôm na là kẻ tấn công can thiệp vào giữa kết nối của người dùng và ngân hàng sau đó bí mật ngăn chặn và thay đổi thông tin qua lại giữa hai bên. HPKP vẫn còn khá mới và chưa được hỗ trợ rộng khắp, người dùng cần sử dụng phiên bản khá mới của các trình duyệt để được bảo vệ (ví dụ: Chrome 46, Firefox 35 trở lên).

Certificate/Public Key Pinning có ý tưởng gần giống HPKP nhưng thay vì thực hiện kiểm tra ở trình duyệt thì mỗi ứng dụng tự kiểm tra khi kết nối với máy chủ. Do ứng dụng được phát hành bởi chính ngân hàng nên đội phát triển có thể nắm rõ máy chủ ngân hàng sử dụng chứng chỉ gì, phát hành bởi đơn vị nào, từ đó thực hiện Pinning đảm bảo thông tin của người sử dụng không bị lộ với bên thứ ba.

Trong trường hợp không sử dụng Pinning thì ứng dụng cần phải mã hóa tất cả các thông tin nhạy cảm như tên, mật khẩu đăng nhập theo cả hai hướng (gửi lên / nhận về) để bảo vệ người sử dụng.

Kết quả

Mỗi bước kiểm tra có thể có kết quả là:
  • PASS
  • BAD: yêu cầu nên có mà không sử dụng
  • FAIL: yêu cầu phải có mà không sử dụng

Trang web

  • TLS: có PASS
  • SSL Server Test: không kiểm tra được do HTTPS cổng 81
  • HPKP: không cài đặt BAD
  • Mã hóa: có nhưng vẫn có thể lấy được mật khẩu (xài base64) FAIL
  • TLS: có PASS
  • SSL Server Test: A PASS
  • HPKP: không cài đặt BAD
  • Mã hóa: không thực hiện FAIL

  • TLS: có PASS
  • SSL Server Test: B FAIL
  • HPKP: không cài đặt BAD
  • Mã hóa: không thực hiện FAIL
Trang web của ACB bị điểm B vì nhiều lý do tuy nhiên nặng nhất là do cấu hình phần mềm đang hỗ trợ một công nghệ đã cũ và có điểm yếu (DH, chi tiết xem thêm trang tổng hợp về ACB tại SSL Labs).

  • TLS: có PASS
  • SSL Server Test: A- PASS
  • HPKP: không cài đặt BAD
  • Mã hóa: không thực hiện FAIL
  • TLS: có PASS
  • SSL Server Test: A- PASS
  • HPKP: không cài đặt BAD
  • Mã hóa: có nhưng vẫn có thể lấy được tên đăng nhập PASS

Ứng dụng di động

BIDV (Android, iOS)
  • TLS: có PASS
  • Pinning (ebank.bidv.com.vn): có PASS
Ứng dụng BIDV (iOS) thực hiện Pinning
và báo lỗi kết nối trong trường hợp bị tấn công

Vietcombank (AndroidiOS)
  • TLS: có PASS
  • Pinning (vcbmobilebankingp2.smartlink.com.vn): không cài đặt BAD
  • Mã hóa: có nhưng vẫn có thể lấy được tên đăng nhập PASS

ACB (AndroidiOS)
  • TLS: có PASS
  • Pinning: không cài đặt BAD
  • Mã khóa: không thực hiện FAIL
adapter=ACBAdapter&procedure=submitAuthentication&compressResponse&parameters=%5B%7B%22username%22%3A%220901234567%22%2C%22password%22%3A%22qwerty1%22%2C%22device%22%3A%22xxx%22%2C%22ip%22%3A%22xxx%22%7D%5D&__wl_deviceCtx=xxx&isAjaxRequest=true&x=xxx
Ứng dụng của ACB ngoài ra còn thực hiện tự cập nhật sau khi cài đặt từ kho ứng dụng, mặc dù dữ liệu cập nhật có vẻ được mã hóa tuy nhiên do không Pinning nên kẻ xấu rất có thể vẫn có cách chèn mã độc vào quá trình cập nhật này.


Techcombank (AndroidiOS)
  • TLS: có PASS
  • Pinning (m.techcombank.com.vn): không cài đặt BAD
  • Mã khóa: không thực hiện FAIL
{"origin":"MAPP","traceNo":"xxx","AuditData":{"device":"xxx","deviceId":"xxx","otherDeviceId":"xxx","application":"MAPP","applicationVersion":"1.1.2.5"},"identification":"0901234567","credential":"qwerty1","identificationType":"0","credentialType":"0","UnstructuredData":[{"Key":"DeviceToken","Value":"xxx"}]}

Sacombank (Android, iOS)
  • TLS: có PASS
  • Pinning (www.msacombank.com.vn): không cài đặt BAD
  • Mã hóa: có nhưng vẫn có thể lấy được tên đăng nhập PASS

Kiểm tra thêm

Mình cũng hơi rảnh nên quyết định thử thêm Citibank với HSBC.

  • Citibank Vietnam Web
    • TLS: có
    • SSL Test A-
    • Không có HPKP
    • Không mã hóa khi gửi thông tin
    • Tổng kết: FAIL
  • Citibank Vietnam (Android, iOS)
    • TLS: có
    • Pinning (mobile.citibank.com.vn): không
    • Mã hóa: có
    • Tổng kết: PASS
    • Ứng dụng này dùng WebView mà không Pinning nên có thể tấn công bằng cách chèn mã độc vào các đoạn Javascript khi tải ứng dụng.
  • HSBC Vietnam Web
    • TLS: có
    • SSL Test C (chứng chỉ + thuật toán yếu)
    • Không có HPKP
    • Không mã hóa khi gửi thông tin 
    • Tổng kết: FAIL
  • HSBC (Android, iOS)
    • TLS: có
    • Pinning (services.mobile.hsbc.com + www.hsbc.com.vn): có
    • Tổng kết: PASS
    • Ứng dụng này của HSBC toàn cầu, mình chọn kết nối vào HSBC Việt Nam thì thấy ứng dụng áp dụng Pinning cho cả hai máy chủ luôn. Tuy vậy vẫn có một số thông tin theo dõi người dùng (sử dụng mạng gì, thiết bị gì, đang vào trang nào) có thể bị nghe lén (máy chủ dc.webtrends.com)

Thông báo lỗi của ứng dụng HSBC khi bị tấn công

Kết luận


Như vậy là chỉ có 1 trang web qua được bài kiểm tra (Sacombank) và cả 5 trang đều không xài HPKP. Như đã nói ở trên, đây là chức năng khá mới và đa số người dùng cũng chưa sử dụng trình duyệt phiên bản đủ mới để hưởng lợi từ việc này. Trên thế giới cũng còn nhiều trang web tài chính chưa bắt đầu sử dụng HPKP (ví dụ như PayPal, HSBC US).

Về ứng dụng di động, 2 ứng dụng không qua được bài kiểm tra (ACBTechcombank) và 1 ứng dụng duy nhất có sử dụng kỹ thuật Pinning là BIDV.

Bảng xếp hạng chung cuộc:
  1. Sacombank: chưa áp dụng các công nghệ mới nhất nhưng vẫn an toàn
  2. BIDV, Vietcombank: ứng dụng của ngân hàng này an toàn hơn web của họ
  3. ACB, Techcombank: về chót. Nên hạn chế sử dụng nếu đang kết nối qua mạng công cộng (wifi quán cà phê, wifi không bảo mật).
Bài này đã được thay đổi do lỗi khi chạy thử web của BIDV dẫn đến thay đổi thứ tự bảng tổng kết cuối cùng (kết quả cũ là BIDV số 1, kết quả cập nhật là Sacombank vượt lên!).

Xem thảo luận + gạch đá ở tinhte.vn.

Thursday, May 26, 2016

Reverse engineering Pubvn apps for fun and... larger-screen-fun

It's Friday night and the wifeTM wanted to watch Games of Thrones on the TV (via Chromecast). Should be easy right? We have lots of apps installed for exactly this purpose: Netflix, HBO Now, Flix, etc. None of them worked though...

  • Netflix just doesn't have HBO contents like GoT.
  • HBO Now works but it requires a US proxy to watch and there is no way to tell the Chromecast to go through a proxy.
  • Flix, a promising local app, good with TV streaming but not series.
So we had to settle to use HBO Now and Google Chrome's cast tab feature to have it on the big screen. A complicated setup, and slow. The casting was broken a few times during the episode, probably because of wifi interferences. This problem needs some engineering!

Proxy Those Apps

First order of business would be proxy their apps to catch all network requests. I used Charles with their iOS app. At first I thought it would be tricky if they use https or certificate pinning but it turned out everything runs through http. After a few taps on the apps, the flow looks something like this:

  1. `filmlist` api for search
  2. `filmdetail` to get a movie's episodes
  3. Finally use `filmmedia` for the mp4 url
After a few hours or so, I had gotten the mp4 casting on my TV. Success? Not yet.

Subtitles

Hmm, subtitles are important, we really need those (especially for GoT). Chromecast supports subtitles in WebVTT format (which is good) but apparently Pubvn only has SRT. Also, the subtitles url is protected with some weird authentication hashing. Almost gave up, I tried to proxy their Android app and found out that this app uses a slightly different api. Best of all, Android subtitles don't require authentication, they have some custom made encoding instead.

New plan:
  • Switch to use Android api endpoints
  • Decompile their apk to get the SRT decoder.
  • Put that decoder on Heroku with WebVTT converter
Complicated but now we have working mp4 and WebVTT urls. For some reason, Chromecast failed to play with subtitles turned on though...

CORS

Another couple hours passed by until I found out that both urls must have CORS headers. Probably the video player needs more data from the movie stream when it renders subtitles, I don't know.

It's easy to add those headers for the subtitles, we just need to update the Heroku app. But for the movie itself... It is hard, we don't control Pubvn servers so there is no ways to add those CORS headers (I asked them, no answer so far). I guess we can run a CORS proxy and play the movie from there? Just to be safe, let route the srt through that proxy too (so Pubvn servers will see our requests all from one IP).

Hah! Now we have movie with subtitles fully working on Chromecast! I have to keep 2 servers running though: the Heroku app and the CORS proxy.

Source: elitedaily.com
Repositories if you are interested:

Saturday, July 25, 2015

My experiment with golang and social counters

Starting with my frustration while building the scroll website: the social buttons are freaking slow to load. Especially on pages that has a lot of scripts (like mine) it is way worse. The buttons usually take minutes to show up and when they do, each of them render differently from the rest. Thanks Facebook, Twitter and Google for that.

So I went in and found a few options. It looks like people made a few scripts that will collect the counters via AJAX (on user browser) and render the buttons with images. Some use data URI to avoid triggering more requests, brilliant! Since I wanted to make something super simple and fast to use, I decided to have one script that does all of those. The server will keep track of the counters and put them in the script so everything needed is one and only one request.

I needed 3 social networks and each of them has different ways to retrieve the counters so I figured the server has to make the requests asynchronously, cache the values for sometime and return the bundled js. My goal is to have it at maximum 50KB and delivered within 500ms. According to my measurement, current scripts from the social networks are way more than that:

  • Facebook sdk.js is the worst contender at about 164KB 
  • Twitter's widgets.js is 107KB
  • Google is the winner here, their platform.js is only 37KB
At first I wanted to do this with Node.js because it's fairly simple and it looks like all output is javascript anyway. Turned out making 3 async http requests and merging the results together is quite complicated (callback hell, anyone?). So I switched to use golang since I tried their channel before and it seems to be a good fit. The project went well and I have them running at both Google App Engine and Heroku at the moment:
The code is pushed to GitHub too, with a simple demo site which makes use of the Heroku instance: http://hoangson.vn/go-socialcounters/. The all.js script is only 14KB (8KB gzip) and normally finished loading in less than a second. I also added a jQuery Plugin script for advanced usage (it fetches a heavily cached jsonp file). The project uses data URI as the other scripts that I found but those images do not look good in high resolution screens so I try to detect SVG support and use SVG whenever possible.

I hope this project is useful for someone.

Monday, April 13, 2015

Quick DNS switching script for Mac OS X

I'm too lazy to spend 1 minute every time I have to change DNS so I spent 10 minutes to wrote this script to do it quick. It currently supports Google, Open DNS and uFlix but it can support unlimited number of configurations.

Get the script here: https://gist.github.com/daohoangson/60ce8e0317213bc45c30

Use it like

switch-dns-to.sh google

You will need to enter the user password.


Tuesday, March 17, 2015

PDBS 2015

*PDBS stands for Personal Data Backup Strategy.

I have always been paranoid regarding data loss. That's why I try to follow best practices in backing up data:
  • 2 offline full machine backups to external HDDs, one in Hanoi, one in HCMC. I have done this since a few years ago when I was using the ThinkPad T41 laptop (circa 2007).

    The size of this backup grows linear with time and it is about 300GB these days (with TimeMachine).
  • 1 online backup via Arq to Amazon Glacier for important archival data (how did I flirt with my wife, that kind of serious stuff). Before I started using Arq (early 2013), I made yearly dump of data to DVDs.

    This backup grows slowly until I met Sylvie and it started to explode, going around 150+ GB now. Mostly full size photos.
  • 1 online backup for work related files are put in Dropbox because their apps (Windows and Mac) work really well. I believe they are the only one who uses delta sync, which is super fast. Since work data changes regularly, it makes sense to use something efficient. My Dropbox account currently using 40GB of data. I haven't paid for it though, got the storage via their various promotional programs.
  • At least 1 alternative online backup for codes. I have many public repos on github.com and just as many private ones on bitbucket.org to keep track of code and they act as secondary backups.
  • 1 online backup for media from cameras, smart phones. I use Dropbox on all of my devices. There are about 30GB of photos currently (of the total 40GB Dropbox data). Their mobile apps work well enough across all platform so it just makes sense. For each device, I also use the respective native backup service (Apple = iCloud, Google = Google+, Microsoft = OneDrive).
All in all, there has been no problems so far but I made a change recently and moved archival data (150GB) to OneDrive. The simple reason is Microsoft offers 10TB storage for Office 365 subscribers (which I have been for a few years) and OneDrive photo browser is fairly good. Since this collection of data consists 90% of photos, it's great to be able to quickly find a photo when needed. Also, Arq has proven to be quite complicated and slow (probably because I had never upgraded to version 4). Amazon Glacier is cheap and all but downloading data is time consuming and/or expensive. Most of all, there is no way to browse my data online.

I started uploading to OneDrive 9 days ago (March 8th) and have just finished today. I still have 9.95 TB available, it's beautiful!


Saturday, November 29, 2014

The new UISplitViewController, Swift and iOS 7

I was playing around with Swift today and stumbled upon the new awesome UISplitViewController in iOS 8. This enhanced version of the controller makes it work for all iOS devices (originally, it only works with iPads). With the introduction of the "phablet", Apple had to improved their SDK to make it easier for devs to build app that works across all screen sizes. That's a good thing, but a little too late IMHO.

Anyway, back to UISplitViewController, the app created by the Xcode template only works with iOS 8 so I tried to dig in and see if it is possible to support iOS 7 with the same code, same storyboard and everything. It looked like it was possible. Many people tried that, particularly this blog post, but the best solution out there still doesn't have it working smoothly in iPad portrait mode where it should show a button to open the master view in a popup... After a few hours looking around, I finally found the solution and have a demo project available at github.com. Check it out now and I hope you find it useful.

Below are some screenshots:

UISplitViewController in iPad/iOS 7: button with text
UISplitViewController in iPad/iOS 8: button with text + arrow

UISplitViewController in iPhone 5s/iOS 7: button with text + arrow
UISplitViewController in iPhone 5s/iOS 8: button with text + arrow



UISplitViewController in iPhone 6+ landscape: fullscreen button

Download demo project here.


Thursday, November 13, 2014

The Cloud

It's such a good feeling to get a new phone and within minutes you have it running exactly as you like, thanks to the Cloud. The Cloud has its up and down ("Nobody understands the Cloud. It's a fucking mystery!"), yes but what else doesn't? Even people have their freaking mood swings.

All major players are improving their offering to tie users to their Clouds because that strategy pulls in customers for them and also helps with competing in the market. And it works. The Cloud comes in many shapes and forms but in general, user experience is way better. Everyone can do whatever they want fast, securely and conveniently (given that they have a decent internet connection of course). I really think the Cloud will be the future. Everything we are going to do will be on the Cloud. The pieces of hardware we have in the house, at our workplaces or in our pockets are just terminals. They could be broken, water damaged or stolen, who cares! Insurance would just replace it with the latest shiniest gear and you are good to go.

It's funny to think how we are going back to something similar to the old days server vs. dumb terminal. At least the terminals are smart now, that's some progress.