việc bảo mật trong Rails – phần 1

Introduction

hầu như các frameworks phát huy web hiện này đều giúp đỡ và giúp đỡ đỡ các lập trình viêneloper nhiều trong việc tạo dựng các app web. một vài trong chúng còn giúp đỡ bảo mật tốt hơn cho app web. Trong thực tế, không có một framework nào là hoàn hảo: nếu bạn dùng chúng một cách thông minh và khéo léo, bạn có thể tạo dựng các app có độ bảo mật cao với nhiều framework. Ruby on rails có một vài method như vậy, ví dụ như chống lại các cuộc tấn công SQL injection chẳng hạn.

chuyện bảo mật còn phụ thuộc vào người sử dụng framework, đôi khi còn vào phương thức phát huy. Và nó phụ thuộc vào tất cả các tầng của môi trường web: lưu trữ ở back-end, web server và web app. Tập đoàn Gartner ước tính, 75% các vụ tấn công nằm ở tầng web application, và tìm thấy rằng trong 300 website được nghiên cứu, có đến 97% chứa lỗ hổng để tấn công. Bởi vì, các web app này tương đối dễ tấn công, vì chúng rất dễ hiểu và thực thi, ngay cả đối với người bình thường.

Các lỗ hổng đối với các app web bao gồm: chiếm đoạt account người sử dụng, bỏ qua việc kiểm soát vào web, đọc và đổi khác những data nhạy cảm, hay trình bày những content gian lận. Hoặc kẻ tấn công có thể cài đặt một chương trình Trojan, hoặc phần mềm gửi thư không hi vọng, nhằm mục đích xấu. Để ngăn chặn các cuộc tấn công, giảm thiểu tác động của chúng và loại bỏ các lỗ hổng, trước hết bạn phải hiểu đầy đủ các cách thức tấn công để tìm ra biện pháp đối phó chính xác, đó là những gì bài viết này hướng đến.

Sessions

Nơi phù hợp để bắt đầu là với sessions, cái mà khá dễ bị tấn công

Sessions là gì?

    HTTP is a stateless protocol. Sessions make it stateful. 

hầu như các app cần theo dõi trạng thái của một người sử công cụ thể. Ví dụ như content của giỏ mua hàng hoặc id của người sử dụng đang đăng nhập. Nếu không có sessions, người sử dụng phải định danh, authenticate trên mỗi request của mình. Rails sẽ tự động tạo một session mới khi người sử dụng bắt đầu vào web vào app. Về sau, nó sẽ load session đang tồn tại nếu người sử dụng đã dùng app rùi.

Một session là một hash các giá trị và thêm một session ID thường là một chuỗi string 32 kí tự để định danh hash. Mỗi cookie được gửi đến trình duyệt của client chứa ID của session. Và trình duyệt sẽ gửi nó đến server với mỗi request từ client. Trong Rails, bạn có thể save hay get các giá trị đó bằng các method của session:

    session[:user_id] = @current_user.id     User.find(session[:user_id]) 

Session ID

    The session ID is a 32-character random hex string. 

Session ID được generate bằng SecureRandom.hex(sinh ra một string mật mã tùy tiện có độ bảo mật cao dựa trên các platform Open SSL, /lập trình viên/urandom or Win32)

Session Hijacking

    Stealing a user's session ID lets an attacker use the web application in the victim's name. 

hầu như các app web đều có một hệ thống authenticate: một người sử dụng cung ứng user name và password, tiếp theo app web kiểm tra và lưu user id tương ứng vào session. Với mỗi request từ người sử dụng, app web sẽ chính xác user bằng user id của session mà không cần một authenticate mới.

Cookie đóng vai trò chính xác ngắn hạn cho các app web. Do vậy, bất kì ai lấy được cookie đó có thể dùng các app web như với quyền của người sử dụng đó, với những hậu quả nghiêm trọng có thể diễn ra. sau đây là một vài cách để hack một session và các biện pháp để đối phó với chúng:

