Bài giảng Lập trình an toàn - Chương 1: Kiểm tra đầu vào - Lương Ánh Hoàng
1.1 Các nguyên tắc kiểm tra
Luôn luôn giả định dữ liệu đầu vào là không đáng tin cậy
- Dữ liệu từ mạng trong mô hình client-server
- Dữ liệu từ người dùng
- Dữ liệu từ tệp tin
Ưu tiên loại bỏ dữ liệu hơn là cố gắng sửa chữa dữ liệu.
Thực hiện kiểm tra đầu vào tại nhiều cấp, nhiều điểm
- Kiểm tra đầu vào ở các hàm
- Kiểm tra đầu vào giữa các module.
Không tiếp nhận lệnh trực tiếp từ người dùng nếu chưa qua kiểm tra. Kiểm tra các ký tự đặc biệt, dấu nháy.
Tìm hiểu và sử dụng cơ chế trích dẫn (quoting mechanism) nếu cần. Càng hiểu về dữ liệu bao nhiêu càng lọc được tốt bấy nhiêu.
1.2 Các hàm định dạng xâu
Họ các hàm printf() , syslog() cho phép định dạng dữ liệu rất mềm dẻo và mạnh mẽ tuy nhiên cũng cực kỳ nguy hiểm.
Thận trọng khi sử dụng “%n”
- Tham số %n cho phép ghi ra số lượng ký tự đã kết xuất được ra một địa chỉ bất kỳ chỉ ra trong tham số tương ứng. Nếu không tồn tại tham số nào thì printf sẽ ghi đè lên một vùng nào đó thuộc stack của luồng đang thực thi.
int counter = 0;
printf(“Hello%n”,&counter); // OK, counter = 5 printf(“Hello%n”); // Nguy hiểm !!!
Không sử dụng trực tiếp xâu định dạng từ nguồn bên ngoài
- Xâu định dạng có nguồn gốc từ ngoài chương trình có thể có một vài ký tự đặc biệt mà chương trình chưa lường trước được, hoặc không có tham số thay thế tương ứng.
char str[1024];
gets(str);
printf(“Xin chao:”);
printf(str); // Nguy hiểm !!!
printf(“%s”,str); // OK
Tóm tắt nội dung tài liệu: Bài giảng Lập trình an toàn - Chương 1: Kiểm tra đầu vào - Lương Ánh Hoàng
LẬP TRÌNH AN TOÀN Secure Programming Lương Ánh Hoàng hoangla@soict.hut.edu.vn Mục đích ■ Cung cấp các kiến thức, kỹ thuật cơ bản để xây dựng các ứng dụng an toàn. Yêu cầu Yêu cầu về kiến thức: An ninh mạng Ngôn ngữ lập trình C/C++. Lên lớp đầy đủ Thời lượng môn học Thời lượng: 45 tiết Lý thuyết: 30 tiết Bài tập:15 tiết Tài liệu Secure Program Cookbook for C and C++, Matt Messier, John Viega, O'Reilly 2003. Nội dung Chương 1. Kiểm tra đầu vào Chương 2. Kiểm soát truy nhập Chương 3. Kiểm soát xung đột Chương 4. Mã hóa đối xứng Chương 5. Hàm băm và xác thực thông điệp Chương 6. Mã hóa công khai Chương 7. Anti-Tampering Chương 8. Các vấn đề khác Đánh giá Bài tập lớn: 70% Quá trình: 30% Chương 1. Kiểm tra đầu vào Input Validation Lương Ánh Hoàng hoangla@soict.hut.edu.vn Nội dung Nguyên tắc kiểm tra. Các hàm định dạng xâu (string formatting) . Tràn bộ đệm. ■ ■ Tràn số học. ■ Kiểm tra tên file và đường dẫn. Giải mã URL Cross-Site Scripting SQL Injection Các nguyên tắc kiểm tra Luôn luôn giả định dữ liệu đầu vào là không đáng tin cậy Dữ liệu từ mạng trong mô hình client-server Dữ liệu từ người dùng Dữ liệu từ tệp tin Ưu tiên loại bỏ dữ liệu hơn là cố gắng sửa chữa dữ liệu. Thực hiện kiểm tra đầu vào tại nhiều cấp, nhiều điểm Kiểm tra đầu vào ở các hàm Kiểm tra đầu vào giữa các module. Không tiếp nhận lệnh trực tiếp từ người dùng nếu chưa qua kiểm tra. Kiểm tra các ký tự đặc biệt, dấu nháy. Tìm hiểu và sử dụng cơ chế trích dẫn (quoting mechanism) nếu cần. Càng hiểu về dữ liệu bao nhiêu càng lọc được tốt bấy nhiêu. Các hàm định dạng xâu Họ các hàm printf() , syslog() cho phép định dạng dữ liệu rất mềm dẻo và mạnh mẽ tuy nhiên cũng cực kỳ nguy hiểm. Thận trọng khi sử dụng “%n” Tham số %n cho phép ghi ra số lượng ký tự đã kết xuất được ra một địa chỉ bất kỳ chỉ ra trong tham số tương ứng. Nếu không tồn tại tham số nào thì printf sẽ ghi đè lên một vùng nào đó thuộc stack của luồng đang thực thi. VD. ■ ■ int counter = 0; printf(“Hello%n”,&counter); // OK, counter = 5 printf(“Hello%n”); // Nguy hiểm !!! Không sử dụng trực tiếp xâu định dạng từ nguồn bên ngoài Xâu định dạng có nguồn gốc từ ngoài chương trình có thể có một vài ký tự đặc biệt mà chương trình chưa lường trước được, hoặc không có tham số thay thế tương ứng. VD. ■ ■ char str[1024]; gets(str); printf(“Xin chao:”); printf(str); // Nguy hiểm !!! printf(“%s”,str); // OK Các hàm định dạng xâu Thận trọng khi sử dụng sprintf, vsprintf với “%s” Các hàm trên đều giả định kích thước bộ đệm cho xâu đích là vô hạn. Nên chỉ rõ số lượng ký tự tối đa sẽ sử dụng khi dùng với %s. Nên sử dụng snprintf, vsnprintf nếu có thể. VD char str[i024]; char dst[32]; gets(str); sprintf(dst,”Xau vua nhap vao la %s”,str); // Nguy hiểm sprintf(dst,”Xau vua nhap vao la %.16s”,str); // OK snprintf(dst,32,”Xau vua nhap vao la %s”,str);// OK Tràn bộ đệm Tràn bộ đệm (Buffer Overflow): copy dữ liệu vượt quá biên của một bộ đệm nào đó => đè lên vùng nhớ của biến (cấu trúc) khác. Phần lớn các hàm xử lý xâu trong C đều không thực hiện kiểm tra biên của bộ đệm: gets, strcpy, ... VD1: Dữ liệu bị hỏng int x = 0; char buff[8]; strcpy(buff,”Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAA”); printf(“%d”,x); VD2: Stack bị hỏng char name[8]; gets(name); printf(name); Tràn bộ đệm VD3: Không trở về được từ chương trình con void Hello() { ' _ char name[8]; printf(“What is your name ?”); gets(name); printf(“Hello %s !”, name); } ■ void main() { Hello(); printf(“Bye”); } Tràn bộ đệm VD4: Tấn công có chủ ý trên bộ đệm void Bye() { printf(“Bye”); } ' void Hello() { _ _ void (*p)() = Bye; char nãme[8]; printf(“What is your name ?”); gets(name); printf(“Hello %s !”, name); ' p(); void main() { Hello(); } Tràn bộ đệm Giải pháp: Sử dụng các hàm strncpy, memcpy.và những hàm có kiểm soát kích thước bộ đệm một cách tường minh. Sử dụng Stack Guard trong các trình biên dịch hỗ trợ. Sử dụng DEP (Data Execution Preventation) trên hệ điều hành hỗ trợ. Sử dụng ASLR (Address Space Layout Randomization) trên trình biên dịch và hệ điều hành hỗ trợ. Tràn số học ■ Dữ liệu nhận về có thể có sai sót trong trường liên quan đến kích thước. Các thao tác liên quan đến số nguyên lớn có thể’ bị tràn, lẫn lộn giữa số nguyên không dấu và có dấu VD1: Tràn số unsigned int x = oxFFFFFFFF; // MAX_INT if ( x+5 > 5 ) printf (“X > o” ) else printf(“X < 0”); VD2: Dùng sai kiểu có/không dấu if (x < MAX_SIZE) { // x, số byte cần cấp phát tùy theo giải thuật tính được if (!(ptr = (unsigned char *)malloc(x))) abort( ); } else { ~ /* Handle the error condition ... */ } Kiểm tra tên file và đường dẫn Dữ liệu nhận về có thể là tên file, ứng dụng cần xác định đường dẫn tuyệt đối nếu cần thiết. Dùng hàm realpathQ trên Unix/Linux và GetFullPathName trên Windows. Sử dụng realpath() Nguyên mẫu: char *realpath(const char *pathname, char resolved_path[MAXPATHLEN]); Thận trọng: Có thể tràn resolved_path và không thread-safe. Thư viện: stdlih.h VD char resolved[i024]; char * result = realpath(”printf.c”,resolved); printf(”%s”,result); Kiểm tra tên file và đường dẫn Sử dụng GetFullPathName() Thư viện: windows.h Nguyên mẫu: DWORD GetFullPathName(LPCTSTR IpFileName, DWORD nBufferLength, LPTSTR IpBuffer, LPTSTR *lpFilePath); VD: int nBufferLen = 0; LPTSTR lpBuffer; nBufferLen = GetFullPathName(L”test.c”,0,0,0); if (nBufferLen>0) { , _ _ , lpBuffer = new TCHAR[nBufferLen+i]; GetFullPathName(L”test.c”,nBufferLen,lpBuffer,0); wprintf(L”%s”,lpBuffer); } Giải mã URL RFC 1738 quy định cách mã hóa các ký tự không nhìn thấy được trong URL dưới dạng “%”. VD: Cách giải mã: duyệt từ đầu đến cuối , tìm các ký tự % và thay thế bằng mã ASCII tương ứng. Không sử dụng các hàm xử lý xâu chuẩn vì có thể có ký tự NULL trong URL. Cross-Site Scripting Cross-Site Scripting (XSS) là hình thức tấn công vào trình duyệt người dùng bắt nguồn từ việc kiểm tra lỏng lẻo từ server. Có thể’ dẫn đến thất thoát thông tin nhạy cảm: mật khẩu, session, cookie... Thực hiện bằng cách chèn mã HTML/JAVASCRIPT vào dữ liệu sẽ hiể’n thị ra trình duyệt => đoạn mã sẽ chạy trên trình duyệt của nạn nhân. VD. Một ứng dụng web có hai trang Hello.php: Hiển thị form và nhận tên của người dùng. Chao.php: hiển thị tên nhận được lại cho người dùng. Cross-Site Scripting File Hello.php Xin chào, vui lòng nhập tên bạn File Chao.php <?PHP echo ”Xin chao ”.$_POST['name']; ?> Demo Với tên là : Secure Với tên là: Secure alert('XSS was found !'); Với tên là: Secure alert(‘Hacked'); Giải pháp: Lọc bỏ các thẻ HTML khỏi dữ liệu từ người dùng. Mỗi ngôn ngữ lập trình có một cách riêng. SQL Injection SQL Injection: Tấn công vào CSDL thông qua dữ liệu nhập từ trình duyệt. Lợi dụng việc kiểm tra lỏng lẻo từ đầu vào, chèn mã lệnh SQL vào các truy vấn đến CSDL của ứng dụng web. Thường lợi dụng dấu nháy “ ‘ “ để’ kết thúc câu truy vấn SQL hoặc thêm các câu truy vấn khác. VD: Lệnh so sánh tên và mật khẩu trong SQL select * from users where username = '$user' and password = 'Spass' Nếu $user hoặc Spass chứa dấu “'” thì SQL sẽ hiểu nhầm nội dung truy vấn... Các kỹ thuật khai thác: An ninh mạng VD: Một ứng dụng web muốn kiểm tra tên và mật khẩu gồm hai trang ask.php: Hiện form đăng nhập và thu nhận tên, mật khẩu login.php: Kết nối đến CSDL và kiểm tra SQL Injection VD (tiếp - File ask.php Vui long nhap ten va mat khau Ten: Mat khau: SQL Injection VD (tiếp) - File login.php <?PHP $db_server = "localhost"; $db_username= "root"; $db_password= "123456"; $db = "test"; $table = "users"; $conn = mysql_connect($server,$db_username,$db_password); if (!$conn) { echo "Khong ket noi dc den CSDL"; return; } $ret = mysql_select_db($db,$conn); SQL Injection if (!$ret) { echo "Khong ton tai CSLD tuong ung"; return; $user = $_GET['name']; $pass = $_GET['pass']; $sql = "select * from $table where username='$user' and password='$pass'"; echo $sql; $ret =mysql_query($sql,$conn); if (mysql_num_rows($ret)>o) echo "Dang nhap thanh cong"; else echo "Sai ten hoac mat khau"; ?> SQL Injection Tấn công username = a' or ‘1'=‘1 password = b' or T=‘1 Phòng chống Loại bỏ tất cả các dấu ‘ và các ký tự đặc biệt nếu cần. Sử dụng escaped string Với php/mysql: mysql_real_escape_string, hoặc thêm ‘\'. Với SQL server: thêm ký tự ‘ trước ký tự đặc biệt. Với Oracle DB: thêm ký tự ‘\' trước ký tự đặc biệt.
File đính kèm:
- bai_giang_lap_trinh_an_toan_chuong_1_kiem_tra_dau_vao_luong.docx
- secureprogramming_1_2968_505054.pdf