SQL Injection trong Rails

Tram Ho

Mở đầu

SQL injection là một lỗ hổng bảo mật cho phép hacker truy cập thông tin cá nhân trong cơ sở dữ liệu. Điều này có thể làm lộ thông tin người dùng như email, địa chỉ, số điện thoại hoặc nhạy cảm như thông tin thẻ tín dụng.
Hầu hết các frameworks đều có các phương pháp để ngăn chặn điều này, nhưng lỗ hổng bảo mật này vẫn có thể xảy ra nếu lập trình viên không cẩn thận.
Cách tốt nhất để tránh gặp phải điều này là bạn phải hiểu nó, biết cách tấn công trang web bằng SQL Injection. Hãy cùng tìm hiểu SQL Injection trong ứng dụng Rails

Bài viết này gồm 3 phần

  1. Khái niệm về SQL Injection
  2. Phát triển một trang web bằng Rails
  3. Tấn công trang web bằng SQL Injection

1. Khái niệm về SQL Injection

SQL Injection là gì?

SQL injection là chèn 1 câu truy vấn SQL vào một input field được chạy trực tiếp đến cơ sở dữ liệu.
Điều này được cho phép khi một ứng dụng can thiệp vào input của người dùng vào một truy vấn SQL ở phía back end.
Ví dụ:
Đoạn code dưới đây trả về những bài post tương ứng với truy vấn của người dùng

Khi người dùng nhập vào input field với nội dung “Wine Food Pairings”, câu lệnh SQL dưới đây được thực hiện và sẽ không có vấn đề gì xảy ra

Nhưng khi người dùng nhập vào input field nội dung Wine Food Pairings’ or 1=1) --, SQL sau đây được thực thi.

Và vấn đề xảy ra ở đây là gì?
Câu truy vấn sau kí tự -- sẽ không được thực thi (-- sẽ định nghĩa 1 comment trong SQL) và những bản ghi (ở đây là bài post) có trường private với giá trị true vẫn sẽ được truy vấn.
Đoạn code dưới đây sẽ ngăn chặn được điều này.

Đây là 1 ví dụ điển hình cho việc tấn công lỗ hổng bảo mật bằng SQL Injection. Chúng ta sẽ cùng tìm hiểu các trường hợp khác qua phần dưới đây

2. Tạo 1 trang web bằng Rails

Ở phần này chúng ta sẽ tạo một trang web sau đó sẽ tấn công trang web này bằng SQL Injection.

Khởi tạo project mới

Phần này mình sẽ nói ngắn gọn.
Trong terminal, viết các lệnh sau

Project này mình sẽ thêm 2 gem khá quen thuộc là gem 'pg' và gem 'devise'. Trong file có tên Gemfile bạn thêm vào 2 dòng sau

sau đó dùng lệnh $ sudo bundle install để cài đặt 2 gem trên.
Sau đó cái tạo database với lệnh $ rails db:create

Thêm chức năng loggin

Ở đây chúng ta sẽ sử dụng gem 'devise' vừa thêm ở bước trên. Để cài đặt chúng ta sử dụng lệnh $ rails generate devise:install
Trong Rails, một model là một class. Ruby ánh xạ tới một bảng cơ sở dữ liệu và đơn giản hóa việc thực hiện các transation DB thông qua ORM, Active Record của nó.
Sử dụng chức năng loggin với model user bằng lệnh sau:

Tạo màn hình loggin bằng lệnh

Thêm các trường cần thiết cho model user
Đầu tiên tạo file migration

Trong thư mục /db/migrate/ sẽ có 1 file tên là add_admin_to_user.rb. Trong file này chúng ta thêm đoạn code sau:

Sau đó dùng lệnh $ rails db:migrate. Thao tác này sẽ thêm hai cột này vào bảng user trong cơ sở dữ liệu.

Thêm model Post

Với model post chúng ta sẽ cần các hành động cơ bản CRUD. Câu lệnh sau sẽ tạo model post cùng với controller với các action CRUD cũng như các màn hình CRUD tương ứng

Trong thư mục /config/routes.rb thêm đoạn root 'posts#index' để trang web của chúng ta sẽ mặc định đi đến trang index của model post. File routes.rb sẽ có nội dung như sau:

Bây giờ khởi động lại server và truy cập vào đường dẫn http://localhost:3000/ và trang web sẽ hiển thị nội dung trang index của model post

Ở màn hình này hãy tạo một vài bản ghi để thử xem chức năng CRUD có hoạt động hay không.

Ở trên chúng ta đã thêm phần xác thực người dùng với gem Devise nhưng cần thêm một vài đoạn code để có thể hiển thị thêm thông tin rằng chúng ta đã đăng nhập hay chưa.
Trong file /app/views/layouts/application.html.erb chúng ta sẽ sửa lại như sau:

Bây giờ hãy click vào phần “Sign up” ở trên cùng bên trái của trang web và tạo tài khoản cho mình. Sau khi đăng ký xong màn hình của bạn sẽ hiển thị như hình dưới

Thêm một cột nữa vào model Posts bằng cách tạo một file migration khác

sau đó chạy lệnh $ rake db:migrate

Thêm một vài dữ liệu để hiển thị lên trang web của mình

Tạo một file có tên là seed_data.rake trong thư mục /lib/task/. Với nội dung

Chạy lệnh $ rake seed_data để tạo các bản ghi vào trong DB
Bây giờ trang web của chúng ta đã sẵn sàng để sử dụng các chứng năng như đăng nhập, đăng xuất, CRUD với model Posts

Thêm tính năng search

Bây giờ, chúng ta sẽ tạo một form tìm kiếm để lấy ra các bài posts được hiển thị. Đây sẽ là nơi để chúng ta sẽ tấn công bằng SQL Injection.
Trong file app/views/posts/index.html.erb chúng ta thêm vào dưới dòng <h1>Posts</h1> đoạn code sau:

Đoạn code này sẽ cho phép chúng ta nhập dữ liệu để tìm kiếm các bài posts.
Sau đó trong controller /app/controllers/posts_controller.rb chúng ta sẽ thêm logic xử lý những giá trị đầu vào từ form search để lấy ra các bài posts tương ứng

3. Tấn công trang web bằng SQL Injection

Hơi dài dòng một chút nhưng bây giờ sẽ đến phần chính của bài viết này. Sau khi đã tạo thành công trang web với các chức năng cơ bản và tạo ra một số dữ liệu mẫu, sau khi đăng nhập, trang web của chúng ta sẽ hiển thị như hình dưới

Ở đây chỉ những bài post có trạng thái public (private = false) mới được hiển thị (hàm index có đoạn truy vấn @posts = Post.where("title = '#{query}' and private = false"))
Hãy cùng khai thác vài lỗi bảo mật (SQL Injection) mà trang web này đang gặp phải

1. Get private posts

Đây là ví dụ từ phần giới thiệu. Nhập nội dung sau vào ô tìm kiếm Wine Food Pairings' or 1=1) --

Dấu -- đã chặn câu truy vấn private = false trong câu truy vấn chúng ta đã viết ở controller. Điều này đã thực thi câu truy vấn:

Như đã nói ở trên, dấu -- là 1 cú pháp định nghĩa 1 comment trong ngôn ngữ SQL vì thế câu lệnh private = false sẽ không được thực thi. Điều này dẫn đến kết quả search của chúng ta như sau:

2 bài posts có title My PasswordsEmployee Directory mặc dù có giá trị private = true nhưng vẫn được hiển thị trong kết quả tìm kiếm.

2. Get all user emails in the database

Form search chúng ta vừa làm không thiết kế để trả về một users. Nhưng chúng ta vẫn có thể làm điều này xảy ra.
Nhập vào form tìm kiếm nội dung sau: Cheese') union select 1, email,'', null, null, true from users --
Sau khi ấn button Filter, câu truy vấn sau sẽ được thực hiện:

Đoạn input trên đã thực hiện câu lệnh onion để liên kết bảng posts và bảng users và hiển thị những bản ghi của bảng users
Kết quả sẽ như sau:

Tất cả mọi thông tin của bảng users đã hiển thị ra ở màn hình này.

3. Find which users are admins

Nếu muốn biết ai trong số những người dùng trên là admin, chúng ta chỉ cần sửa đổi một chút ở nội dung input.
Input: Cheese') union select 1,email,'', null, null, true from users where admin = true --
Câu truy vấn sau sẽ được thực thi:

Và trả về kết quả như sau:

Là một người xấu, việc chiếm được quyền admin của một trang web là rất nguy hiểm. Chúng có thể lấy được mọi thông tin của người dùng như email, số điện thoại hoặc các thông tin nhạy cảm mà chỉ admin mới có thể biết.

4. Tổng kết

Bài viết này không nhằm mục đích dạy bạn cách hack các ứng dụng web. Bài viết chỉ cho bạn biết cách hoạt động của SQL injection và thiệt hại mà lỗi bảo mật có thể gây ra để biết cách phòng tránh và đừng viết code không cẩn thận gây
ra những thiệt hại không đáng có.

Bài viết còn nhiều thiếu sót, mong mọi người thông cảm. Cám ơn mọi người đã đọc bài viết của mình,

5. Nguồn

https://medium.com/better-programming/learn-sql-injection-by-ethically-hacking-a-rails-app-e96906f8c593

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo