- Tương tác với cơ sở dữ liệu tránh lỗ hổng SQL Injection:
- Dữ liệu input từ người dùng phải được truyền dưới dạng tham số không được sử dụng cách cộng xâu trong các truy vấn tới cơ sở dữ liệu.
2.
Xử lý dữ liệu đầu vào tránh lỗ hổng XSS:
- Mã hóa dưới dạng HTML các ký tự đặc biệt do người dùng gửi lên máy chủ và các ký tự đặc biệt trong cơ sở dữ liệu trước khi gửi tới người dùng.
3.
Sử dụng Token trong các phương
thức GET và POST tránh lỗ hổng CSRF:
- Trong các tương tác của người dùng với cơ sở dữ liệu thông qua các form, liên kết, sử dụng thêm biến token (được tạo ra mỗi đầu phiên truy cập của người dùng) như một tham số trong phương thức GET hoặc POST và kiểm tra giá trị token này tại máy chủ để xác nhận hành vi của người dùng.
4.
Kiểm soát các thao tác với file:
- Giới hạn chỉ cho phép các định dạng file theo yêu cầu của ứng dụng được phép upload lên máy chủ. Kiểm soát file upload ở phía máy chủ. Lưu trữ các file upload tại một thư mục riêng nằm ngoài thư mục web hoặc không cho phép truy cập, thực thi trên các thư mục đó.
- Chặn các kí tự \, /, null và kiểm tra phần mở rộng của file khi xử lý với tên file trên máy chủ.
5.
Mã hóa dữ liệu nhạy cảm
- Những dữ liệu nhạy cảm trong cơ sở dữ liệu cần được mã hóa.
6.
Kiểm tra quyền truy cập của người
dùng
- Kiểm soát quyền của người dùng trong mỗi request lên máy chủ.
7.
User enumeration
- Sử dụng chung thông báo lỗi cho cả 2 trường hợp nhập sai tên đăng nhập và mật khẩu trên trang đăng nhập vào hệ thống. Nhằm tránh trường hợp thông báo lỗi trên trang đăng nhập phân biệt giữa nhập sai tên đăng nhập và sai mật khẩu à Dựa vào đó hacker có thể thử và tìm ra các user có trên hệ thống.
8.
Session fixation
- Renew session sau khi đăng nhập và xóa session cũ (trên Server) sau khi log out. Tránh trường hợp Session của ứng dụng trước và sau khi đăng nhập không thay đổi. Hacker có thể sử dụng lỗ hổng này để đăng nhập mà không cần biết username/password.
9.
Session Hijacking
- Không cho phép 2 phiên truy cập đồng thời, session được xây dựng từ các thông tin hướng người dùng (IP, User-Agent hoặc địa chỉ MAC).
10.
HTTP Only cookie
- Yêu cầu thiết lập thuộc tính ”HTTP Only” cho session cookie. Vì nếu Session cookie không được set thuộc tính ”HTTP Only”. Hacker có thể sử dụng mã javascript để ăn cắp cookie của người dùng.
- Tránh người dùng cuối có thể can thiệp vào quá trình redirect từ ứng dụng này sang ứng dụng khác. Nếu cần sử dụng thì URI phải được validate, đảm bảo URI được redirect đến nằm trong whitelist của ứng dụng. Nếu không dược validate, kẻ tấn công có thể redirect đến URI có nhiễm mã độc.
12.
Để lộ dữ liệu của hệ thống
- Yêu cầu tất cả dữ liệu, tài nguyên hệ thống(báo cáo, file lưu trữ) không được lưu trong thư mục chia sẻ(share). Các dữ liệu này lưu trong thu mục bên ngoài thư mục cài đặt web server, việc thực hiện download các dữ liệu này phải qua bước xác thực và tham số phải mã hóa
13.
Thất thoát thông tin và xử lý lỗi
không dúng tốt
- Yêu cầu không hiển thị chi tiết lỗi cho người dùng cuối, hạn chế thông tin hiển thị nhất có thể. Đồng thời các thông tin lỗi này phải được log lại bên server để phục vụ bảo trì
1. Kiểm soát truy
vấn cơ sở dữ liệu để tránh lỗ hổng SQL Injection
- Nguy cơ: Khi truy vấn tới cơ sử dữ liệu lập trình viên thường sử dụng cách cộng xâu
Input từ người dùng, các câu truy vấn này có thể bị mắc lỗi SQL Injection hoặc
HQL Injection (nếu sử dụng Hibernate). Bằng việc lợi dụng các lỗi này, kẻ tấn
công có thể xem, thêm, sửa, xóa dữ liệu trong database từ đó chiếm được tài
khoản admin, lấy cắp thông tin người dùng...
-
Phòng chống:
o 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 xử dụng cách cộng xâu trong truy vấn.
o Truy vấn
HQL tất cả tham số phải được add bằng hàm( setParam..), không được xử dụng cách
cộng xâu trong truy vấn.
-
Ví dụ: Đoạn code
kiểm tra đăng nhập với username/password do người dùng nhập vào
String sql = "select * from users where
user_name = '" + userName
+ "'
and password = '" + encrypt(password) + "'";
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(sql);
if (!rs.next()) {
bResult = false;
} else {
bResult = true;
}
|
Nhập vào username là test’ or ‘1’=‘1 thì câu query sẽ là: select
* from users where user_name=‘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.
Đoạn code bên dưới, username,password được tham số hóa khi đưa vào câu truy
vấn nên tránh được lỗi SQL Injection:
String sql = "select * from users where
user_name = ? and password = ?";
PreparedStatement statement =
connection.prepareStatement(sql);
statement.setString(0, userName);
statement.setString(1, encrypt(password));
ResultSet rs = statement.executeQuery(sql);
if (!rs.next()) {
bResult = false;
} else {
bResult = true;
}
|
2.
Xử lý dữ liệu đầu vào để tránh lỗ hổng XSS
-
Nguy cơ: Kết quả
server trả về cho người dùng chủ yếu là dưới dạng HTML. Nội dung trả về thường
bao gồm cả những giá trị mà người dùng nhập vào hệ thống có thể bị mắc lỗi XSS
nếu không kiểm soát dữ liệu đầu vào. XSS (Cross-Site Scripting) là một kĩ thuật
tấn công bằng cách chèn vào các website động (ASP, PHP, CGI, JSP ...) những thẻ
HTML hay những đoạn mã script nguy hiểm có thể gây nguy hại cho những người sử
dụng khác. Trong đó, những đoạn mã nguy hiểm đựơc chèn vào hầu hết được viết
bằng các Client-Site Script như JavaScript, JScript, DHTML và cũng có thể là cả
các thẻ HTML.
-
Phòng chống:
Mã hóa 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
o Dữ
liệu client gửi lên máy chủ
o Dữ
liệu lấy ra từ database khi trả về cho client
Bản chất của
việc mã hóa là thay thế các kí tự trên bằng chuỗi tương ứng trong bảng bên
dưới:
STT
|
Ký tự
|
HTML
|
1
|
"
|
"
|
2
|
&
|
&
|
3
|
'
|
'
|
4
|
/
|
/
|
5
|
<
|
<
|
6
|
>
|
>
|
-
Ví dụ: Trang jsp
bên dưới hiển thị lên lời chào với tên người dùng được lấy từ client
<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</h1><script>alert('XSS')</script>
thì trên trên trình duyệt sẽ thực hiện đoạn java script thông báo XSS.
Để khắc phục
lỗi này ta có thể dùng thư viện JSTL để mã hóa HTML biến user
<%@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>
|
3.
Sử dụng token để tránh lỗ hổng CSRF
-
Nguy cơ: CSRF
(Cross-site request forgery) là phương pháp mượn quyền của người dùng khác để
thực hiện một hành động không cho phép. Ví dụ: Để có thể xóa một bài viết trên
diễn đàn một member có thể mượn tay của một admin để làm việc đó vì member
không đủ chủ quyền nhưng admin lại đủ chủ quyền để thực hiện hành động
này. Kẻ tấn công lừa admin truy cập vào trang web có chứa đoạn mã xóa bài
viết trên diễn đàn (Admin đang đăng nhập vào diễn đàn) như vậy admin đã gửi yêu
cầu xóa bài viết trên diễn đàn mà không hề biết.
-
Phòng chống: Đối với
các yêu cầu quan trọng, sử dụng thêm biến token. Trên server sẽ kiểm tra token
trong yêu cầu gửi lên từ client, nếu token không hợp lệ thì yêu cầu sẽ không
được thực hiện
-
Ví dụ: Ứng dụng
struts cho phép hiển thị lời chào với tên người dùng nhập từ form
index.jsp
<%@taglib
prefix="s" uri="/struts-tags" %><br />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8">
</head>
<body>
<h2>Hello World!</h2>
Struts 2 Message: <s:property value="message"
default="Guest." />
<s:form method="GET"
action="/HelloStruts2World.action">
Enter your name:<s:textfield name="userName" />
<s:submit value="Submit" />
</s:form>
</body>
</html>
|
struts.xml
<struts>
<package name="/"
extends="struts-default">
<action name="HelloStruts2World"
class="hello.HelloStruts2World">
<result
name="success">/index.jsp</result>
</action>
</package>
</struts>
|
helloStruts2World.java
package
hello;
import
com.opensymphony.xwork2.ActionSupport;
public
class HelloStruts2World extends ActionSupport {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
private String message;
public String getMessage() {
return message;
}
@Override
public String execute() {
message = "Hello, " + userName + ".";
return SUCCESS;
}
}
|
Tuy nhiên,
yêu cầu trên có thể được thực hiện mà không cần phải nhập username từ form bằng
cách đưa trực tiếp vào URL:
Để khắc phục
lỗi trên, ta có thể sử dụng token intercepter đã có sẵn của struts.
index.jsp
<%@taglib
prefix="s" uri="/struts-tags" %><br />
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Hello World!</h2>
Struts 2 Message: <s:property value="message"
default="Guest." />
<s:form method="GET"
action="/HelloStruts2World.action">
<s:token/>
Enter your name:<s:textfield name="userName" />
<s:submit value="Submit"
/>
</s:form>
</body>
</html>
|
struts.xml
<struts>
<package name="/" extends="struts-default">
<interceptors>
<interceptor-stack name="defaultSecurityStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="tokenSession">
<param name="excludeMethods">*</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultSecurityStack" />
<global-results>
<result name="invalid.token">/error.jsp</result>
</global-results>
<action name="HelloStruts2World"
class="hello.HelloStruts2World">
<interceptor-ref name="defaultSecurityStack">
<param name="tokenSession.includeMethods">*</param>
</interceptor-ref>
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
|
4.
Kiểm soát file upload lên hệ thống
-
Nguy cơ: Các thao
tác với file thường sử dụng tên file, đường dẫn file được gửi lên từ client,
nếu ứng dụng không kiểm soát tốt các giá trị này (việc kiểm soát phải được thực
hiện phía server) có thể dẫn đến việc download hoặc upload các file không hợp
lệ.
-
Phòng chống:
Kiểm soát
phía server tên file, đường dẫn file được gửi lên từ client
o Kiểm
soát phần mở rộng của file, chỉ cho phép thực hiện với các file có định dạng
theo yêu cầu.
o Các
hàm liên quan đọc ghi file, biến đường dẫn file phải được lọc /, \ và kí tự
null.
-
Ví dụ 1: Đoạn code
bên dưới in ra đường dẫn file với đầu vào là tên file
String
fileName = "temp.txt";
File file1
= new File(fileName);
System.out.println("File
1 path: " + file1.getCanonicalPath());
fileName =
"./../../../../../../../boot.ini";
File file2
= new File(fileName);
System.out.println("File
2 path: " + file2.getCanonicalPath());
fileName =
"boot.ini" + String.valueOf((char) 0) + ".txt";
File file3
= new File(fileName);
System.out.println("File
3 path: " + file3.getCanonicalPath());
|
Với đường
dẫn thư mục hiện tại là
“C:\Documents
and Settings\Website\upload\test\”.Ta có kết quả thực hiện:
File 1
path: C:\Documents and Settings\Website\upload\test\temp.txt
File 2
path: C:\boot.ini
File 3
path: C:\Documents and Settings\Website\upload\test\boot.ini
|
Trong trường
hợp 1, kết quả in ra đường dẫn file temp.txt nằm trong thư mục hiện
tại
Trong 2
trường hợp còn lại, tên file được thay đổi để truy cập đến các file không được
phép.
o Trường hợp
2: Trong tên file có chứa các chuỗi ./ và ../, các chuỗi này có
tác dụng chuyển đến thư mục hiện tại (./) và thư mục cha của thư mục
hiện tại (../). Vì thế với tên file là “./../../boot.ini”, kết
quả in ra là file boot.ini nằm trong thư mục gốc ổ C.
Chú ý: Kỹ thuật
này thường được dùng để truy cập đến các thư mục nằm ngoài thư mục hiện tại.
Các chuỗi .\ và ..\ cũng có tác dụng tương tự như ./ và ../
o Trường hợp
3: Các hàm xử lý file của hệ điều hành khi gặp kí tự NULL (mã ASCII là 0) trong
tên file sẽ hiểu rằng đây là kí tự kết thúc xâu chứa tên file và bỏ qua tất cả
các kí tự phía sau (đặc điểm của các hàm xử lý xâu bằng ngôn ngữ C – ngôn ngữ
của hầu hết các hệ điều hành). Vì thế kết quả trong trường hợp này sẽ là file boot.ini
trong thư mục hiện tại mặc dù tên file nhập vào có phần mở rộng là “.txt”.
Chú ý: Kỹ thuật
này thường được dùng để vượt qua việc chặn phần mở rộng của file.
Để sửa
lỗi trên ta có thể sử dụng hàm lọc các kí tự /,\,null trong tên file
public
static String getSafeFileName(String input) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c != '/' && c != '\\' && c != 0) {
sb.append(c);
}
}
return sb.toString();
}
|
-
Ví dụ 2: Đoạn mã
bên dưới có tác dụng upload file từ client và save vào thư mục upload
private
File clientFile;
private
String clientFileFileName;
@Override
public
String execute() throws Exception {
try {
if (clientFileFileName != null) {
clientFileFileName = getSafeFileName(clientFileFileName);
if (!clientFileFileName.endsWith(".txt")) {
message = "Not .txt file!";
} else {
String uploadDir = "C:\\upload\\";
File uploadFile = new File(uploadDir + clientFileFileName);
FileUtils.copyFile(clientFile, uploadFile);
message = "Upload file success!";
}
}
} catch (Exception e) {
message = "Upload file error!";
}
return SUCCESS;
}
|
Sử dụng hàm getSafeFileName trong ví dụ 1 kết hợp với việc kiểm tra
phần mở rộng đảm bảo upload file an toàn, chỉ các file được phép mới được
upload lên server và các file này chỉ có thể được phép save vào thư mục chỉ
định.
5.
Mã hóa dữ liệu nhạy cảm
-
Nguy cơ: Khi hệ
thống bị tấn công và kẻ tấn công lấy được thông tin trong cơ sở dữ liệu, các dữ
liệu nhạy cảm sẽ bị lộ nếu không được mã hóa hoặc mã hóa không an toàn.
-
Phòng chống:
o
Mã hóa các
dự liệu nhạy cảm trong cơ sở dữ liệu.
o
Các hàm mã
hóa 1 chiều phải có thêm salt.
-
Ví dụ: Mật khẩu
của người dùng được mã hóa trong cơ sở dữ liệu bằng hàm mã hóa 1 chiều. Kẻ tấn
công lấy được mật khẩu đã mã hóa là QL0AFWMIX8NRZTKeof9cXsvbvu8= và có
thể tìm được mật khẩu chưa mã hóa là 123, thuật toán mã hóa là hash =
base64(SHA1(pass)) bằng cách tìm kiếm trên Internet. Các mật khẩu
phổ biến dễ bị dò ngược lại bằng phương pháp này.
-
Để sửa lỗi
này ta cần thêm salt vào hàm mã hóa. Thay vì hash = encrypt(pass),
hàm mã hóa sẽ chuyển thành hash = encrypt(salt + pass)và khi bị lộ hash
cũng không thể tìm kiếm được trên Internet để tìm ra mật khẩu chưa mã hóa
6.
Kiểm tra quyền truy cập của người dùng
-
Nguy cơ: Trong các
hệ thống có phân quyền, mỗi người dùng chỉ được phép truy cập các dữ liệu mà mình
được phép. Tuy nhiên, nếu việc kiểm tra quyền không được kiểm soát tốt thì
người dùng có thể truy cập được các dữ liệu không được quyền.
-
Phòng chống: Kiểm tra
quyền trong từng request gửi lên server.
-
Ví dụ: Hàm bên
dưới cho phép quản trị khóa tài khoản người dùng với đầu vào là ID của người
dùng được gửi từ client
public
String lockUsers() {
String strUserId = getRequest().getParameter("userId");
Long userId = Long.parseLong(strUserId);
doLock(userId);
return SUCCESS;
}
|
Như vậy,
bằng cách thay đổi ID của người dùng từ client, người quản trị này có thể khóa
tài khoản của các người dùng mà mình không được phép quản lý.
Để sửa lỗi
này, ta cần kiểm tra quyền khóa của quản trị đối với người dùng này trước khi thực
hiện khóa
public
String lockUsers() {
String strUserId = getRequest().getParameter("userId");
Long userId = Long.parseLong(strUserId);
if (checkLockPermission(userId)) {
doLock(userId);
return SUCCESS;
} else {
return ERROR;
}
}
|
7.
Để lộ dữ liệu của hệ thống
- Nguy cơ: Trên hệ thống tồn tại các chức năng
cho phép kết xuất dữ liệu truy vấn, kết quả làm việc ra dưới dạng các file
excel tuy nhiên chức năng này có các lỗ hổng sau có thể làm lộ dữ liệu của hệ
thống:
·
File exel
được lưu trữ trong thư mục con của thư mục webapp.
·
File exel
sau khi được người dùng tải về không được xóa.
·
Cho phép
truy cập trực tiếp vào các file exel này mà không qua xác thực.
Ví dụ như đường link sau sẽ cho phép
tải một file exel mà hệ thống đã xuất ra trước đó về mà không cần qua các bước
xác thực:
-
Phòng chống:
Các dữ liệu này lưu trong thu mục bên ngoài thư mục
cài đặt web server, việc thực hiện download các dữ liệu này phải qua bước xác
thực và tham số phải mã hóa
0 nhận xét:
Đăng nhận xét