Rails security checklist

Lỗi về bảo mật trong một Rails App có thể phát sinh từ nhiều nguồn khác nhau, sau đây là một số biện pháp tránh gây ra các lỗi về bảo mật mà mình tổng hợp được từ một số bài viết hay trên mạng như: Zen Rails Security Checklist

Injection

Injection là lỗi bảo mật lúc nào cũng nằm trong top những lỗi bảo mật nguy hiểm nhất bởi dễ thực hiện mà tác hại lại rất cao.

  • Không sử dụng cách viết thường dùng ("#{foo}...") cho những nơi user có thể nhập string để submit data mà sử dụng string ấy cho ActiveRecord hoặc SQL query thuần. Hãy sử dụng ký tự ? và bind data vào câu query thông qua việc sử dụng ActiveRecord::Sanitization methods to sanitize. Việc làm này giúp ta tránh được tấn công SQL injection , một dạng injection nguy hiểm khi tác động trực tiếp vào dữ liệu trong cơ sở dữ liệu của bạn.
  • Không sử dụng những ký tự user có thể nhập cho những câu lệnh commands line như eval() , system, syscall, %x(), popen<n>, File.read, File.writeexec.

Xác thực người dùng(Authentication)

Bị phá vỡ xác thực người dùng và quản lý Session cũng là một lỗi nguy hiểm trong những lỗi về bảo mật, để tránh lỗi này, ta cần chú ý:

  • Chỉ bỏ qua xác thực người dùng nếu như biết chắc chắn rằng việc không sử dụng xác thực người dùng là cần thiết. Nên sử dụng những gem như Devise, Authlogic hoặc Clearance, đây là những gem hỗ trợ cho việc xác thực người dùng.
  • Đảm bảo chiều dài của trường password ít nhất là 8 ký tự hoặc nhiều hơn để tránh brute-force attacks.Một mật khẩu quá ngắn thì dẫn đến dễ đoán ra, đặc biệt là đối với những phần mềm có khả năng auto nhập và dò password.Đối với những ứng dụng sử dụng Devise thì config sẽ rất đơn giản trong file config/initializers/devise.rb. như sau:
    Devise: set config.password_length = 8..128
    
  • Xem xét validate password đối với:
  1. Sử dụng từ điển (Dictionary words), khi mà password đã có yêu cầu độ dài tối thiểu thì từ điển chỉ cần bao gồm các từ đáp ứng được yêu cầu đó
  2. Xem xét đánh giá độ mạnh của password, bạn có thể tham khảo các gem sau: password_strength StrongPassword
  • Xem xét về viêc đề ra các quy tắc về độ phức tạp của password, nhiều ứng dụng sử dụng điều này, điều này cũng góp phần tránh được brute-force attacks.
  • Khóa tạm thời đối với những tài khoản đăng nhập nhiều lần không thành công.Chẳng hạn như đối với Devise hãy sử dụng lockable module(brute-force attacks)
  • Yêu cầu người dùng confirm lại mật khẩu dùng để đăng ký tài khoản và khi thay đổi địa chỉ email.Đối với Devise hãy sử dụng confirmable module và set config.reconfirmable = true trong file config/initializers/devise.rb.
  • Yêu cầu người dùng nhập lại password cũ khi thay đổi password.Đây là mặc định trong Devise.
  • Sét hết hạn session khi user đăng xuất và những session cũ khi user đăng nhập thành công.(CSRF, session hijackingsession fixation attacks).
  • Sét hết hạn session sau 1 khoảng thời gian không active(ví dụ: 30 phút).Đối với Devise hãy sử dụng timeoutable module .(CSRF, session hijackingsession fixation attacks).
  • Nhắc nhở người dùng khi password thay đổi.Điều này không thể ngăn cản kẻ tấn công thay đổi mật khẩu người dùng, nhưng việc này giúp cho người dùng có thể biết được password của mình đã được thay đổi bởi người khác và liên lạc với nguời quản trị hệ thống để vô hiệu hóa quyền truy cập cảu kẻ tấn công.Trong Devise có thể setting như sau trong file config/initializers/devise.rb :
Devise: set config.send_password_change_notification = true
  • Sử dụng những câu thông báo chung chung đại loại như: "Invalid email or password" thay vì chỉ ra chính xác thông tin nào sai(email hay password)
  • Hãy chắc chắn đối với những controller/actions cần phải đăng nhập thì phải xác minh đăng nhập trước đó.Đối với Devise ta có thể sử dụng:
before_action :authenticate_user!

và sử dụng như sau để bỏ yêu cầu xác thực người dùng:

