HTTPS secure

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)
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ử
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.

python3
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:

python3
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.