+22

HTTPS có thực sự bảo mật?

Bài viết gốc: https://manhhomienbienthuy.github.io/2017/01/11/https-da-du-bao-mat-chua.html (đã xin phép tác giả 😄)

HTTPS hay còn được gọi là HTTP Secure, hoặc HTTP over SSL, HTTP over TLS là một giao thức được coi là bảo mật hơn của giao thức truy cập Web HTTP thông thường. Bản thân nó đã có nghĩa "bảo mật" nhưng liệu thực sự nó có đủ bảo mật như chúng ta vẫn nghĩ hay không? Trong bài viết này, chúng ta sẽ tìm hiểu thêm về HTTPS và cách thức bảo mật của nó.

Tại sao chúng ta cần đến HTTPS

Hiện nay Google đã thêm tiêu chí sử dụng HTTPS để đánh giá các trang Web. Tuy nhiên, không phải lúc nào chúng ta cũng cần đến HTTPS. Chúng ta chỉ cần chúng khi bảo mật thông tin mà thôi.

Tại sao phải bảo mật thông tin?

Trong thời chiến tranh, rất nhiều thông tin quân sự, tình báo chỉ có thể thông tin cho một số người, những người khác, nhất là kẻ địch không được biết. Tuy nhiên, vì nhiều lý do, việc truyền tải tin tức không thể trực tiếp từ người gửi đến thẳng người nhận, mà phải thông qua một số trung gian nhất định. Việc truyền tải như vậy khiến tin tức dễ dàng bị lọt ra ngoài. Ví dụ, các phương thức truyền tin bằng điện tín dễ dàng bị bắt trộm sóng và nghe lén.

Vì vậy, người ta dùng nhiều phương thức khác nhau đễ mã hóa đoạn tin cần gửi, để đảm bảo rằng, ngoại trừ người cần nhận, những người khác dù nghe được cũng không hiểu gì. Nếu bạn đã từng xem phim Windtalkers thì bạn có thể hiển được tầm quan trọng của mã hóa trong chiến tranh là như thế nào.

Tương tự như vậy, trên Internet hiện nay có rất nhiều kiểu tấn công kiểu nghe lén như vậy. Một hình thức phổ biến được gọi là Eavesdrop, ngoài ra còn một kiểu tấn công mạnh hơn nữa gọi là Man in the Middle. Tuy nhiên, nội dung bài viết này sẽ không đi sâu vào chi tiết các kiểu tấn công đó, có thể tôi sẽ trở lại trong bài viết sắp tới. Những gì tôi muốn nói ở đây là những gì chúng ta làm trên Internet không bao giờ là riêng tư theo đúng nghĩa cả.

Big Brother is watching you

Mạng Internet là một nơi kết nối rất nhiều máy tính, một gói tin đi từ người gửi trước khi đến với người nhận sẽ phải đi qua rất nhiều máy trung gian khác nhau. Vì vậy, việc bị đọc trộm các gói tin này đã trở thành một phần tất yếu của lịch sử. Không ai có thể ngăn chặn được những kẻ táy máy tìm cách đọc trộm gói tin của chúng ta trên đường đi. Thậm chí, cơ chế hoạt động của Internet cho phép việc nghe lén này diễn ra hết sức dễ dàng. Nếu không tin, bạn có thể cài thử Wireshark và xem mạng mà bạn đang sử dụng có những hoạt động nhộn nhịp như thế nào.

Những gì chúng ta làm trên Internet có nhiều thứ người khác biết cũng chẳng sao. Nhưng cũng có nhiều thứ chúng ta chẳng muốn ai biết cả. Và một nhu cầu hết sức chính đáng của con người là che giấu một số thứ có thể gọi là "bí mật" đó khỏi con mắt nhòm ngó của những người xung quanh. Vì việc xem trộm các gói tin diễn ra hết sức bình thường như vậy, nên chúng ta cần đến các phương thức mã hóa để đảm bảo rằng, gói tin mà chúng ta gửi đi chỉ có chúng ta và nơi nhận hiểu được. Tất cả những kẻ táy máy đọc trộm trên đường dù đọc được cũng không hiểu được gì.

