Các lỗ hổng thường gặp và cách thực hiện lập trình an toàn trong phát triển ứng dụng web (P1)
tháng 3 15, 20191. Kiểm soát truy vấn cơ sỡ dữ liệu để tránh lỗ hổng SQL Injection
- Truy vấn SQL phải dùng PrepareStatement, tất cả tham số phải được add bằng hàm (setParam…), không được sử dụng cách cộng xâu trong truy vấn.
- Với một số trường hợp sử dụng ORDER BY, không thể dùng được hàm setParam thì có thể định nghĩa một mảng chứa toàn bộ các column (field) cần ORDER BY gọi là whitelist. Mỗi khi cần ORDER BY thì kiểm tra lại xem column (field) đó có thuộc mảng whitelist đã định nghĩa không. Ví dụ 1: Đoạn code kiểm tra đăng nhập với username/password do người dùng nhập vào:
1
2
3
4
5
6
7
8
9
10
|
String sql = "select * from users where user_name = "' + userName + '" and password = "' + encrypt(password) + '";
Statement statement = connection.createStatement();
ResultSet rs = statement.excuteQuery(sql);
if (!rs.next()) {
bResult = false;
} else {
bResult = true;
}
|
- Với đoạn code trên, khi nhập vào username là test’ or ‘1’=’1 thì câu query sẽ là: select from users where username=’test’ or ‘1’=’1′ and password=’…’. Mệnh đề where sẽ tương đương với user_name = ‘test’. Như vậy, dù không có password vẫn đăng nhập được vào hệ thống.
- Sửa đoạn code trên lại như sau, với userName và password được tham số hóa khi đưa vào câu truy vấn sẽ tránh được lỗi SQL Injection:
1
2
3
4
5
6
7
8
9
10
11
12
|
String sql = "select * from users where user_name = ? and password = ?";
PreparedStatement statement = connection.preparedStatement(sql);
statement.setString(0, userName);
statement.setString(1, encrypt(password));
ResultSet rs = statement.excuteQuery(sql);
if (!rs.next()) {
bResult = false;
} else {
bResult = true;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// Mảng lưu danh sách các column (field) của BO cần order by (hay gọi là whitelist)
private static List columnSort = new ArrayList();
public static String getColumnSort(String sortField) {
// Thực hiện 1 lần và lấy ra toàn bộ mảng column cần order và add vào whitelist
if (columnSort.size() == 0) {
// Danh sách BO cho phép order by
String[] arrTableName = {"ActionLog", "BanPosition", "Category", ...};
};
// Lấy ra toàn bộ các column (field) BO cần order by
for (String tableName : arrTableName) {
try {
Class class = Class.forName("com.demo.DEMO.database.BO." + tableName);
Field[] fieldArr = class.getDeclaredFields();
for (int i = 0; i< fieldArr.length; i++) {
String fieldName = fieldArr[i].getName();
// add các column vào 1 mảng
columnSort.add(fieldName);
}
} catch (ClassNotFoundException ex) {
}
}
}
// Cắt ký tự "-" ở đầu field sort
String sort = sortField;
if (sortField != null && sortField.startsWith("-")) {
sortField = sortField.substring(1);
}
// Kiểm tra field cần order by có nằm trong danh sách field cho phép sort hay không
if (sortField != null && columnSort.contains(sortField)) {
return sort;
}
return null;
|
2. Xử lý dữ liệu đầu vào để tránh lỗ hổng XSS
- Encode dưới dạng HTML các ký tự đặc biệt do client gửi đến bao gồm: <,>,&,’,”,/ trong các trường hợp
- Dữ liệu client gửi lên máy chủ.
- Dữ liệu lấy ra từ database khi trả về cho client. Bảng chất của việc encode là thay thế các ký tự trên bằng chuỗi tương ứng trong bảng bên dưới:
1
2
3
4
5
6
7
8
9
10
|
| STT | Ký tự | HTML |
| --- | ----- | ------- |
| 1 | " | " |
| 2 | & | & |
| 3 | ' | ' |
| 4 | / | /t; |
| 5 | < | < |
| 6 | > | > |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%
String user = request.getParameter("user");
request.setAttribute("user", user);
%>
<h1> Hello ${user}! </h1>
</body>
</html>
|
- Khi nhập vào địa chỉ trình duyệt
http://localhost/example?user=abc
thì trên trình duyệt sẽ hiện thị dòng Hello abc! - Khi nhập vào địa chỉ trình duyệt
http://localhost/example?user=abc<script>alert('XSS')</script>
thì trên trình duyệt sẽ thực hiện đoạn JavaScript thông báo XSS. - Để khắc phục lỗi này ta có thể dùng thư viên JSTL để encode HTML biến user
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%
String user = request.getParameter("user");
request.setAttribute("user", user);
%>
<h1> Hello ${fn:escapeXml(user)}! </h1>
</body>
</html>
|
0 bình luận