Sniff cookie trong một mạng không an toàn, chẳng hạn như một mạng LAN không dây, Với một mạng LAN không dây không được mã hóa, thật là rất dễ để nghe được các traffic của tất cả các clients đã liên kết. Đứng về góc nhìn của nhà phát huy web, ta cần cung ứng một liên kết an toàn qua SSL. Kể từ Rails 3.1 trở đi, điều này có thể thực hiện bằng việc config SSL trong file config

    config.force_ssl = true 

hầu như người sử dụng không có thói quen clear cookie sau khi vào web tại một điểm internet công cộng nào đó, như quán nét chẳng hạn. Vì vậy, nếu người sử dụng cuối quên chưa log out khỏi app web, bạn có thể thể dùng chúng với quyền user này. Hãy cung ứng một button log-out trong app của bạn và đặt nó ở chỗ bắt mắt. Có nhiều các cuộc tấn công cross-site scripting (XSS) nhắm vào cookie của người sử dụng. cụ thể hơn bạn có thể tham khảo tại: http://guides.rubyonrails.org/security.html#cross-site-scripting-xss

Session Guidelines

Không lưu trữ những objects lớn trong một session. Thay vào đó, bạn nên lưu chúng và database và save id của chúng trong session. Điều này sẽ rất dễ trong việc đồng bộ và tránh tràn bộ nhớ session. Đây cũng là một sáng kiến hay, nếu bạn sửa đổi cấu trúc của một đối tượng, thì bạn vẫn rất dễ đồng bộ chúng vì bạn chỉ lưu id của đối tượng trong session. data quan trọng không nên lưu trong session. Nếu người sử dụng xóa cookie của họ hoặc đóng trình duyệt, chúng sẽ bị mất.

Session Storage

    Rails provides several storage mechanitin nhắn for the session hashes. The most important is ActionDispatch::Session::CookieStore. 

Rails 2 đã giới thiệu một storage cho session, CookieStore. CookieStore save session hash trực tiếp tại cookie phía client. Phía server nhận session hash từ cookie và get session ID. Điều đó sẽ làm tăng đáng kể tốc độ của app, nhưng đó là một storage gây tranh cãi và bạn phải nghĩ về các chuyện bảo mật xung quanh nó:

Cookies lưu trữ được tối đa data 4kB. Điều này hoàn toàn hợp lý vì không nên lưu trữ một lượng data lớn trong một session. Thường chỉ lưu id của database trong cookies. Client có thể xem mọi thứ mà bạn lưu trữ trong một session, bởi vì nó được lưu trữ ở dạng clear-text(dạng base64 encoded). Vì vậy bạn không thích lưu trữ bất kì data bí mật ở đây. Để ngăn chặn giải mạo, một digest đã được tạo từ session với một secret phía server(secrets.secret_key) và chèn vào phần cuối của cookie.

mặc dù vậy, kể từ Rails 4, storage default là EncryptedCookieStore. Với EncryptedCookieStore, session được mã hóa trước khi được lưu trữ vào cookie. Điều này sẽ ngăn chặn người sử dụng vào web và giải mạo content của cookie. Do vậy session trở thành một nơi an toàn để lưu trữ data. secrets.secret_key được lưu trong config/secrets.yml

Do vậy, chuyện bảo mật phụ thuộc hoàn toàn vào secret key này, và một giải thuật digest(thường default là SHA1). secrets.secret_key_base được dùng như một khóa đặc sắc cấp quyền session được verify lại nhằm ngăn chặn giả mạo.

    lập trình viênelopment:       secret_key_base: a75d...      test:       secret_key_base: 492f...      production:       secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 

Replay Attacks for CookieStore Sessions

    Another sort of attack you have to be aware of when using CookieStore is the replay attack. 

Nó làm việc như sau:

Một người sử dụng get account tín dụng, số tiền được lưu trong session(đó là sáng kiến tồi tệ, nhưng giả sử vậy) người sử dụng mua thứ gì đó Số tiền tín dụng giảm và giá trị mới được đổi khác trong session người sử dụng copy cookie từ bước trước khi mua và replace vào cookie mới người sử dụng có account nguyên bản khi chưa mua

Việc add thêm một Nonce trong session sẽ giải quyết được replay attacks. Một nonce chỉ valid một lần, và server phải theo dõi tất cả nonces valid. Công việc trở nên phức tạp hơn nếu hệ thống chạy trên một vài servers. Lưu trữ nonces trong database sẽ ngăn chặn tất cả muc đích của CookieStore
phương án tốt nhất chống lại nó là không lưu trữ bất kì data loại này trong session, mà chỉ lưu trong database. Trong tình thế này thì tin tức credit nên lưu trong database, còn logged_in_user_id trong session

Session Fixation

    Apart from stealing a user's session ID, the attacker may fix a session ID known to them. This is called session fixation. 

Phía bên trên là sơ đồ một cuộc tấn công session fixation. Cuộc tấn công nhắm vào việc đổi khác ID session của nạn nhân để tấn công, ép trình duyệt của nạn nhân dùng một ID session nào đó mà không rất cần ăn cắp session ID của người sử dụng, các bước được cụ thể hóa như sau:

Hacker tạo một session ID hợp lệ tại một hệ thống tín dụng nào đó chẳng hạn, login đăng nhập và get lấy một session ID hợp lệ, như hành động 1 và 2 vào web định kì vào app để giữ session luôn ở trạng thái action Kẻ tấn công xâm nhập và đổi khác buộc trình duyệt của người sử dụng dùng session ID bên trên(hành động số 3). Do không thể đổi khác cookie của một tên miền khác nên hacker có thể chạy một mã javascript từ tên miền của app mục tiêu. Ịnjection một mã JS vào app bằng XSS. Ví dụ như:

    <script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script> 

Kẻ tấn công bẫy nạn nhân click vào một trang có chứa mã Javascript đó. Do vậy trình duyệt nạn nhận sẽ tự động đổi khác session ID Khi session ID bẫy được dùng, nạn nhận vào web lại hệ thống tín dụng và tất nhiên, yêu cầu chính xác để login. Kể từ giờ đây cả nạn nhân và hacker đồng thời dùng hệ thống tín dụng với cùng một session. Session có hiệu lực mà nạn nhân không hề hay biết

Session Fixation – Countermeasures

    One line of code will protect you from session fixation. 

Cách giải quyết có tác dụng nhất là định danh một session mới và loại bỏ session cũ sau khi đăng nhập thành công. Bằng cách đó, hacker không thể dùng session cố định. Đây cũng là một biện pháp có tác dụng chống ăn cắp session. sau đây là cách để tạo ra một session mới trong Rails:

    reset_session 

Nếu bạn đang dùng gem lập trình viênise, nó sẽ tự động tạo mới và hết hạn các session ID sau khi bạn đăng nhập. Sau khi đăng nhập session cũ bị loại bỏ và session mới được sinh ra.
Một biện pháp đối phó khác là lưu các thuộc tính đặc trưng của người sử dụng trong session, xác minh chúng mỗi lần request, và deny nếu không hợp lệ. Chẳng hạn như địa chỉ IP hoặc tên trình duyệt web. Khi lưu địa chỉ IP, bạn phải nhớ rằng các nhà cung ứng dịch vụ internet ẩn người sử dụng của họ đằng sau các proxy

Session Expiry

    Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking and session fixation. 

Có thể set thời gian hết hạn expires date của cookie với một session ID. mặc dù vậy, phía client có thể edit cookie trong trình duyệt nên việc set expires cho session phía server sẽ an toàn hơn. sau đây là ví dụ để set expires của session trong database:

    class Session < ApplicationRecord       def self.sweep(time = 1.hour)         if time.is_a?(String)           time = time.split.inject { |count, unit| count.to_i.send(unit) }         end          delete_all "updated_at < '#{time.ago.to_s(:db)}'"       end     end 

Lời kết

Trên đây là cách thức làm việc, tấn công và cách thức phòng tránh đối với kiểu tấn công session. Ở bài kế tiếp ta sẽ tìm hiểu về kiểu tấn công Cross-Site Request Forgery(CSRF). Thanks for reading!

Nguồn:

http://guides.rubyonrails.org/security.html

Nguồn viblo.asia