Đó là lý do chúng ta cần đến HTTPS trong các giao dịch Web, HTTPS sẽ giúp chúng ta mã hóa quá trình giao dịch của máy chủ Web và trình duyệt. Ngoài ra, HTTPS còn một số tác dụng khác nữa, như xác thực máy chủ (tránh bị phishing), v.v...

HTTPS bảo mật giao dịch như thế nào?

Khi trình duyệt truy cập trang Web sử dụng HTTPS, trình duyệt và máy chủ sẽ thiết lập một kết nối SSL bằng cách sử dụng giao thức SSL Handshake. Quá trình thiết lập kết nối này hoàn toàn trong suốt với người dùng, thông thường người dùng không cần quan tâm đến nó.

Để thiết lập kết nối SSL, có 3 khóa được sử dụng: public key, private key và session key. Public key và private lập thành một cặp: mọi thứ cần mã hóa được mã hóa bằng public key và giải mã bằng private key. Session key là khóa dùng trong phương thức mã hóa đối xứng, nó được dùng cho cả quá trình mã hóa và giải mã.

Nếu bạn chưa hiểu hết về các phương thức mã hóa bằng public key và mã đối xứng, có lẽ bạn nên tìm hiểu về chúng trước khi chúng ta tiếp tục.

Việc mã hóa bằng public key rất tốn kém nên nó chỉ được dùng vào thời điểm thiết lập kết nối, sau khi kết nối được thiết lập, mã hóa đối xứng sẽ được sử dụng (với khóa là session key). Toàn bộ quá trình diễn ra như sau:

  1. Trình duyệt kết nối với máy chủ sử dụng HTTPS.
  2. Máy chủ trả về một SSL certificate, trong đó có chứa public key dùng để mã hóa.
  3. Trình duyệt kiểm tra certificate (quá trình này chúng ta sẽ tìm hiểu ở phần sau). Nếu mọi thứ đều ổn hoặc người dùng cố xử lý tiếp thì trình duyệt sẽ sinh ngẫu nhiên session key và gửi cho server (dữ liệu được mã hóa bằng public key).
  4. Máy chủ sử dụng private key giải mã gói tin lấy session key, gửi phản hồi đã nhận key cho trình duyệt.
  5. Từ đây trở đi, máy chủ và trình duyệt gửi nhận các gói tin được mã hóa bằng session key.

SSL certificate

SSL certificate là giấy chứng nhận được dùng khi thiết lập kết nối giữa trình duyệt và máy chủ. SSL certificate về mặt kỹ thuật là những tập tin kích thước tương đối nhỏ trong đó có lưu thông tin về public key cùng với các thông tin khác về tổ chức chủ sở hữu của trang Web.

Một số thông tin được lưu trong SSL certificate:

  • Domain, tên server, hostname
  • Tên công ty, tổ chức, địa chỉ liên hệ
  • Thời hạn sử dụng
  • Public key

Tuy nhiên, giấy chứng nhận này hoàn toàn có thể bị làm giả. Giống như chúng ta viết sơ yếu lý lịch vậy, làm sao để biết chúng ta đã viết những thông tin chính xác? Chúng ta cần phải có xác nhận của chính quyền địa phương. SSL certificate cũng tương tự như vậy, để đảm bảo chứng nhận này không phải là giả, chúng ta cần đến Certificate Authority.

Certificate Authority (CA) có thể xác nhận rằng certificate là thật, họ sẽ sử dụng chữ ký điện tử với private key của riêng họ. CA sẽ đóng vai trò như những công chứng viên đã được cấp giấy phép hành nghề, chữ ký của họ được tin tưởng và certificate được họ chứng nhận có thể coi là hợp lệ.

Thường thì CA bán các giấy chứng nhận này và họ sẽ xác nhận cho giấy tờ mà họ cấp. Vì vậy, thường chúng ta phải mua SSL certificate với giá cũng không rẻ lắm. Kỳ thực giá trị của SSL certificate không chỉ ở bản thân giấy chứng nhận, mà nó con bao gồm một phần không nhỏ giá thương hiệu của người bán.

