Mục lục
Header
Check JWT có cho phép sử dụng thuật toán “None”
Giải thích: JWT có thể sử dụng thuật toán “None”(None, none, nOnE,NONE) để chỉ ra rằng không có chữ ký nào cần thiết. Điều này rất nguy hiểm vì nó có thể bị lợi dụng để tạo ra các token giả mạo. Đảm bảo rằng tùy chọn này bị vô hiệu hóa trong hệ thống của bạn.
Ví dụ: JWT có header chứa thuật toán “none”
{
"alg": "none",
"typ": "JWT"
}
Check tham số “kid” có thể bị tấn công injection
Giải thích: “kid” (Key ID) là phần tử trong header dùng để chỉ định khóa nào dùng để ký token. Ta có thể tấn công injection(SQL Injection, OS Command Injection) hoặc Path Traversal vào giá trị của tham số “kid”.
Ví dụ: Kẻ tấn công có thể khai thác lỗ hổng Path Traversal bằng cách sử dụng đường dẫn tới tệp /dev/null, một tệp rỗng có mặt trên hầu hết các hệ thống Linux. Khi máy chủ đọc nó, sẽ trả về một chuỗi rỗng. Vì vậy, kẻ tấn công có thể ký JWT bằng một chuỗi rỗng, sau đó gửi JWT đó đến trang web xác minh JWT, với hi vọng trang web sẽ chấp nhận chữ ký này là hợp lệ.
{
"alg": "HS256",
"typ": "JWT",
"kid": "../../dev/null"
}
Thêm thành phần JWK vào header như khóa công khai.
Giải thích: “jwk” (JSON Web Key) là các thuộc tính được sử dụng để mô tả một khóa mật mã trong định dạng JSON. “jwk” có thể được nhúng trong header của JWT. Tuy nhiên, phía Server có thể lấy khóa công khai (public key) được nhúng từ tham số “jwk” để tiến hành xác minh JWT.
Ví dụ: JWK nhúng vào header.
{
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
}
}
Payload
Check thông tin nhạy cảm trong payload JWT.
Giải thích: Payload của JWT có thể chứa thông tin nhạy cảm như mật khẩu, thông tin thẻ tín dụng, hoặc dữ liệu cá nhân mà không có mã hóa bổ sung.
Ví dụ: Những thông tin nhạy cảm có thể có ở Payload như email, password, role.
{
"sub": "1234567890",
"name": "CookieArena",
"email": "[email protected]",
"role": "admin",
"password": "s3cr3tP@ssw0rd",
"exp": 1671513600
}
Check thời hạn sử dụng của JWT thông qua các thành phần “exp” và “iat”.
Giải thích: “exp” (expiry) xác định thời điểm token hết hạn, còn “iat” (issued at) xác định thời điểm token được phát hành. Cả hai đều giúp giới hạn thời gian tồn tại của token. Nếu mà JWT hết hạn thời gian mà vẫn còn hiệu lực, điều này có thể tạo ra lỗ hổng bảo mật, người dùng có thể không cần đăng nhập những vẫn có thể vào hệ thống.
Ví dụ: Sử dụng công cụ token.dev, trang web thông báo lỗi ở tham số “exp”. Ta trỏ chuột vào thấy thông báo token này hết hạn vào lúc 12g20 ngày 20/12/2022
Signature
Check JWT có thể không thực hiện kiểm tra signature
Giải thích: Khi thực hiện thay đổi 1 trong các thành phần của header hoặc payload mà vẫn có thể truy cập vào hệ thống thì ở phìa Back-end không thực hiện xác thực signature.
Tấn công brute force vào weak secret key của JWT
Giải thích: Phía Back-end sử dụng secret key yếu. Attacker có thể tấn công brute force dựa trên wordlist phổ biến tìm ra secret key và thực hiện giả mạo JWT để truy cập vào hệ thống.
Ví dụ: JWT sử dụng thuật toán HS256. Đoạn code python phía dưới sử dụng lần lượt các key trong wordlist để thực hiện việc dò đoán secret key.
import jwt
# Token đã biết
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.0l7fhxIxwZlN0mfZ8H7kfbns5sJl0oGBW3kHbPy0k2M'
# Duyệt qua các secret key có thể
for secret in list_secret:
decoded = jwt.decode(token, str(secret), algorithms=['HS256'])
print("Tìm thấy secret key:", scret)
Tấn công Timing side-channel attacks vào JWT
Giải thích: Sử dụng thời gian phản hồi từ server để suy ra các thông tin trong JWT. Kẻ tấn công có thể sử dụng kỹ thuật này để suy ra chữ ký hoặc mã hóa của JWT và tạo ra một JWT mới.
Ví dụ: Đoạn code so sánh chữ ký của server với chữ ký mà client gửi đến. Kẻ tấn công đoán độ dài chữ ký bằng cách thử các độ dài khác nhau và đo thời gian xử lý. Sau khi xác định được độ dài, họ đoán từng byte của chữ ký. Nếu byte đầu tiên đoán đúng, thời gian xử lý kéo dài hơn, cho phép tiếp tục đoán byte tiếp theo, và cứ thế tiếp diễn.
import time
def unsafe_compare(a, b):
if len(a) != len(b):
return False
for i in range(len(a)):
if a[i] != b[i]:
return False
time.sleep(0.1) # Giả định thời gian xử lý
return True
What do you think?
It is nice to know your opinion. Leave a comment.