skip_before_action :authenticate_user!
  • Không lưu những thông nhạy cảm của người dùng vào cookiehoặc CookieStore Session.
  • Mã hóa những thông tin cần thiết được lưu trong cookie
  • Sét httponly: true khi mà bạn không cần đọc cookie từ client.

Cross-Site Scripting (XSS)

  • Luôn validate những thông tin user này nhập được mà user khác có thể nhìn thấy, đưa những chuỗi ký tự nguy hiểm vào Blacklist, ví dụ như sau
  • Cân nhắc việc sử dụng gem loofah-activerecord để lọc các giá trị cho attribute model của bạn.
  • Nếu bắt buộc phải tạo links từ những URL user nhập vào, hãy chắc chắn validate chúng.Nếu sử dụng regex, chắc chắn rằng chuỗi ký tự phải bắt đầu bằng những gì bạn mong muốn, chẳng hạn: \Ahttps?.
  • Khi sử dụng regex cho validate input, hãy sử dụng \A\z để khớp các ký tự đầu và cuối của string.Không dùng ^$.
  • Dù có hay không validate ở client thì validate trên server phải là bắt buộc, kể cả trong trường hợp validate dưới client rồi, vì validate client có thể bị phá vỡ.
  • Không gửi những chuỗi string mà user nhập trong email tới những user khác.Đối với những trường nhập text field bất kỳ không có validate URL trong đó.

Cross-Site Request Forgery (CSRF)

  • Sử dụng protect_from_forgery with: :exception trong mọi controllers trong tất cả các controller sử dụng cho web view hoặc trong ApplicationController.
  • Không sử dụng GET để thay đổi trạng thái tài nguyên, nếu tránh được thì nên tránh sử dụng GET.
  • Ở Rails 4 chỉ có một CSRF token cho toàn bộ form, action và method.Rails 5 có thể sử dụng CSRF token cho mỗi form bằng setting:
config.action_controller.per_form_csrf_tokens = true

Định tuyến, chuyển hướng.

  • Không chuyển hướng URL dựa trên những gì mà user nhập vào.Nói cách khác, không sử dụng những gì user nhập cho redirect_to.Nếu không còn lựa chọn nào khác, thì hãy validate những gì user nhập vào.
  • Không sử dụng những gì user nhập vào để xác định template view hiển thị, nó có thể là cách để truy cập vào những trang mà bạn chỉ muốn nó dành cho quản trị viên .
  • Không sử dụng "catch-all" routes kiểu như: match ':controller(/:action(/:id(.:format)))' và cho những method trong controller private nếu có thể.

Files update and download

  • Tránh sử dụng những file name user submit để đặt tên cho file khi lưu lại.Nếu được, hãy sử dụng một tên ngẫu nhiên hoặc sinh ra 1 chuỗi bất kỳ để add vào tên file mà user submit lên.Nếu không thể làm như thế thì chí ít hãy đảm bảo validate tên file cẩn thận với những ký tự cho phép và không cho phép trong file name.
  • Hạn chế sử dụng những thư viện có nhiều lỗ hổng bảo mật như ImageMagick để xử lý ảnh và video.Nếu được hãy dùng Transloadit, Cloundinary, imgix.Tham khảo thêm tại đây.
  • Nếu sử dụng gem paperclip với imagemagick để upload file, hãy đảm bảo:
  1. Các chính sách của ImageMagick phù hợp với môi trường của bạn để tránh bị khai thác như pixel flood attack.
  2. Xử lý các nội dung giả mạo thủ công vì nó có thể fail trong các trường hợp như #2426.
  • Xử lý các tệp tải lên không đồng bộ, nếu không được, hãy hạn chế tỉ lệ đối với mỗi client.
  • Không chỉ dừng lại ở validate client, hãy chắc chắn bạn có validate server.
  • Validate file trước khi xử lý.
  • Nên hạn chế những file type cho phép upload.
  • Đề ra file size tối đa có thể upload.
  • Xem xét upload file từ client lên những server như S3 hoặc dịch vụ khác tương tự thay vì server của bạn.
  • Nếu cho phép tải lên những file có khả năng có phần mềm độc hại(exe, msi, zip, rar, pdf), hãy quét virut/malware.Nếu có thể, hãy sử dụng dịch vụ của bên thứ 3.
  • Nếu cho phép tải lên các file đóng gói như zip, rar và gz, validate đường dẫn hợp lệ của đối tượng, ước lượng size và types của file khi giải nén.
  • Không cho phép download tên file và đường dẫn mà user submit.Nếu không được, hãy chắc chắn validate để đảm bảo những filename và đường dẫn hợp lệ.