Thực ra chữ ký của CA cũng cần phải được xác thực. Giống như chúng ta kiểm tra lại chữ ký của công chứng viên vậy. Các certificate của CA sẽ được chứng nhận bởi những CA cấp cao hơn, và quá trình này là một quá trình đệ quy như sau:

validation chain

Mỗi certificate sẽ được chứng nhận bằng certificate cấp cao hơn, và cấp cao nhất gọi là CA Root certificate. CA Root certificate cũng là một SSL certificate, nhưng nó dùng để xác thực và gắn chữ ký điện tử cho các certificate thương mại được bán cho người dùng. Những root certificate này thường được cài đặt sẵn trên trình duyệt và khi trình duyệt nhận certificate từ website nào đó, nó sẽ dùng root certificate để kiểm tra những certificate nhận được có hợp lệ hay không.

Nhờ quá trình xác thực trên, mà khi sử dụng HTTPS, chúng ta không chỉ đơn giản mã hóa thông tin, mà chúng ta còn chứng thực được mình đang làm việc với đúng đối tượng mà chúng ta muốn.

Vì quá trình xác thực, mã hóa và giải mã rất phức tạp như trên, nên HTTPS tốn nhiều thời gian để xử lý hơn HTTP. Trong nhiều trường hợp HTTPS là không cần thiết, nhiều hãng lớn như CNN, BBC không sử dụng HTTPS cho trang Web của họ, đơn giản vì nó là các trang tin tức, không có thông tin nhạy cảm nào mà việc phản hồi nhanh với người dùng quan trọng hơn.

HTTPS có thực sự bảo mật?

Trong nhiều trường hợp, HTTPS với dấu hiệu màu xanh trên thanh địa chỉ là dấu hiện cho thấy những gì chúng ta thao tác sẽ được bảo mật. Nhưng liệu nó đã đủ bảo mật hay chưa? Ý kiến cá nhân của tôi là chưa. HTTPS cũng giống như bạn ra khỏi ra mà khóa kín cửa vậy. Kỳ thực khóa cửa chỉ phòng người ngay chứ chẳng tránh được kẻ gian. Nếu có kẻ đã cố tính vào nhà ăn trộm thì khóa cửa chắc mấy cũng chỉ cần cắt một nhát là đứt. HTTPS có lẽ có phần tương tự như vậy.

Với máy chủ và Web app

HTTPS là một cơ chế bảo mật giao dịch giữa người dùng và máy chủ. Có thể nói, đối với máy chủ Web cũng như các ứng dụng Web, nó không có tác dụng gì trong việc bảo mật máy chủ và ứng dụng.

Việc bảo mật ứng dụng cần rất nhiều quá trình phức tạp, bao gồm chống tấn công DDoS, chống XSS, CSRF, v.v..

Với người dùng

Vậy với người dùng thì sao? Chẳng phải HTTPS giúp người dùng mã hóa dữ liệu, xác thực máy chủ hay sao? Câu trả lời thật phũ phàng là vẫn có rất nhiều cách để phá vỡ HTTPS. Tạm thời chưa nói đến các phương thức mã hóa có những lỗ hổng nhất định, vẫn còn rất nhiều phương pháp khác nhau để phá bỏ hệ thống xác thực certificate:

  • Đột nhập vào hệ thống của CA. Như chúng ta đã biết, có hàng trăm CA được trình duyệt tin tưởng. Những kẻ tấn công chỉ cần tìm một trong số các CA này có khả năng đột nhập là đủ. Và thực tế thì chuyện này cũng đã từng xảy ra với những hậu quả thật khủng khiếp.
  • Đột nhập các router gần CA hoặc gần nạn nhân, đọc và giả mạo các gói tin DNS đến và đi, tấn công việc trao đổi email giữa nạn nhân và CA. Các phương thức mã hóa email không giúp ích được gì trong trường hợp này, vì STARTTLS hoàn toàn có thể bị phá vỡ.
  • Đột nhập các máy chủ DNS được sử dụng với CA hoặc giả mạo các gói tin DNS với domain của nạn nhân. Nhiều khi việc này khá dễ dàng.
  • Tấn công một số giao thức mạng khác, ví dụ TCP, để tấn công các gói tin của nạn nhân.
  • Một số CA có thể bị chính quyền nước sở tại bắt buộc cung cấp certificate độc hại như đã từng bị. Bởi vì CA có mặt ở rất nhiều quốc gia khác nhau mà nhiều chính phủ có thể tìm cách yêu cầu CA làm như vậy.

Trên đây là những vẫn đề của hệ thống ngoài khiến dữ liệu của chúng ta vẫn có thể bị đánh cắp dù HTTPS vẫn hoạt động tốt. Nhưng ngay cả HTTPS bản thân nó cũng có những vẫn đề nhất định. Ví dụ như lỗ hổng Heartbleed (trái tim rỉ máu). Lỗ hổng này có khả năng phơi bày các nội dung chứa trong bộ nhớ máy chủ, cho phép kẻ tấn công sao chép các mã khóa của máy chủ. Có được khóa rồi, chúng dễ dàng giải mã các thông tin được trao đổi.

Và ngay cả cơ chế xác thực bằng root certificate cũng không hoàn toàn an toàn. Hãy xem kiểu tấn công Man in the Middle như sau:

MitM

Ví dụ, bạn cần vào https://www.gmail.com, nhưng có kẻ nào đó giả crack vào quá trình trao đổi giữa bạn và máy chủ. Và bạn tin tưởng rằng, với certificate đã được chứng thực, bạn có thể yên tâm rằng mình an toàn, những kết nối với máy chủ không phải Gmail sẽ không thể được xác thực bằng SSL certificate.

Nhưng bạn đã nhầm rồi.

Những gì thực sự có thể diễn ra rất khác với bạn tưởng tượng:

  1. Bạn kết nối đến https://www.gmail.com
  2. Kẻ tấn công chuyển hướng truy vấn của bạn đến máy chủ hắn đã chuẩn bị sẵn.
  3. Vì máy chủ này chứa SSL certificate hoàn toàn hợp lệ, trình duyệt của bạn sẽ không thể biết được bạn đã kết nối sai máy chủ.
  4. Bạn thao tác với máy chủ giả, mọi dữ liệu sẽ bị kẻ tấn công đọc được, hắn ta có thể thay đổi nó, và gửi nó cho máy chủ Gmail thật.
  5. Bạn hoàn toàn không hề hay biết rằng kết nối được bảo mật của mình hoàn toàn không hề bảo mật.

Tại sao kẻ tấn công có thể có được SSL certificate hợp lệ? Kẻ tấn công có thể lợi dụng root certificate (được cài đặt sẵn trong các trình duyệt, mà trình duyệt mã nguồn mở thì không thiếu) để tạo ra các SSL certificate cho website của hắn. Nếu vậy thì có trời mới biết thứ nào là thật, thứ nào là giả.

Nói một cách ngắn gọn, có rất nhiều con đường khác nhau để bẻ khóa HTTPS.

No system is safe

Các giao thức bảo mật Web có thể đủ tốt để phòng chống những kẻ tấn công vãng lai, không có nhiều thời gian và động lực. Nhưng nó vẫn còn quá nhỏ bé trong một thế giới mà công nghệ và các phương thức tấn công ngày càng phát triển.

Ví dụ minh họa

Mời các bạn thử sức với bài CTF sau, đây sẽ là một ví dụ minh họa đơn giản cho thấy HTTPS dễ bị tổn thương như thế nào?

http://ksnctf.sweetduet.info/problem/33

