Bài giảng môn Lập trình an toàn | Trường Đại học Bách Khoa Hà Nội

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

Lương&Ánh&Hoàng&
hoangla@soict.hut.edu.vn&
LẬP&TRÌNH&AN&TOÀN&
Secure&Programming&
! "#$%&'()&'*'&+,-$&./0'1&+2&./#3.&'4&56$&78&9:;&<=$%&'*'&0$%&<>$%&?$&
.@A$B&
Mục&đích&
C&
! DE#&'F#&GH&+,-$&./0'I&
J K$&$,$/&LM$%&
J N%O$&$%P&Q3)&.RS$/&"T"UUB&
! VE$&QW)&7F;&7X&
Yêu&cầu&
Y&
! Z/[,&Q\]$%I&^_&.,-.&
J V`&./#;-.I&Ya&.,-.&
J bA,&.3)Ic_&.,-.&
Thời&lượng&môn&học&
^&
! de'#Re&fR@%R?L&"@@+5@@+&g@R&"&?$<&"UU1&Matt$Messier,$
John$Viega,$O'Reilly$2003B$
Tài&liệu&
_&
! "/\4$%&cB&h,8L&.R?&7F#&GA@&
! "/\4$%&CB&h,8L&i@*.&.R#;&$/3)&
! "/\4$%&YB&h,8L&i@*.&9#$%&7j.&
! "/\4$%&^B&kl&/m?&7n,&90$%&
! "/\4$%&_B&oAL&5pL&GA&9*'&./='&./O$%&7,q)&
! "/\4$%&rB&kl&/m?&'O$%&+/?,&
! "/\4$%&sB&K$.,tZ?L)eR,$%&
! "/\4$%&uB&"*'&G($&7H&+/*'&
Nội&dung&
r&
s&
! bA,&.3)&QW$I&sav&
! w#*&.RS$/I&Yav&
Đánh&giá&
u&
Lương&Ánh&Hoàng&
hoangla@soict.hut.edu.vn&
Chương&1.&Kiểm&tra&đầu&vào&
Input&Validat ion&
cBc&N%#;E$&.x'&+,8L&.R?B&
cBC&"*'&/AL&7y$/&<M$%&9:#&zi.R,$%&g@RL?..,$%{&B&
cBY&ZRA$&5j&7qLB&
cB^&ZRA$&in&/|'B&
cB_&h,8L&.R?&.E$&},Qe&GA&7\[$%&<~$B&
cBr&•,6,&Ll&€•V&
cBs&"R@iitd,.e&d'R,).,$%&
cBu&dwV&‚$ƒe'.,@$&
Nội&dung&
ca&
! V#O$&Q#O$&%,6&7y$/&<P&Q,q#&7F#&GA@&QA&+/O$%&7*$%&.,$&'3;&
J „P&Q,q#&.…&LM$%&.R@$%&LO&/S$/&'Q,e$.tieRGeR&
J „P&Q,q#&.…&$%\[,&<†$%&
J „P&Q,q#&.…&.q)&.,$&
J ‡&
! ˆ#&.,E$&Q@M,&5‰&<P&Q,q#&/4$&QA&'n&%x$%&iŠ?&'/P?&<P&Q,q#B&
! Z/='&/,q$&+,8L&.R?&7F#&GA@&.M,&$/,H#&'()1&$/,H#&7,8L&
J h,8L&.R?&7F#&GA@&‹&'*'&/AL&
J h,8L&.R?&7F#&GA@&%,P?&'*'&L@<#QeB&
J ‡&
! h/O$%&.,-)&$/3$&Qq$/&.R='&.,-)&.…&$%\[,&<†$%&$-#&'/\?&Œ#?&+,8L&.R?B&
! h,8L&.R?&'*'&+`&.=&7•'&5,q.1&<(#&$/*;B&
! ZSL&/,8#&GA&iŠ&<>$%&'4&'/-&.RŽ'/&<~$&zŒ#@.,$%&Le'/?$,iL{&$-#&'F$B&
! "A$%&/,8#&GH&<P&Q,q#&5?@&$/,E#&'A$%&Q|'&7\]'&.n.&5(;&$/,E#B&
1.1&Các&nguyên&tắc&kiểm&tra&
cc&
! o|&'*'&/AL&!"#$%&'()*)+,+-./'())'/@&)/•)&7y$/&<M$%&<P&Q,q#&R(.&LHL&<•@&GA&
LM$/&L‘&.#;&$/,E$&'’$%&'='&+“&$%#;&/,8LB&
! Z/3$&.R|$%&+/,&iŠ&<>$%&”%n•&
J Z/?L&in&v$&'/@&)/•)&%/,&R?&in&Q\]$%&+`&.=&7l&+-.&9#(.&7\]'&R?&Lj.&7y?&'/–&5(.&+“&'/–&R?&
.R@$%&./?L&in&.\4$%&0$%B&N-#&+/O$%&.—$&.M,&./?L&in&$A@&./S&printf&i‘&%/,&7˜&QE$&Lj.&G†$%&
$A@&7m&./#j'&i.?'+&'X?&Q#—$%&7?$%&./='&./,B&
J ™„B&
int $counter$=$0;$
printf(“Hello%n”,&counter);$//$OK,$counter$=$5$
printf(“Hello%n”);$//$Nguy$hiểm$!!!$$
! h/O$%&iŠ&<>$%&.R='&.,-)&9:#&7y$/&<M$%&.…&$%#—$&5E$&$%@A,&
J š:#&7y$/&<M$%&'m&$%#—$&%n'&.…&$%@A,&'/\4$%&.RS$/&'m&./8&'m&Lj.&GA,&+`&.=&7•'&5,q.&LA&
'/\4$%&.RS$/&'/\?&Q\[$%&.R\W'&7\]'1&/@•'&+/O$%&'m&./?L&in&./?;&./-&.\4$%&0$%B&&
J ™„B&
&char $str[1024];$
$gets(str);$
$printf(“Xin$chao:”);$
$printf(str);$//$Nguy$hiểm$!!!$
$printf(“%s”,str);$//$OK$$
1.2&Các&hàm&định&dạng&xâu&
cC&
! Z/3$&.R|$%&+/,&iŠ&<>$%&i)R,$.g1&Gi)R,$.g&GW,&“%s”&
J "*'&/AL&.RE$&7H#&%,6&7y$/&+Ž'/&./\W'&5j&7qL&'/@&9:#&7Ž'/&QA&GO&/M$B&
J NE$&'/–&R›&in&Q\]$%&+`&.=&.n,&7?&i‘&iŠ&<>$%&+/,&<†$%&GW,&viB&
J NE$&iŠ&<>$%&i$)R,$.g1&Gi$)R,$.g&$-#&'m&./8B&
J ™„&
char$str[1024];$
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$
&
$
1.2&Các&hàm&định&dạng&xâu&
cY&
! ZRA$&5j&7qL&zb#ggeR&œGeR}Q@•{I&'@);&<P&Q,q#&G\].&Œ#*&5,E$&'X?&Lj.&5j&
7qL&$A@&7m&žŸ&7˜&QE$&G†$%&$/W&'X?&5,-$&z'(#&.R '{&+/*'B&
! f/F$&QW$&'*'&/AL&9Š&Q`&9:#&.R@$%&"&7H#&+/O$%&./='&/,q$&+,8L&.R?&5,E$&
'X?&5j&7qLI&/0%+*)+%"1!,*)2&
! ™„cI&„P&Q,q#&5y&/‰$%&
&int$ $x$=$0;$
$char $buff[8];$
$strcpy(buff,”Hello$$$AAAAAAAAAAAAAAAAAAAAAAAAAAAAA”);$
$printf(“%d”,x);$
™„CI&d.?'+&5y&/‰$%&
&char $name[8];$
$gets(name);$
$printf(name);$
$
1.3&Tràn&bộ&đệm&
c^&
! ™„YI&h/O$%&.R‹&GH&7\]'&.…&'/\4$%&.RS$/&'@$&
$void$Hello()$
${$
$ $char$name[8];$
$ $printf(“What$is$your$name$?”);$
$ $gets(name);$
$ $printf(“Hello$%s$!”,$name); $$
$} $$
$void$main()$
${$
$ $Hello();$
$ $printf(“Bye”);$
$}$
1.3&Tràn&bộ&đệm&
c_&
! ™„^I&Z($&'O$%&'m&'/X&`&.RE$&5j&7qL&
$void$Bye()$
${$
$ $printf(“Bye”);$
$}$
$void$Hello()$
${$
$ $void$(*p)()$=$Bye;$
$ $char$name[8];$
$ $printf(“What$is$your$name$?”);$
$ $gets(name);$
$ $printf(“Hello$%s$!”,$name);$
$ $p(); $$
$} $$
$void$main()$
${$
$ $Hello();$
$}$
1.3&Tràn&bộ&đệm&
cr&
! •,6,&)/*)I&&
J dŠ&<>$%&'*'&/AL&i.R$');1&LeL');‡GA&$/P$%&/AL&'m&+,8L&i@*.&+Ž'/&./\W'&
5j&7qL&Lj.&'*'/&.\[$%&L,$/B&
J dŠ&<>$%&Stack&Guard&.R@$%&'*'&.RS$/&5,E$&<y'/&/¡&.R]B&&
J dŠ&<>$%&DEP&(Data&Execution&Preventation)&.RE$&/q&7,H#&/A$/&/¡&.R]B&
J dŠ&<>$%&ASLR&(Address&Space&Layout&Randomization)&.RE$&.RS$/&5,E$&
<y'/&GA&/q&7,H#&/A$/&/¡&.R]B&
1.3&Tràn&bộ&đệm&
cs&
! „P&Q,q#&$/3$&GH&'m&./8&'m&i?,&im.&.R@$%&.R\[$%&Q,E$&Œ#?$&7-$&+Ž'/&
./\W'B&
! "*'&./?@&.*'&Q,E$&Œ#?$&7-$&in&$%#;E$&QW$&'m&./8&5y&.RA$1&Q~$&Qj$&%,P?&in&
$%#;E$&+/O$%&<(#&GA&'m&<(#&
! ™„cI&ZRA$&in&
unsigned$$int$x$=$0xFFFFFFFF;$//$MAX_INT$
if $($x+5$>$5$)$printf$(“X$>$0”$)$
$else $printf(“X$<$0”);$
™„CI&„†$%&i?,&+,8#&'mT+/O$%&<(#&
&&&&&&&&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$...$*/$
$}$
&&
)))
1.4&Tràn&số&học&
cu&
! „P&Q,q#&$/3$&GH&'m&./8&QA&.E$&},Qe1&0$%&<>$%&'F$&9*'&7y$/&7\[$%&<~$&
.#;q.&7n,&$-#&'F$&./,-.B&
! „†$%&/AL&Re?Q)?./z{&.RE$&€$,9TV,$#9&GA&•e.¢#QQf?./N?Le&.RE$&
£,$<@•iB&
! dŠ&<>$%&"03-!3%4'()
! N%#;E$&L~#I&&
&char$*realpath(const$char$*pathname,$char$resolved_path[MAXPATHLEN]);$
! Z/3$&.R|$%I&"m&./8&.RA$&Rei@QGe<¤)?./&GA&+/O$%&./Re?<ti?geB&
! Z/\&G,q$I&stdlih.h$
! ™„&
&char$resolved[1024];$
$char$*$result$=$realpath("printf.c",resolved);$
$printf("%s",result);$
)))
1.5&Kiểm&tra&tên&qile&và&đường&dẫn&
c¥&
! dŠ&<>$%&50%67--83%493:0'()
! Z/\&G,q$I&•,$<@•iB/&
! N%#;E$&L~#I&&
&DWORD$GetFullPathName(LPCTSTR$lpFileName,$DWORD$nBufferLength,$LPTSTR$
$ $$$$$$$$$$$$$lpBuffer,$LPTSTR$*lpFilePath);$
! ™„I&
&int $nBufferLen$=$0;$
$LPTSTR $lpBuffer;$
$
$nBufferLen$=$GetFullPathName(L"test.c",0,0,0);$
$if$(nBufferLen>0)$
${$
$ $lpBuffer$=$new$TCHAR[nBufferLen+1];$
$ $GetFullPathName(L"test.c",nBufferLen,lpBuffer,0);$
$ $wprintf(L"%s",lpBuffer);$
$}$
&&
)))
1.5&Kiểm&tra&tên&qile&và&đường&dẫn&
Ca&
| 1/131

