Đôi lời

Dạo gần đây trong công ty có phong trào đọc sách kỹ thuật và chia sẻ. Nhân tiện mình cũng muốn chia sẻ với mọi người những gì mình đã đọc lĩnh hội về cuốn sách "How to Secure your website". Cuốn sách nói về các kiểu injection, ví dụ , cách giải quyết. Dưới đây mình sẽ trình bày theo cách hiểu của bản thân ,nên có thể sẽ có sai xót hoặc thiếu xót, mong mọi người góp ý và thông cảm .

SQL Injection

Khái niệm:

Là việc cấu trúc câu SQL có vấn đề , dựa vào đó hacker có khả năng sử dụng , thao tác bất chính vào Database.

Những uy hiếp có thể xảy ra:

  • Xem được những thông tin bí mật , ví dụ :thông tin cá nhân của người dùng …
  • Thay đổi dữ liệu : làm giả web, đổi pass , làm cho hệ thống ngừng chạy.
  • Tránh né chứng thực và login bất chính.
  • Thi hành lệnh OS bằng cách sử dụng thủ tục lưu trữ.

Ví dụ:

$query = "SELECT * FROM usr WHERE uid = '$uid' AND pass = '$passh';

$result = pg_query($conn, $query);

Đây là đoạn query liên đến việc chứng thực user khi login

  • pg_query() là 1 hàm của PostgreSQL trong PHP
  • $uid thì không được Escape processing.

Vì vậy , hacker có thể sử dụng $uid để hình thành nên 1 câu SQL với ý đồ xấu .

Giải thích ví dụ:

Hacker sẽ sửa câu SQL thành

SELECT * FROM usr WHERE uid = 'taro'--' AND pass ='eefd5bc2...‘

Phía sau của「--」sẽ trở thành comment. Vì vậy đọan SQl trên thực tế sẽ thành như bên dưới .

SELECT * FROM usr WHERE uid = 'taro'--

=> Không cần biết pass vẫn login vô được.

Ngoài ra pg_query() là hàm có thể thực hiện nhiều query, hacker có thể lợi dụng nó để lồng những query với ý đồ xấu .

$query = "SELECT item FROM shop WHERE id = 1;
SELECT item FROM shop WHERE id = 2;"

$result = pg_query($conn, $query);

Giải quyết vấn đề

Cách 1:

Sử dụng pg_prepare()pg_execute() thay cho pg_query().