Đề bài cho một file pcap, đây là file capture các gói tin trong mạng. Trong file này thể hiện rất rõ ràng quá trình thiết lập kết nối SSL và trao đổi dữ liệu. Sử dụng Wireshark, chúng ta có thể thấy được toàn bộ quá trình trao đổi dữ liệu này.

  1. Client hello, đây là bước mở đầu, trình duyệt thông báo cho máy chủ biết về thuật toán mã hóa.
  2. Server hello, đây là bước máy chủ phản hồi rằng đã chấp nhận thuật toán mã hóa của trình duyệt.
  3. Certificate, đây là bước máy chủ gửi SSL certificate cho trình duyệt.
  4. Change cipher spec, đây là bước trình duyệt gửi cho máy chủ thông tin về session key được sinh ngẫu nhiên.

Tiếp theo là quá trình trao đổi dữ liệu sử dụng session key, như chúng ta có thể thấy, ở packet thứ 12 là Application data, đây là packet HTTP đã được mã hóa bằng session key.

https data

Để hiểu được các gói tin này, chúng ta cần phải tìm được private key của server. Trước hết, bằng cách Export selected packet bytes, chúng ta dễ dàng lấy được thông tin public key của certificate nhận được từ máy chủ:

certificate

Việc sinh ra public key và private key được thực hiện theo cách thức của RSA. Từ các packet thu được, chúng ta có thể thu được public key của máy chủ

inspect public key

Modulus ở đây là tích của hai thừa số nguyên tố. Chỉ cần phân tích được nó thì chúng ta có thể tìm được private key. Về lý thuyết, việc này là hoàn toàn có thể. Tuy nhiên, việc phân tích nó có thể nói là quá sức của những máy tính cá nhân bình thường, vì giá trị của nó quá lớn. (Tuy nhiên, sau này, máy tính lượng tử có thể sẽ giải quyết được vấn đề tính toán này)

Rất may, chúng ta có thêm gợi ý thứ 2. Ở đây, client đang giao tiếp với hai server (192.168.0.39 và 192.168.0.40). Chúng ta dễ dàng lấy được public key của server thứ 2. Và trong bài toán này, hai server sử dụng public key tương tự nhau, phải chăng chúng có cùng thừa số nguyên tố. Chúng ta sẽ tìm cách lấy chúng ra.

def gcd(a, b):
    while b != 0:
        r = a % b
        a, b = b, r
    return a

mod1 = """
00:a5:a7:ce:44:46:2e:8a:c6:e4:da:5e:8a:8d:58:
e0:03:b8:26:75:68:b3:58:10:6c:f0:64:12:88:4c:
ee:b7:cc:42:51:c2:cc:e2:db:74:68:9d:1a:fa:10:
9b:de:97:62:40:2e:81:d9:6c:b6:c8:c6:c5:ae:bc:
8d:45:a9:6b:f2:14:a6:18:b4:99:a8:c6:13:40:35:
c5:03:9b:f9:a3:9b:c4:71:90:e4:cc:45:60:cb:75:
ab:8d:63:63:5c:de:e8:e5:0f:58:15:b2:91:80:cc:
51:a4:c8:cf:76:a8:bb:e6:e6:1c:68:ac:a3:85:fd:
f9:9e:71:2b:10:a6:be:7e:d7:94:cf:27:54:0b:7a:
a0:0f:59:da:55:79:04:0a:9b:3b:7c:23:e9:e2:2a:
15:c2:9e:b0:c0:60:b9:6d:1f:48:d1:c4:58:e2:c4:
12:51:29:62:ce:5a:f8:85:23:7b:61:38:df:6c:9e:
85:d1:01:c2:66:c3:b8:0b:02:ff:97:d6:fd:e4:65:
98:e1:9e:3f:a1:df:2c:56:bd:34:ad:df:e7:16:56:
9a:2e:d4:2c:64:42:bf:2d:b5:e9:a5:1c:c2:d7:dd:
44:97:71:7d:dd:9a:8a:66:ae:28:1e:1a:2a:bf:7d:
f7:a5:97:79:b4:99:cc:0f:81:67:a1:9e:3c:a5:c9:
bb:e3
"""

mod2 = """
00:a4:da:ad:49:ea:e0:b5:c5:9d:a0:45:29:78:ae:
98:7e:1b:96:f1:49:de:db:62:27:4c:97:f9:9a:c4:
54:4a:a9:0d:b4:aa:f9:a0:96:7f:11:8b:70:09:09:
7b:cb:0b:ae:b4:a1:96:36:77:7a:77:47:e0:6a:d8:
44:96:c9:c6:1d:18:a7:b5:ca:77:65:85:a8:17:52:
6e:d6:d9:f0:f2:ab:d8:c4:34:c6:2c:bf:02:5e:b7:
ce:5a:83:e4:a7:f9:93:8f:38:62:de:24:e6:29:2f:
43:27:0f:fd:a7:57:c1:7a:aa:79:7f:f9:fe:18:fd:
1c:b2:39:21:dc:58:5d:45:50:38:4f:f5:c4:f2:4e:
6d:fc:6d:4f:44:b5:69:34:58:08:23:92:47:c2:0d:
26:6c:d0:f5:e3:73:88:9e:d4:e4:59:59:0b:7d:74:
2d:28:37:c1:c4:8d:cf:94:18:e2:21:91:ab:4a:0b:
ca:0e:d7:9b:1d:45:c0:ca:5d:36:ea:69:60:c9:36:
0c:11:41:23:29:fd:5d:90:ff:34:67:f2:d8:2e:23:
02:1a:df:3b:6d:8b:e2:49:03:b7:6e:ff:c9:38:15:
4e:c2:19:f3:44:11:8f:1c:41:fe:c3:11:71:b6:29:
45:a0:7e:35:76:2a:96:1a:05:79:53:89:08:60:52:
de:c7
"""

pubs = [int(''.join(mod.replace('\n', '').split(':')), 16)
        for mod in (mod1, mod2)]

p = gcd(*pubs)

Từ đây, chúng ta có thể lấy ra được thừa số nguyên tố còn lại từ Modulus. Việc chúng ta cần làm lúc này khá đơn giản, tìm cách ghi private key ra file theo định dạng PEM để Wireshark hiểu và dự giải mã cho chúng ta là được:

e = 65537

from Crypto.PublicKey import RSA

def inverse(a, n):
    t = 0
    newt = 1
    r = n
    newr = a
    while newr != 0:
        quotient = r // newr
        t, newt = newt, t - quotient * newt
        r, newr = newr, r - quotient * newr
    if r > 1:
        return 0
    if t < 0:
        t = t + n
    return t

for i, pub in enumerate(pubs):
    q = pub // p
    with open("key%d.pem" % (i + 1), "w") as f:
        n = p * q
        phi = (p - 1) * (q - 1)
        comps = (n, e, inverse(e, phi))
        x = RSA.construct(comps)
        pk = x.exportKey().decode()
        f.write(pk)

Vậy là chúng ta đã thu được hai file PEM chứa private key của hai máy chủ. Giờ chỉ cần thêm vào cho Wireshark là được

add pem file

add keys

Vậy là đủ, Wireshark sẽ giải mã các gói tin cho chúng ta, lúc này chúng ta có thể thấy được các packet HTTP

decrypted packet

Và dễ dàng lấy được những thông tin chúng ta cần.

flag

Có thể nói rằng đây chỉ là một bài CTF nên người ra đề đã cố tình để lộ ra một vài sơ hở. Nhưng cũng nên nhớ rằng, tôi cũng chỉ là "tay mơ" đang tập tành chơi, còn ngoài kia có biết bao nhiêu người tài năng khác, họ có thể tìm ra lỗ hổng bảo mật ngay cả khi mà người thiết kế giao thức vẫn còn chưa nghĩ đến nó.

Kết luận

HTTPS thực sự chỉ đủ bảo mật ở mức độ chấp nhận được. Nếu muốn thực sự an toàn trên Internet, chúng ta cần nhiều biện pháp hơn thế. HTTPS cũng giống như bạn ra khỏi nhà mà khóa cửa, phần lớn chúng ta vẫn tạm hài lòng với tình trạng như vậy, nhưng vẫn có nhiều người chưa hẳn yên tâm và còn phải khóa thêm vài lớp, mua thêm két sắt để cất giữ đồ đạc quan trọng.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí