Computer >> Máy Tính >  >> Lập trình >> Ruby

Rails Security Threats:Authentication

Phần một của loạt bài này, có đề cập đến Các cuộc tấn công bằng tiêm

Trong bài viết thứ hai của loạt bài về 10 Rủi ro Bảo mật Ứng dụng Web Hàng đầu của OWASP, chúng tôi sẽ đi sâu vào vũ trụ của các mối đe dọa xác thực bị hỏng và phơi nhiễm dữ liệu.

Cụ thể hơn, chúng ta sẽ nói về việc một tin tặc dễ dàng đánh lừa mã bạn đã tạo và thực hiện các cuộc tấn công để lấy dữ liệu của người dùng như thế nào:

  • Danh sách người dùng :Khi họ khai thác các trang đăng nhập của bạn bằng cách kiểm tra bạo lực một danh sách những người dùng có thể có chỉ để kiểm tra xem họ có tồn tại trong cơ sở dữ liệu của bạn hay không.
  • Mật khẩu yếu :Khi hệ thống của bạn cho phép mật khẩu yếu, tin tặc có thể thực hiện một cuộc tấn công thô bạo để đoán mật khẩu của người dùng của bạn.
  • Cookie không hạn chế :Khi hệ thống của bạn lưu trữ dữ liệu nhạy cảm trong cookie mà không có cài đặt bảo mật thích hợp, tin tặc có thể lấy cắp thông tin thông qua các cuộc tấn công XSS.

Chúng tôi cũng sẽ đi vào chi tiết về dữ liệu nhạy cảm không được bảo vệ đầy đủ, tạo chỗ cho các lỗ hổng, chẳng hạn như sau:

  • Bộ nhớ nhạy cảm không an toàn :khi dữ liệu nhạy cảm được mã hóa bằng các thuật toán yếu, chẳng hạn như MD5.
  • Tiết lộ dữ liệu nhạy cảm :ví dụ:khi nhà phát triển vô tình để lộ dữ liệu nhạy cảm không được mã hóa trong URL hoặc trường ẩn.

Như với bài viết đầu tiên của loạt bài này, chúng tôi cũng sẽ sử dụng RailsGoat để khám phá từng mối đe dọa này trong thực tế. Nếu bạn là người mới ở đây, vui lòng tham khảo bài viết trước để thiết lập và chạy ứng dụng.

Hãy bắt tay ngay vào!

Đe dọa xác thực

Chúng ta không thể sống mà không có xác thực. Cho dù đó là trên các API back-end hay trong các biểu mẫu front-end của bạn, đây là một trong những bước quan trọng nhất trong quá trình phát triển ứng dụng vì nó nêu bật các giới hạn biên giới của các biện pháp bảo mật của bạn.

Không chỉ cho bản thân xác thực mà cho những gì tiếp theo:quản lý phiên. Bạn sẽ lưu trữ mật khẩu và mã thông báo của mình ở đâu? Chúng có được mã hóa đúng cách không? Bạn có đang sử dụng một thuật toán đáng tin cậy không? Mật khẩu của bạn có đủ phức tạp không?

Có rất nhiều câu hỏi để theo dõi. Hãy phân tích chúng một chút và hiểu một số cuộc tấn công phổ biến liên quan đến xác thực và quản lý phiên trong các ứng dụng Rails.

Danh sách người dùng

Liệt kê người dùng là một kỹ thuật nổi tiếng mà những kẻ tấn công sử dụng để kiểm tra (thông qua việc sử dụng vũ lực) liệu dữ liệu đã cho có tồn tại trong hệ thống của bạn hay không.

Một trong những ví dụ khét tiếng nhất của cuộc tấn công này xảy ra với trang đăng nhập Facebook hiện tại. Nếu bạn nhập một số thông tin đăng nhập không hợp lệ và ngẫu nhiên như được hiển thị trong hình ảnh bên dưới, Facebook sẽ xử lý yêu cầu và kiểm tra sự tồn tại của người dùng trong cơ sở dữ liệu của họ.

Rails Security Threats:Authentication

Trang đăng nhập của Facebook.

Khi bạn nhấp vào nút Đăng nhập , Facebook sẽ trả lại thông báo lỗi cho biết tên người dùng của bạn (có thể là email hoặc số điện thoại) không hợp lệ.

Rails Security Threats:Authentication

Thông báo tên người dùng không hợp lệ.