Preview text:

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. 2 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 đủ 3
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 4 Tài liệu
• Secure Program Cookbook for C and C++, Matt Messier,
John Viega, O'Reilly 2003. 5 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 6 7 Đánh giá • Bài tập lớn: 70% • Quá trình: 30% 8
Chương 1. Kiểm tra đầu vào Input Validation Lương Ánh Hoàng
hoangla@soict.hut.edu.vn Nội dung 1.1 Nguyên tắc kiểm tra.
1.2 Các hàm định dạng xâu (string formatting) . 1.3 Tràn bộ đệm. 1.4 Tràn số học.
1.5 Kiểm tra tên }ile và đường dẫn. 1.6 Giải mã URL 1.7 Cross-­‐Site Scripting 1.8 SQL Injection 10
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. 11
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. – 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 12
1.2 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[1024]; 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 13 1.3 Tràn bộ đệm
• Tràn bộ đệm (Buffer Over}low): 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); 14 1.3 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”); } 15 1.3 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 name[8];
printf(“What is your name ?”); gets(name);
printf(“Hello %s !”, name); p(); } void main() { Hello(); } 16 1.3 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ợ. 17 1.4 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 = 0xFFFFFFFF; // MAX_INT if
( x+5 > 5 ) printf (“X > 0” ) 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 ... */ } 18
1.5 Kiểm tra tên qile và đường dẫn
• Dữ liệu nhận về có thể là tên }ile, ứng dụng cần xác định đường dẫn
tuyệt đối nếu cần thiết.
• Dùng hàm realpath() 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[1024];
char * result = realpath("printf.c",resolved); printf("%s",result); 19
1.5 Kiểm tra tên qile và đường dẫn
• Sử dụng GetFullPathName() § Thư viện: windows.h § Nguyên mẫu:
DWORD GetFullPathName(LPCTSTR lpFileName, DWORD nBufferLength, LPTSTR
lpBuffer, LPTSTR *lpFilePath); § VD: int nBufferLen = 0; LPTSTR lpBuffer;
nBufferLen = GetFullPathName(L"test.c",0,0,0); if (nBufferLen>0) {
lpBuffer = new TCHAR[nBufferLen+1];
GetFullPathName(L"test.c",nBufferLen,lpBuffer,0);
wprintf(L"%s",lpBuffer); } 20