$result = pg_prepare($conn, "query", 'SELECT * FROM usr WHERE uid= $1 AND pass=$2);

$result = pg_execute($conn, "query", array($uid, $passh));
  • Argument thứ 3 của hàm pg_prepare() là tham số vẫn chưa dc gán giá trị thực tế.
  • Hàm pg_execute() sẽ tự động gán giá trị cho các placeholder khi thực thi.

=> Với cách sử lý này thì ta không cần phải Escape processing cũng đuược.

Cách 2:

Sử dụng pg_query_params() thay cho pg_query().

$result = pg_query_params($conn, 'SELECT * FROM usr WHERE uid = $1 AND
pass = $2', array($uid, $passh));
  • pg_query_params() cũng là hàm cấu trúc placeholder, kiểu kiểu giống như ở cách 1.
Cách 3:

Sử dụng hàm escape chuyên dụng như là pg_escape_string(). Là hàm lọc những ký tự đặc biệt của Javascript như là "<" ">".

$query = "SELECT * FROM usr WHERE uid = '".pg_escape_string($uid)."' AND pass = '".pg_escape_string($passh)."'";

$result = pg_query($conn, $query);
Các CSDL khác:

Phía trên là vì dụ với PostgreSQL trong PHP, còn trong MySQL các bạn có thể tham khảo bên dưới .

Ví dụ :

$query = "SELECT * FROM usr WHERE uid = '$uid' AND pass = '$passh'";

$result = mysql_query($query);
  • Sử dụng mysqli_prepare() , mysqli_stmt_bind_param(), mysqli_stmt_execute() thay cho mysql_query().
$stmt = mysqli_prepare($conn, "SELECT * FROM usr WHERE uid= ? AND pass = ?");

mysqli_stmt_bind_param($stmt, "ss", $uid, $passh);

mysqli_stmt_execute($stmt);
  • Hoặc là sử dụng hàm escape chuyên dụng mysqli_real_escape_string()
$query = "SELECT * FROM usr WHERE uid = '". mysqli_real_escape_string($conn, $uid)."' AND pass = '". mysqli_real_escape_string($conn, $passh)."'";

$result = mysqli_query($conn, $query);

Tóm tắt cách giải quyết, và phòng ngừa

  • Sử dụng các hàm có cấu trúc placeholder để tạo câu SQL, và binding giữ liệu vào câu SQL.

  • Khi xây dựng câu lệnh SQL bằng cách nối chuỗi, sử
    dụng API của cơ sở dữ liệu thực hiện quá trình escape processing để tạo câu SQL đúng .

  • Không trực tiếp truyền các câu lệnh SQL trong các
    tham số truyền vào ứng dụng web.

  • không hiển thị y nguyên error massage lên trình duyệt

ví dụ :
“mật khẩu không chính xác”

Mà phải hiển thị là :
“ID hoặc là Pass không chính xác”

  • Cấp quyền thích hợp cho tài khoản trong DB

OS Command Injection

Khái niệm:

Là một lệnh hệ điều hành của máy chủ web bị thực
thi bất hợp pháp do một cuộc tấn công bên ngoài.

Những uy hiếp có thể xảy ra:

  • Xem, sửa đổi và xóa các tệp trên máy chủ.

  • Thao tác hệ thống bất hợp pháp.

  • Tải về và thực thi các chương trình độc hại.

  • Làm bàn đạp tấn công vào các hệ thống khác.

Ví dụ

Từ perl gọi command sendmail.

$from =~ s/"|;|'||\|| //ig;

open(MAIL, "|/usr/sbin/sendmail -t -i -f $from");

Đây là một phần của chương trình gửi thư. Với dòng đầu tiên có ý nghĩa là xóa đi các kí tự “ ; ‘ >< |” ” . Dòng thứ 2 có ý nghĩa là gọi lệnh gửi mail.

Nếu nhập someone@example.com thì việc sử lý sendmail diễn ra bình thường .

Nhưng nếu có ác ý nhập :

`touch[0x09]/tmp/foo`

=> Thì nó thành tấn công OS Command Injection.

/usr/sbin/sendmail -t -i -f `touch[0x09]/tmp/foo`
  • 「`」nghĩa là thực thi phần dc bao bên trong và xuất output ra command line.
  • 「[0x09]」có ý nghĩa tương đương là khoảng trắng

Cách giải quyết

Cách 1:

Sử dụng thư viện.

  • Ngưng việc gọi command thì sẽ giải quết dc vấn đề.
use Mail::Sendmail;

%mail = (From => $from, …);

sendmail(%mail);
  • Vì mục đích là sendmail nên nếu ta sử dụng thư viện để sendmail thì sẽ tránh dc OS Command Injection mà vẫn duy trì được chức năng send mail.
Cách 2:

Phương pháp không nhúng giá trị vào trong command
line.

  • Trường hợp khó sử dụng thư viên và buộc phải sử
    dụng command , bằng việc thay đổi cách gọi command ta có giải quyết dc vấn đề OS Command Injection.
$from =~ s/\r|\n//ig;

open(MAIL, '|/usr/sbin/sendmail -t -i');
…
print MAIL "From: $from\n";
Cách 3:

Phương pháp gọi command mà không thông qua shell.

open(MAIL, '|-') || exec '/usr/sbin/sendmail', '-t', '-i', '-f', '$from';

Tóm tắt cách giải quyết và phòng ngừa .

  • Tránh sử dụng các ngôn ngữ có thể khởi động shell.
  • Để sử dụng ngôn ngữ có thể khởi động shell, kiểm tra tất cả các biến cấu thành đối số, và chỉ thực hiện các quá trình được phép trước.

Unchecked pathname parameter / directory traversal

Khái niệm:

Một số ứng dụng web mà tên tập tin trong máy chủ web được chỉ định trưc tiếp dưới dạng các tham số bên ngoài. Và thực hiện các xử lý không theo ý đồ của ứng dụng web

Những uy hiếp có thể xảy ra:

  • Rò rỉ thông tin quan trọng
  • Giả mạo, xóa các tập tin cấu hình, các tập tin dữ
    liệu, mã nguồn chương trình vv.

Ví dụ:

Hiển thị nội dung file lên màn hình bằng PHP

$file_name = $_GET['file_name'];

if(!file_exists($file_name)) {
$file_name = 'nofile.png';
}

$fp = fopen($file_name,'rb');

fpassthru($fp);
  • Đây là một phần của chương trình hiển thị nội dung của tệp với tên được chỉ định trên màn hình.

Giải thích:

Trong thực thi này, nếu "/ etc / passwd" được chỉ định trong tham số file_name trong URL, nội dung của / etc / passwd sẽ được hiển thị trên màn hình.

Cách giải quyết:

Chỉ sử dụng tên file được lấy từ path name.

$dir = '/home/www/image/';
…
$file_name = $_GET['file_name'];
…
if(!file_exists($dir . basename($file_name))) {
$file_name = 'nofile.png';
}

$fp = fopen($dir . basename($file_name),'rb'); fpassthru($fp);

basename() là hàm chỉ lấy tên file .

=> Điều này sẽ loại bỏ các lỗ hổng liên quan đến các tham số tên đường dẫn.

Tóm tắt cách giải quyết và phòng ngừa.

  • Tránh thực hiện trực tiếp chỉ định tên tệp
    trong máy chủ web với các tham số bên ngoài.
  • Khi mở một tập tin, chỉ định một thư mục cố
    định và chắc chắn rằng tên tập tin không bao gồm tên thư mục.
  • Quản lý chính xác việc thiết lập quyền truy cập
    vào tệp trong máy chủ web.
  • Kiểm tra tên tệp.

Tham khảo

https://www.ipa.go.jp/files/000017316.pdf

https://www.ipa.go.jp/files/000017320.pdf