Do đó, kẻ tấn công biết rằng ứng dụng cho bạn biết liệu một người dùng đã được đăng ký hay chưa. Miễn phí.

Nếu kẻ tấn công có danh sách các email (cho dù chúng được tạo ngẫu nhiên hoặc mua ở đâu đó), thì cũng có thể hỏi ứng dụng xem mật khẩu có đúng không:

Rails Security Threats:Authentication

Thông báo mật khẩu không hợp lệ.

Sau khi kẻ tấn công biết cách hệ thống phản hồi riêng biệt với từng xác thực, một danh sách có thể được tạo gồm possible users và mật khẩu phổ biến / yếu. Sau đó, các bài kiểm tra bạo lực có thể được tiến hành lặp đi lặp lại đối với hệ thống cho đến khi có được quyền truy cập.

Tất nhiên, các nhà phát triển Facebook biết về điều này và đó là lý do tại sao họ triển khai các biện pháp bảo vệ bổ sung, chẳng hạn như hình ảnh xác thực ẩn và xác thực đối với số lượng yêu cầu đến từ một địa chỉ IP cụ thể.

Một trong những điều bạn có thể làm để tránh liệt kê người dùng là xác thực cả tên người dùng và mật khẩu cùng nhau và trả về một thông báo chung. Hãy xem cách tiếp cận này hoạt động!

Mối đe dọa trong hành động

Trong ứng dụng RailsGoat, hãy mở user.rb tệp trong ứng dụng / mô hình và định vị authenticate phương pháp. Trong đó, bạn có thể tìm thấy đoạn mã sau:

raise "#{email} doesn't exist!" if !(user)
if user.password == Digest::MD5.hexdigest(password)
  auth = user
else
  raise "Incorrect Password!"
end

Một cách chính xác! Các thông báo đang được thiết lập theo cách cho phép những kẻ tấn công biết liệu người dùng không tồn tại hoặc mật khẩu không chính xác.

Kiểm tra nó ra. Truy cập trang đăng nhập RailsGoat và nhập một email và mật khẩu ngẫu nhiên. Bạn có thể thấy thông báo lỗi sau:

Rails Security Threats:Authentication

Người dùng không tồn tại.

Ngược lại, nếu người dùng tồn tại ( ken@metacorp.com , chẳng hạn) nhưng mật khẩu sai, thông báo sau được hiển thị:

Rails Security Threats:Authentication

Mật khẩu không chính xác.

Xét rằng ứng dụng của bạn chỉ cho phép mật khẩu mạnh, kẻ tấn công vẫn có thể tạo danh sách các email khách hàng hợp lệ được liệt kê và nhắm mục tiêu các email lừa đảo đến họ, tạo ấn tượng rằng bạn là người đang yêu cầu hành động độc hại.

Cách Giải quyết Vấn đề này

Hành động nhanh nhất mà bạn có thể thực hiện để đảm bảo an toàn hơn là thay đổi thông điệp của bạn và làm phức tạp thêm cuộc sống của tin tặc.

Trong sessions_controller.rb (app/controllers thư mục), định vị create và thay đổi đoạn mã sau

flash[:error] = e.message

như sau:

flash[:error] = "Your credentials aren't valid."

Giờ đây, mỗi khi người dùng nhập sai tên người dùng hoặc mật khẩu, đó là thông báo họ sẽ nhận được:

Rails Security Threats:Authentication

Thông tin đăng nhập không hợp lệ.

Một cách khác để làm điều đó là thay đổi hai thông báo trong users.rb mô hình.

Mật khẩu yếu

Chúng ta không thể nhấn mạnh điều này đủ. Yêu cầu người dùng của bạn nhập mật khẩu mạnh và đảm bảo tạo một số mã xác thực để kiểm tra xem chúng có đáp ứng các tiêu chí cho một mật khẩu mạnh hay không.

Đây là một trong những bước quan trọng nhất để ngăn chặn việc liệt kê người dùng.

Đe doạ đang thực hiện

Trong RailsGoat, mở user.rb tập tin và định vị dòng mã đầu tiên ngay trước định nghĩa lớp:

validates :password,
    presence: true,
    confirmation: true,
    length: {
      within: 6..40
    },

    ...

Đây là một ví dụ rõ ràng về việc mật khẩu được xác thực yếu vì chỉ kiểm tra độ dài của nó.

Cách Giải quyết Vấn đề này

Giải pháp khá đơn giản; xác thực mật khẩu của bạn theo một số yêu cầu mạnh hơn, chẳng hạn như sau:

  • ít nhất 1 chữ thường và 1 chữ hoa,
  • ít nhất 1 chữ số,
  • ít nhất 10 ký tự.

Bạn càng thêm nhiều yêu cầu, mật khẩu của bạn càng an toàn. Chỉ cần đảm bảo không đẩy quá nhiều vì điều này có thể dẫn đến sự gia tăng độ phức tạp trong quy trình khôi phục mật khẩu và khả năng sử dụng.

Để giải quyết vấn đề này trong RailsGoat, chỉ cần thay thế thuộc tính length bằng thuộc tính sau:

:format => {:with => /\A.*(?=.*[a-zA-Z])(?=.*[0-9])(?=.{10,}).*\z/},

Sau đó, truy cập trang đăng ký, điền vào các trường và cung cấp mật khẩu yếu. Khi bạn gửi, đây sẽ là thông báo lỗi được hiển thị:

Rails Security Threats:Authentication

Mật khẩu không hợp lệ.

Cookies không hạn chế

Trong bài viết trước, chúng tôi đã dành một chút thời gian để tìm hiểu cách thức các cuộc tấn công XSS xảy ra. Vì chúng diễn ra bằng cách cho phép kẻ tấn công chạy các tập lệnh độc hại, thông tin quan trọng có thể bị đánh cắp từ cookie phiên nếu chúng tôi không ngăn quyền truy cập vào các thuộc tính, chẳng hạn như document.cookie trong mã JavaScript của bạn.

Hãy nhớ rằng tranh chấp giữa lưu trữ Web và cookie thường được thảo luận trong cộng đồng. Mặc dù lưu trữ trên Web thực tế hơn, nhưng kẻ tấn công có thể có toàn quyền truy cập vào các đối tượng được lưu trữ ở đó mà không có sự bảo vệ thích hợp khỏi các mối đe dọa XSS.

Đổi lại, cookie sẽ an toàn hơn một chút nếu bạn thực hiện đúng các bước để làm cho chúng như vậy, chẳng hạn như đặt HttpOnly cờ.

Nói tóm lại, một cookie chứa thông tin phiên và được đặt bằng HttpOnly Không thể truy cập cờ từ JavaScript Document.cookie API. Bằng cách này, chỉ máy chủ mới nhận được.

Ngoài ra, chúng tôi cũng có Secure thuộc tính này sẽ đảm bảo rằng cookie chỉ được gửi đến máy chủ nếu (và chỉ khi) yêu cầu xảy ra trong HTTPS (không bao giờ trong HTTP). Điều này sẽ giúp các yêu cầu của bạn an toàn hơn trong trường hợp ai đó đánh hơi thấy chúng là người ở giữa .

Đe doạ đang thực hiện

Rails thực hiện một bước cho bạn bằng cách tự động thiết lập tất cả cookie với HttpOnly lá cờ. Điều này thật tuyệt vời vì nó giúp các nhà phát triển không hiểu biết tránh bị tấn công ứng dụng của họ.

Để kiểm tra ví dụ này, chúng tôi sẽ phải tắt tính năng này, điều mà RailsGoat đã thực hiện một cách rõ ràng trong session_store.rb , nằm trong config/initializers thư mục. Kiểm tra nó ra!

Sau đó, hãy truy cập trang đăng ký một lần nữa, điền vào các trường một cách chính xác và nhập nội dung sau vào Tên lĩnh vực:

<script>
  alert(document.cookie);
</script>

Khi bạn gửi biểu mẫu, người dùng sẽ được tạo, cùng với thông báo cảnh báo tiếp theo sau:

Rails Security Threats:Authentication

Thông báo cảnh báo tiết lộ cookie phiên RailsGoat.

Cách Giải quyết Vấn đề này

Trong trường hợp này, điều đó khá đơn giản, chỉ cần đảm bảo không tắt HttpOnly gắn cờ trên các ứng dụng Rails của bạn.

Vì vậy, hãy xóa httponly: false thiết lập và khởi động lại máy chủ. Khi bạn cố gắng thực hiện cùng một thao tác, thông báo cảnh báo sau sẽ được hiển thị:

Rails Security Threats:Authentication

Thông báo cảnh báo trống.

Các tình huống khác

Hãy tưởng tượng rằng bạn đang truy cập một ứng dụng Web từ các máy tính không an toàn, chẳng hạn như máy tính trong thư viện công cộng hoặc nhà mạng LAN. Nếu ứng dụng không được định cấu hình để đăng xuất bạn đúng cách sau một khoảng thời gian không hoạt động cụ thể, thì phiên của bạn sẽ vẫn ở đó.

Chỉ cần đóng một tab trình duyệt là không đủ để đăng xuất khỏi ứng dụng.

Một vấn đề phổ biến khác trong mã của nhà phát triển là khi bạn để lộ bất kỳ loại ID nào trong giao diện người dùng. Không khó để nghĩ ra các tình huống trong đó việc giữ ID của người dùng trong một đầu vào ẩn hoặc thậm chí trong URL sẽ giúp cuộc sống của bạn dễ dàng hơn khi người dùng yêu cầu thêm một thứ gì đó khác từ máy chủ.

Tuy nhiên, đây là một cuộc tấn công ăn cắp giữa chừng.

Phơi nhiễm dữ liệu nhạy cảm

Chủ đề này có lẽ là một trong những chủ đề bị đánh giá thấp nhất về việc dành đủ nỗ lực để đảm bảo tính bảo mật của thông tin nhạy cảm.

Cho dù dữ liệu của bạn đang chuyển liên tục hay ở trạng thái nghỉ, việc tách biệt dữ liệu thông thường khỏi dữ liệu nhạy cảm là vô cùng quan trọng. Dữ liệu nhạy cảm bao gồm số và mã thẻ tín dụng, mật khẩu, số nhận dạng cá nhân hoặc bất kỳ thứ gì liên quan đến luật tuân thủ hoặc quyền riêng tư (chẳng hạn như GDPR của EU và PCI).

Ngoài ra, tùy thuộc vào lĩnh vực kinh doanh cụ thể mà ứng dụng của bạn đang hoạt động, điều quan trọng là phải tham khảo luật pháp địa phương để xác định xem các quy tắc tuân thủ khác cũng được áp dụng hay không.

Dưới đây là một số ví dụ rõ ràng về lỗ hổng này:

  • Bằng cách nào đó, dữ liệu của bạn có được mã hóa hoặc truyền tải dưới dạng văn bản thuần túy qua Web không?
  • Nếu bạn mã hóa dữ liệu, bạn đang sử dụng thuật toán nào? Nó có mạnh mẽ và đáng tin cậy để chống lại các loại tấn công tiền điện tử mới nhất không?
  • Bạn có sử dụng các khóa mật mã mặc định nếu không có khóa nào được cung cấp không?
  • Bạn đã kiểm tra xem các yêu cầu HTTP của mình có được thực thi bởi các tiêu đề bảo mật thích hợp không?

Hãy phân tích một số tình huống phổ biến nhất.

Lưu trữ nhạy cảm không an toàn

Nếu bạn đã làm việc với các ứng dụng Web một thời gian, rất có thể bạn đã nghe nói về (hoặc có thể đã sử dụng) thuật toán thông báo MD5. Mặc dù nó vẫn được sử dụng rộng rãi để băm mật khẩu, nhưng nó đã được chứng minh là cực kỳ yếu.

Đây là điều quan trọng để hiểu sự khác biệt giữa băm và mã hóa thông tin. Mã hóa được cho là xảy ra khi một số loại khóa được sử dụng để giải mã dữ liệu. Hashing đề cập đến phương pháp chuyển đổi; bạn có thể biến dữ liệu thành hàm băm nhưng không thể ngược lại.

Điều này áp dụng cho tất cả các loại thông tin nhạy cảm, mặc dù MD5 chủ yếu được biết đến với việc sử dụng băm mật khẩu. Ví dụ:nếu ứng dụng của bạn giữ Số an sinh xã hội (SSN) của người dùng, hãy đảm bảo không chỉ lưu trữ chúng một cách an toàn trong cơ sở dữ liệu của bạn mà còn theo dõi cách dữ liệu được truyền qua ứng dụng của bạn tới các cơ sở dữ liệu khác và đặc biệt là trình duyệt.

Đe doạ đang thực hiện

Như chúng ta đã thấy, RailsGoat cố tình lưu trữ mật khẩu của người dùng dưới dạng băm MD5. Bạn có thể thấy điều này trong user.rb mô hình:

def hash_password
  if self.password.present?
      self.password = Digest::MD5.hexdigest(password)
  end
end

Mỗi khi người dùng đăng nhập, ứng dụng sẽ băm mật khẩu được cung cấp và kiểm tra xem kết quả có bằng nhau hay không. Nếu không, mật khẩu không khớp, do đó sẽ xảy ra lỗi.

Cách Giải quyết Vấn đề này

Có nhiều cách để giải quyết vấn đề này, nhưng có lẽ một trong những cách nổi tiếng nhất là thông qua phương pháp băm muối, chẳng hạn như phương pháp được cung cấp bởi BCrypt.

Mặc dù Rails đi kèm với các khả năng mặc định để đối phó với Bcrypt, một lib khét tiếng đã được sử dụng rộng rãi cho mục đích này:bcrypt-ruby:

gem install bcrypt

Khi bạn ánh xạ mô hình của mình với nó, mật khẩu được đặt và lấy từ cơ sở dữ liệu sẽ được xác định như thế nào. Lib tự động điều chỉnh mọi thứ khác:

require 'bcrypt'

class User < ActiveRecord

  include BCrypt

  def password
    @password ||= Password.new(password_hash)
  end

  def password=(new_password)
    @password = Password.create(new_password)
    self.password_hash = @password
  end
end

Tuy nhiên, quy trình yêu cầu một cột chuỗi bổ sung (password_hash ) tại bảng để lưu trữ băm mật khẩu cho thuật toán BCrypt.

Bằng cách này, bạn có thể đặt giá trị mật khẩu trực tiếp cho đối tượng mô hình và BCrypt sẽ đảm nhận việc băm nó một cách an toàn. Điều tương tự cũng sẽ xảy ra khi mật khẩu được truy xuất để so sánh với thông tin đầu vào của người dùng.

Phơi bày quá nhiều

Cho dù bạn đang làm việc với API REST hay điểm cuối GraphQL chẳng hạn, hãy đảm bảo chỉ trả lại những gì cần thiết để ứng dụng khách hoạt động.

Nếu ứng dụng khách JavaScript của bạn yêu cầu thông tin từ một API và chỉ sử dụng một phần của nó, nó không cản trở kẻ tấn công lấy điểm cuối của bạn và gọi nó một lần nữa để truy xuất toàn bộ phản hồi hoặc phát hiện ra bằng công cụ proxy.

Luôn xem xét các API của bạn để xác nhận rằng bất kể thông tin nhạy cảm được trả lại là gì, nó sẽ chỉ làm như vậy với mã hóa thích hợp và ở đúng vị trí.

Đe doạ đang thực hiện

Khi nói đến dữ liệu của người dùng, điều quan trọng là tạo cơ chế an toàn để đảm bảo thông tin nhạy cảm không bị rò rỉ.

Mở users_controller.rb tệp trong api/v1 thư mục. Tại đó, bạn sẽ tìm thấy phương pháp sau:

def show
  respond_with @user.as_json
end

Đơn giản như nó là, khi được truy cập bởi máy khách Web, điểm cuối này sẽ trả về tất cả các trường của người dùng được điền trong phản hồi, bao gồm cả mật khẩu.

Không chỉ người dùng user cũng như các mô hình khác chứa thông tin nhạy cảm cần có cách chọn các thuộc tính sẽ hiển thị với các API.

Cách Giải quyết Vấn đề này

May mắn thay, Rails cung cấp một cách rất dễ dàng để đối phó với nó. Hãy ghi đè as_json phương pháp như sau:

def as_json
  super(only: [:id, :email])
end

Bây giờ, thay vì hiển thị mọi thứ theo mặc định, chúng tôi chỉ phản hồi với dữ liệu được yêu cầu. Đối với mỗi mô hình, hãy đảm bảo chọn các trường quan trọng và áp dụng cùng một quy tắc chung.

Kết thúc

Hôm nay, chúng tôi đã điều hướng qua vùng xác thực bị hỏng và phơi nhiễm dữ liệu nhạy cảm. Bằng cách tuân theo các quy tắc này, chắc chắn bạn sẽ đảm bảo một ứng dụng an toàn hơn nhiều cho người dùng và khách hàng của mình.

Ngoài ra, tầm quan trọng của việc xem qua Tài liệu bảo mật chính thức của Ruby on Rails không thể được nhấn mạnh quá mức. Tại đó, bạn có thể tìm thêm thông tin về chiếm quyền điều khiển phiên, cơ chế lưu trữ và các chiến lược để mã hóa dữ liệu của bạn theo cách tốt nhất có thể.

Hẹn gặp lại các bạn ở điểm dừng chân tiếp theo!