lập trình an toàn - secure programming

131
Lương Ánh Hoàng [email protected] LẬP TRÌNH AN TOÀN Secure Programming

Upload: beatmaking

Post on 13-Jan-2017

464 views

Category:

Technology


4 download

TRANSCRIPT

Page 1: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

LẬP  TRÌNH  AN  TOÀN  Secure  Programming  

Page 2: Lập Trình an toàn - Secure programming

•  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.  

Mục  đích  

2  

Page 3: Lập Trình an toàn - Secure programming

•  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  đủ  

Yêu  cầu  

3  

Page 4: Lập Trình an toàn - Secure programming

•  Thời  lượng:  45  tiết  –  Lý  thuyết:  30  tiết  –  Bài  tập:15  tiết  

Thời  lượng  môn  học  

4  

Page 5: Lập Trình an toàn - Secure programming

•  Secure  Program  Cookbook  for  C  and  C++,  Matt  Messier,  John  Viega,  O'Reilly  2003.  

Tài  liệu  

5  

Page 6: Lập Trình an toàn - Secure programming

•  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  

Nội  dung  

6  

Page 7: Lập Trình an toàn - Secure programming

7  

Page 8: Lập Trình an toàn - Secure programming

•  Bài  tập  lớn:  70%  •  Quá  trình:  30%  

Đánh  giá  

8  

Page 9: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  1.  Kiểm  tra  đầu  vào  Input  Validation  

Page 10: Lập Trình an toàn - Secure programming

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  

Nội  dung  

10  

Page 11: Lập Trình an toàn - Secure programming

•  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.1  Các  nguyên  tắc  kiểm  tra  

11  

Page 12: Lập Trình an toàn - Secure programming

•  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    

1.2  Các  hàm  định  dạng  xâu  

12  

Page 13: Lập Trình an toàn - Secure programming

•  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  

   

1.2  Các  hàm  định  dạng  xâu  

13  

Page 14: Lập Trình an toàn - Secure programming

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

 

1.3  Tràn  bộ  đệm  

14  

Page 15: Lập Trình an toàn - Secure programming

•  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”);    }  

1.3  Tràn  bộ  đệm  

15  

Page 16: Lập Trình an toàn - Secure programming

•  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();    }  

1.3  Tràn  bộ  đệm  

16  

Page 17: Lập Trình an toàn - Secure programming

•  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ợ.  

1.3  Tràn  bộ  đệm  

17  

Page 18: Lập Trình an toàn - Secure programming

•  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  ...  */    }            

1.4  Tràn  số  học  

18  

Page 19: Lập Trình an toàn - Secure programming

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

1.5  Kiểm  tra  tên  qile  và  đường  dẫn  

19  

Page 20: Lập Trình an toàn - Secure programming

•  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);    }            

1.5  Kiểm  tra  tên  qile  và  đường  dẫn  

20  

Page 21: Lập Trình an toàn - Secure programming

•  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  “%<Mã  hexa>”.  

•  VD:    http://m%61il.google.com    http://m%25%36%31il.google.com  

•  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.  

         

1.6  Giải  mã  URL  

21  

Page 22: Lập Trình an toàn - Secure programming

•  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.  

         

1.7  Cross-­‐Site  Scripting  

22  

Page 23: Lập Trình an toàn - Secure programming

•  File  Hello.php  <HTML>  Xin  chào,  vui  lòng  nhập  tên  bạn  <FORM  action="chao.php"  method=“POST">  <input  type="text"  name="name"/><br/>  <input  type="submit"  value="Submit">  </FORM>  </HTML>  

•  File  Chao.php  <?PHP  echo  "Xin  chao  ".$_POST['name'];  ?>  

•  Demo  •  Với  tên  là  :  Secure  •  Với  tên  là:  Secure  <script>alert('XSS  was  found  !');</script>    •  Với  tên  là:  Secure  <s%63ript>alert(‘Hacked’);</s%63ript>  

•  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.  

1.7  Cross-­‐Site  Scripting  

23  

Page 24: Lập Trình an toàn - Secure programming

•  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  =  ‘$pass’    –  Nếu  $user  hoặc  $pass  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  

1.8  SQL  Injection  

24  

Page 25: Lập Trình an toàn - Secure programming

•  VD  (tiếp  –  File  ask.php  

 <HTML>  Vui  long  nhap  ten  va  mat  khau  <FORM  action="login.php"  method="GET">  Ten:  <INPUT  type="text"  name="user"/><BR/>  Mat  khau:<INPUT  type="text"  name="pass"/><BR/>  <INPUT  type="submit"  name="Submit">    </FORM>      

1.8  SQL  Injection  

25  

Page 26: Lập Trình an toàn - Secure programming

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

1.8  SQL  Injection  

26  

Page 27: Lập Trình an toàn - Secure programming

 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)>0)      echo  "Dang  nhap  thanh  cong";  else      echo  "Sai  ten  hoac  mat  khau";  

   ?>  

1.8  SQL  Injection  

27  

Page 28: Lập Trình an toàn - Secure programming

•  Tấn  công  –  username  =  a’  or  ‘1’=‘1  –  password  =  b’  or  ‘1’=‘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.      

1.8  SQL  Injection  

28  

Page 29: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  2.  Kiểm  soát  truy  nhập  Access  Control  

Page 30: Lập Trình an toàn - Secure programming

2.1  Cơ  chế  kiểm  soát  truy  nhập  trên  Unix/Linux  2.2  Cơ  chế  kiểm  soát  truy  nhập  trên  Windows  2.3  Hạ  thấp  quyền  truy  nhập  của  tiến  trình  2.4  Xóa  }ile  an  toàn  2.5  Hạn  chế  quyền  truy  nhập  trên  }ile  2.6  Khóa  }ile  2.7  Tạo  }ile  tạm  2.8  Hạn  chế  truy  nhập  đến  hệ  thống  }ile    

Nội  dung  

30  

Page 31: Lập Trình an toàn - Secure programming

•  Trên  Unix/Linux  tất  cả  các  tài  nguyên  đều  được  coi  là  }ile:  tệp  tin,  ổ  đĩa,  bộ  nhớ,  thiết  bị….  

•  Mỗi  }ile  kiểm  soát  bởi  user  id  và  group  id.  •  Mỗi  tiến  trình  có  ba  quyền:  effective  user  id,  real  user  id,  saved  user  id.  

Effective  user  id  được  sử  dụng  trong  phần  lớn  các  kiểm  tra.    •  Mỗi  tiến  trình  cũng  thuộc  về  ba  nhóm:  effective  group  id,  real  group  id,  

saved  group  id.  •  Có  ba  loại  quyền  

•  Đọc  (read)  •  Ghi  (write)  •  Thực  thi  (execute)  

2.1  Cơ  chế  kiểm  soát  truy  nhập  trên  Unix/Linux  

31  

Page 32: Lập Trình an toàn - Secure programming

•  Mỗi  }ile  sẽ  có  ba  nhóm  quyền  tương  ứng  với:  user  id,  group  id,  và  other.  

-­‐rwxr-­‐xr-­‐x  1    Luong  Anh  Hoang    None    17964    Aug  28  23:45  test.exe  •  Khi  tiến  trình  tạo  một  }ile  hoặc  tài  nguyên,  hệ  thống  sẽ  gán  user  id  và  

group  id  cho  }ile  mới  đó  bằng  effective  user  id  và  effective  group  id  của  tiến  trình.  

•  Khi  tiến  trình  truy  nhập  một  }ile  hoặc  tài  nguyên,  hệ  thống  sẽ  lần  lượt  so  sánh  user  id,  group  id  của  tiến  trình  và  }ile  và  chọn  ra  tập  quyền  tương  ứng.  Nếu  không  khớp  thì  lớp  quyền  thứ  3  sẽ  được  sử  dụng.  

2.1  Cơ  chế  kiểm  soát  truy  nhập  trên  Unix/Linux  

32  

Page 33: Lập Trình an toàn - Secure programming

•  Mỗi  }ile  cũng  có  thể  có  3  bit  đặc  biệt  •  Sticky.  Nếu  bit  này  được  thiết  lập,  người  dùng  sẽ  không  thể  xóa  hay  đổi  tên  }ile  của  người  khác  nằm  trong  thưc  mục  mà  người  dùng  quản  lý.  Mặc  định  là  không  được  thiết  lập.  

•  Setuid:  Bit  này  liên  quan  đến  quá  trình  tạo  một  tiến  trình  mới.  Nếu  bit  này  được  thiết  lập,  tiến  trình  được  tạo  từ  }ile  này  sẽ  không  kế  thừa  quyền  từ  tiến  trình  cha,  mà  sẽ  có  quyền  từ  user  id  của  chính  }ile  đó.  

•  Setgid:    •  Đối  với  }ile  thực  thi,  nếu  bit  này  được  thiết  lập  thì  một  tiến  trình  mới  được  tạo  sẽ  có  quyền  từ  groupd  id  của  }ile  đó  chứ  không  kế  thừa  từ  tiến  trình  cha  (tương  tự  Setuid).  

•  Đối  với  thưc  mục,  nếu  bit  này  được  thiết  lập  thì  các  }ile  tạo  trong  thư  mục  này  sẽ  có  groupd  id  của  thư  mục  cha,  chứ  không  kế  thừa  từ  tiến  trình  tạo  ra  }ile  đó.  

2.1  Cơ  chế  kiểm  soát  truy  nhập  trên  Unix/Linux  

33  

Page 34: Lập Trình an toàn - Secure programming

•  Windows  sử  dụng  ACL:  Access  Control  List  để  phân  quyền  tài  nguyên.  

•  Các  tài  nguyên  của  Windows:  }ile,  registry,  mutex,  event,  IPC…  được  kiểm  soát  thông  qua  DACL  và  SACL.  

•  DACL  là  danh  sách  các  ACE,  mỗi  ACE  là  một  luật  quy  định  một  quyền  hạn  cụ  thể.  

•  DACL  rỗng  tương  đương  với  việc  tất  cả  mọi  người  có  toàn  quyền  truy  nhập  tới  đối  tượng.  

•  Mỗi  ACE  bao  gồm  3  thông  tin:    •  SID:  Đại  diện  cho  một  user  hay  một  group  trong  hệ  thống  •  Quyền  truy  nhập  •  Giá  trị  boolean  tương  ứng  với  cho  phép  hay  không  cho  phép.  

2.2  Cơ  chế  kiểm  soát  truy  nhập  trên  Windows  

34  

Page 35: Lập Trình an toàn - Secure programming

•  Các  quyền  truy  nhập    

2.2  Cơ  chế  kiểm  soát  truy  nhập  trên  Windows  

35  

TÊN   Diễn  giải  DELETE   The  ability  to  delete  the  object  

READ_CONTROL   The  ability  to  read  the  object's  security  descriptor,  not  including  its  SACL  

SYNCHRONIZE  The  ability  for  a  thread  to  wait  for  the  object  to  be  put  into  the  signaled  state;  not  all  objects  support  this  functionality  

WRITE_DAC   The  ability  to  modify  the  object's  DACL  WRITE_OWNER   The  ability  to  set  the  object's  owner  

GENERIC_READ   The  ability  to  read  from  or  query  the  object  

GENERIC_WRITE   The  ability  to  write  to  or  modify  the  object  

GENERIC_EXECUTE   The  ability  to  execute  the  object  (applies  primarily  to  }iles)  

GENERIC_ALL   Full  control  

Page 36: Lập Trình an toàn - Secure programming

•  Ví  dụ  ACE  •  DENY            GENERIC_ALL                  Everyone:  Cấm  mọi  quyền  với  group  Everyone  •  ALLOW    GENERIC_WRITE      Marketing:  Cho  phép  nhóm  group  Marketing  được  quyền  ghi  

•  Mỗi  đối  tượng  đều  có  một  Owner,  chính  là  người  tạo  ra  đối  tượng.  

•  Owner  có  toàn  quyền  với  đối  tượng  bất  kể  trong  DACL  có  cấm  hay  không.  

•  Owner  có  thể  bị  chiếm  bởi  user  khác.    

2.2  Cơ  chế  kiểm  soát  truy  nhập  trên  Windows  

36  

Page 37: Lập Trình an toàn - Secure programming

•  Nếu  một  tiến  trình  có  đặc  quyền  cao,  thực  hiện  các  thao  tác  nguy  hiểm  =>  cần  hạ  thấp  quyền  trước  khi  thực  hiện.  

•  Tiến  trình  có  thể  kiểm  tra  real  user  id,  real  group  id  bằng  lệnh  getuid  (),  getgid().  Đây  là  các  đặc  quyền  kế  thừa  từ  tiến  trình  cha.  

•  Tiến  trình  có  thể  kiểm  tra  effective  user  id  và  effective  group  id  bằng  lệnh  geteuid()  và  getegid().  Đây  thường  là  user  id  có  đặc  quyền  cao  hơn  (do  được  khởi  chạy  từ  super  user,  hoặc  các  bit  setuid  được  bật).  

•  Tiến  trình  từ  bỏ  đặc  quyền  bằng  việc  thiết  lập  group  mới  chính  là  real  user  id  qua  lệnh    •  setgroups():  Thiết  lập  lại  nhóm  của  tiến  trình.    •  setegid():  Thiết  lập  lại  effective  group  id  của  tiến  trình.  •  seteuid():  Thiết  lập  lại  effective  user  id  của  tiến  trình.  

 

2.3  Hạ  thấp  quyền  truy  nhập  của  tiến  trình  

37  

Page 38: Lập Trình an toàn - Secure programming

•  Thông  thường,  một  }ile  sau  khi  xóa  sẽ  được  hệ  điều  hành  đánh  dấu  là  xóa,  nội  dung  chưa  hoàn  toàn  bị  loại  bỏ  trên  đĩa.  

•  Giải  pháp  •  Ghi  đè  thông  tin  khác  nhiều  lần  lên  đĩa.  •  Ghi  đè  dữ  liệu  ngâu  nhiên  nhiều  lần  lên  đĩa.  •  Ghi  đè  sử  dụng  mẫu  định  sẵn  lên  đĩa.  •  Sau  mỗi  chu  kỳ  ghi,  sử  dụng  fsync  để  đồng  bộ  với  đĩa,  vô  hiệu  hóa  cơ  chế  cache.  Hoặc  lệnh  f}lush()  nếu  sử  dụng  thư  viện  C.  

•  Một  vài  mẫu  được  sử  dụng  •  static  unsigned  char  single_pats[16]  =  {  0x00,  0x11,  0x22,  0x33,  0x44,  0x55,  0x66,  0x77,  0x88,  0x99,  0xaa,  0xbb,  0xcc,  0xdd,  0xee,  0xff  };    

•  static  unsigned  char  triple_pats[6][3]  =  {  {  0x92,  0x49,  0x24  },  {  0x49,  0x24,  0x92  },  {  0x24,  0x92,  0x49  },  {  0x6d,  0xb6,  0xdb  },  {  0xb6,  0xdb,  0x6d  },  {  0xdb,  0x6d,  0xb6  }  };    

 

2.4  Xóa  qile  an  toàn  

38  

Page 39: Lập Trình an toàn - Secure programming

•  Unix/Linux  sử  dụng  umask  cho  mỗi  tiến  trình  để  vô  hiệu  hóa  một  vài  bit  khi  tiến  trình  tạo  }ile.  

•  Hàm  fopen,  open  luôn  luôn  tạo  }ile  với  quyền  666.  •  Giả  sử  tiến  trình  muốn  tạo  }ile  với  quyền  666:  

requested_permissions  =  0666;    actual_permissions  =  requested_permissions  &  ~umask(  );  

•  Ứng  dụng  thay  đổi  umask  bằng  hàm  umask()  trước  khi  thực  hiện  lời  gọi  tạo  }ile.  #include  <sys/types.h>  #include  <sys/stat.h>    mode_t    umask(mode_t    mask);        

 

2.5  Hạn  chế  quyền  truy  nhập  trên  qile  

39  

Page 40: Lập Trình an toàn - Secure programming

•  Tiến  trình  muốn  kiểm  soát  truy  nhập  trên  một  phần  của  }ile  hay  toàn  bộ  }ile  để  tránh  xung  đột  khi  có  nhiều  tiến  trình  cùng  truy    nhập  trên  }ile.  

•  Unix/Linux  cung  cấp  cơ  chế  khóa  mềm:  Mọi  tiến  trình  đều  có  quyền  giành  được  khóa  và  thao  tác  trên  }ile,  tuy  nhiên  không  phải  tiến  trình  nào  cũng  tuân  thủ  theo  khóa  và  có  thể  phá  hỏng  dữ  liệu  của  tiến  trình  khác.  

•  Windows  thực  hiện  vấn  đề  này  tốt  hơn  bằng  khóa  cứng.  Có  hai  loại  khóa:  •  Shared  Lock:  Cho  phép  các  tiến  trình  khác  (kể  cả  tiến  trình  giành  được  khóa)  đọc  nhưng  không  được  ghi  vào  một  phần  đã  khóa  của  }ile.    

•  Exclusive  Lock  :  Cấm  tất  cả  các  tiến  trình  khác  không  được  đọc  hay  ghi  vào  phần  đã  khóa  của  }ile.  Tiến  trình  giành  được  khóa  có  quyền  đọc  hoặc  ghi  vào  }ile.  

   

 

2.6  Khóa  qile  

40  

Page 41: Lập Trình an toàn - Secure programming

•  Các  hàm  khóa  }ile  trên  Windows  •  LockFile,  UnlockFile:  Khóa  và  mở  khóa  đồng  bộ,  sẽ  không  trở  về  đến  khi  giành  được  khóa  hoặc  mở  được  khóa.  

•  LockFileEx,  UnlockFileEx:  Khóa  và  mở  khóa  đồng  bộ  hoặc  bất  đồng  bộ.  •  Khóa  }ile  cũng  có  thể  xác  định  lúc  tạo  lập/truy  nhập  }ile  thông  qua  hàm  

CreateFile.  •  Đoạn  chương  trình  sau  sẽ  mở  một  }ile  để  đọc  với  chế  độ  Shared  Lock.  

 char  buff[1024];    DWORD  bytesRead  =  0;    HANDLE  fileHandle  =  NULL;    fileHandle  =  CreateFile(L"C:\\SecureProgramming\\Test.txt",          GENERIC_READ|GENERIC_WRITE,          FILE_SHARE_READ|FILE_SHARE_WRITE,          0,          OPEN_ALWAYS,          FILE_ATTRIBUTE_NORMAL,          0);      

2.6  Khóa  qile  

41  

Page 42: Lập Trình an toàn - Secure programming

•  VD  (tiếp)    ReadFile(fileHandle,buff,128,&bytesRead,0);    buff[bytesRead]  =  0;    printf("File  content:%s\n",buff);    LockFile(fileHandle,0,0,100,0);  //  Exclusive  Lock    printf("File  is  locked,  press  any  key  to  unlock...\n");      getch();    UnlockFile(fileHandle,0,0,100,0);    printf("File  is  unlocked\n");    getch();    CloseHandle(fileHandle);  

   

2.6  Khóa  qile  

42  

Page 43: Lập Trình an toàn - Secure programming

•  Ứng  dụng  tạo  }ile  tạm  để  lưu  trữ  thông  tin  tạm  thời  của  chương  trình.  •  File  tạm  nên  được  tạo  lập  một  cách  an  toàn,  và  xóa  khi  kết  thúc  chương  

trình.  •  Trên  unix/linux:  

•  Hàm  mkstemp()  có  thể  sử  dụng  để  tạo  }ile  tạm  với  tên  ngẫu  nhiên.  •  Ứng  dụng  cần  xóa  }ile  theo  tên,  ngay  sau  lời  gọi  mkstemp  để  đảm  bảo  không  tiến  

trình  nào  truy  nhập  được.  •  Sau  khi  tiến  trình  kết  thúc  một  cách  bình  thường/không  bình  thường,  }ile  tạm  sẽ  

không  thể  truy  nhập  được  nữa.  •  VD  

 char    szPath[]  =  “fileXXXXXX";    int  fd;      fd  =  mkstemp(szPath);    unlink(szPath);    printf("Temperary  file  created,  press  any  key  to  continue...");    write(fd,"Hello",5);    close(fd);  

2.7  Tạo  qile  tạm  

43  

Page 44: Lập Trình an toàn - Secure programming

•  Trên  Windows:  •  Không  có  hàm  tương  đương  mkstemp()  •  GetTempFileName()  sinh  tên  }ile  ngẫu  nhiên  nhưng  dễ  đoán.  •  GetTempPath()  lấy  đường  dẫn  đến  thư  mục  tạm  của  người  dùng  hiện  tại.  •  Tạo  }ile  bằng  hàm  CreateFile  với  hai  thuộc  tính  FILE_ATTRIBUTE_TEMPORARY  và  

FILE_FLAG_DELETE_ON_CLOSE  •  VD  

HANDLE  }ileHandle  =  NULL;  }ileHandle  =  CreateFile(L"C:\\SecureProgramming\\Tmp.txt",  

   GENERIC_READ|GENERIC_WRITE,      FILE_SHARE_READ|FILE_SHARE_WRITE,      0,      OPEN_ALWAYS,        FILE_ATTRIBUTE_TEMPORARY|    FILE_FLAG_DELETE_ON_CLOSE,          0);      

           

2.7  Tạo  qile  tạm  

44  

Page 45: Lập Trình an toàn - Secure programming

•  Trên  Unix/Linux,  ứng  dụng  có  thể  tự  giới  hạn  phạm  vi  truy  nhập  hệ  thống  tệp  tin  của  mình  bằng  lệnh  chroot()  

•  Sau  khi  gọi  chroot():  •  Tiến  trình  không  thể  mở  rộng  phạm  vi  truy  nhập  bằng  lệnh  chroot  lần  nữa..  •  Tiến  trình  chỉ  có  thể  thu  hẹp  hơn  nữa  phạm  vi  truy  nhập  của  mình.  •  Tiến  trình  phải  chủ  động  gọi  thêm  chdir()  để  lệnh  chroot  có  hiệu  lực.  

•  VD:    #include  <unistd.h>    chroot("/new/root/directory");    chdir("/");      

         

2.8  Hạn  chế  truy  nhập  đến  hệ  thống  qile  

45  

Page 46: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  3.  Kiểm  soát  xung  đột  Synchronization  Technique  

Page 47: Lập Trình an toàn - Secure programming

3.1  Khái  niệm  3.2  Đoạn  găng  (Critical  Section).  3.3  Đèn  hiệu  (Semaphore)    3.4  Mutex  3.5  Event  3.6  SRW  Lock  

Nội  dung  

47  

Page 48: Lập Trình an toàn - Secure programming

§  Xung  đột  là  vấn  đề  phát  sinh  khi  nhiều  luồng  của  chương  trình  chạy  trên  bộ  vi  xử  lý  đa  nhân  cùng  truy  nhập  một  tài  nguyên  hệ  thống.  

§  Ví  dụ  

3.1  Khái  niệm  

48  

int  x  =  0;  DWORD  WINAPI  Thread(LPVOID    lpParam)  {  

 for  (int  i=0;i<2000000;i++)  x++;    return  0;  

}  int  _tmain(int  argc,  _TCHAR*  argv[])  {    

 HANDLE  hThread1  =  CreateThread(NULL,NULL,Thread,NULL,NULL,NULL);    HANDLE  hThread2  =  CreateThread(NULL,NULL,Thread,NULL,NULL,NULL);    WaitForSingleObject(hThread1,INFINITE);    WaitForSingleObject(hThread2,INFINITE);    printf("X=%d",x);    getch();    return  0;  

}  

Page 49: Lập Trình an toàn - Secure programming

§  Đoạn  găng  (Critical  Section)  là  đoạn  chương  trình  được  bảo  vệ  bởi  hệ  điều  hành  sao  cho  tại  mọi  thời  điểm  chỉ  có  một  luồng  được  phép  thực  thi.  

§  Sử  dụng  §  Khai  báo:    CRITICAL_SECTION  cs  §  Khởi  tạo:    InitializeCriticalSection(&cs)  §  Sử  dụng  

 EnterCriticalSection(&cs)    //  Bắt  đầu  đoạn  găng    …    //  Kết  thúc  đoạn  găng    LeaveCriticalSection(&cs)    //      DeleteCriticalSection(&cs)  

§  Ví  dụ  §  Đặc  điểm:  chỉ  có  tác  dụng  trong  cùng  một  tiến  trình  

3.2  Đoạn  găng  

49  

Page 50: Lập Trình an toàn - Secure programming

§  Đèn  hiệu  (Semaphore)  dùng  để  giới  hạn  số  lượng  luồng  tối  đa  được  phép  thực  thi  cùng  một  đoạn  chương  trình.  

§  Sử  dụng  §  Khai  báo:    HANDLE  hSemaphore  §  Khởi  tạo:    hSemaphore  =  CreateSemaphore(NULL,5,5,NULL)  §  Sử  dụng  

 WaitForSingleObject(hSemaphore,  0L)    //    …    //    ReleaseSemaphore(hSemaphore,1,NULL)    //    CloseHandle(hSemaphore)  

§  Ví  dụ  §  Đặc  điểm  

§  Dùng  chung  được  giữa  các  tiến  trình  §  Tốc  độ  chậm  hơn  CRITICAL_SECTION  

3.3  Đèn  hiệu  

50  

Page 51: Lập Trình an toàn - Secure programming

§  Mutex  dùng  để  bảo  vệ  tài  nguyên  của  chương  trình,  tại  một  thời  điểm  chỉ  cho  phép  một  luồng  của  một  tiến  trình  truy  nhập.  

§  Sử  dụng  §  Khai  báo:    HANDLE  hMutex;  §  Khởi  tạo:    hMutex  =  CreateMutex(NULL,  FALSE,  NULL)  §  Sử  dụng  

 WaitForSingleObject(hMutex,  INFINITE)    //    …    //    ReleaseMutex(hMutex)  

§  Ví  dụ  §  Đặc  điểm  

§  Chậm  hơn  CRITICAL_SECTION  §  Có  thể  đồng  bộ  giữa  các  tiến  trình  

3.4  Mutex  

51  

Page 52: Lập Trình an toàn - Secure programming

§  Event  dùng  đồng  bộ  hoạt  động  của  các  luồng  thông  qua  cơ  chế  báo  hiệu.  

§  Sử  dụng  §  Khai  báo:    HANDLE  hEvent;  §  Khởi  tạo:    hMutex  =  CreateEvent(NULL,  TRUE,  FALSE,  “MyEvent”)  §  Sử  dụng  

 WaitForSingleObject(hEvent,  INFINITE)    //    …    SetEvent(hEvent)    //  Báo  hiệu  các  luồng  khác    ResetEvent(hEvent)  //  Chặn  các  luồng  khác    …    //    CloseHandle(hEvent)  

§  Ví  dụ  

3.5  Event  

52  

Page 53: Lập Trình an toàn - Secure programming

§  SRW  Lock  (Slim  Reader  Writer  Lock  )dùng  đồng  bộ  hoạt  động  của  các  luồng  thông  tương  tự  như  đoạn  găng  

§  Sử  dụng  §  Khai  báo:    SRWLOCK    lock;  §  Khởi  tạo:    InitializeSRWLock(&lock);  §  Sử  dụng  

 AcquireSRWLockShared(&lock)    AcquireSRWLockExclusive(&lock)    //    …    //    ReleaseSRWLockShared(&lock)    ReleaseSRWLockExclusive(&lock)  

§  Ví  dụ  

3.5  SRW  Lock  

53  

Page 54: Lập Trình an toàn - Secure programming

1.  Viết  chương  trình  chat  Client  và  Server  với  kênh  truyền  đã  mã  hóa    bằng  thuật  toán  AES-­‐256,  sử  dụng  thư  viện  OpenSSL  và  CryptoAPI.  Mật  khẩu  mã  hóa  là  :  123456.  Việc  mã  hóa  và  việc  nhận  dữ  liệu  được  thực  hiện  đồng  thời  trên  2  luồng  riêng  biệt,  sử  dụng  cơ  chế  đồng  bộ  CRITICAL_SECTION  

2.  Viết  chương  trình  mã  hóa  và  giải  mã  tệp  tin  theo  thuật  toán  AES-­‐256,  với  tên  nhập  từ  bàn  phím,  mật  khẩu  mã  hóa  là  :nopass.  Sử  dụng  thư  viện  OpenSSL  và  CryptoAPI  

Bài  tập  

54  

Page 55: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  4.  Mã  hóa  đối  xứng  Symmetric  Crytography  

Page 56: Lập Trình an toàn - Secure programming

4.1  Biểu  diễn  khóa  4.2  Chuyển  đổi  chuỗi  hexa  và  khóa  nhị  phân.  4.3  Mã  hóa  và  giải  mã  Base64    4.4  Các  phương  pháp  mã  hóa  đối  xứng  4.5  Mã  hóa  đối  xứng  với  OpenSSL  4.6  Mã  hóa  đối  xứng  với  Microsoft  Crypto  API  

Nội  dung  

56  

Page 57: Lập Trình an toàn - Secure programming

•  Khóa  đối  xứng:    Một  số  rất  lớn  sử  dụng  để  mã  hóa  và  giải  mã  thông  điệp.  

•  Biểu  diễn  khóa:  •  Phân  tách  thành  các  byte  và  lưu  dưới  dạng  một  mảng.  

unsigned  char    key[KEYLEN_BYTES]  •  Biểu  diễn  dưới  dạng  số  nguyên  lớn  nếu  khóa  có  chiều  dài  64-­‐bit  

long            long              key  •  Biểu  diễn  dưới  dạng  chuỗi  chữ  số  hexa  

 char  key[]=“AF12B5C7E0…”  •  Biểu  diễn  dưới  dạng  xâu  ASCII  (mật  khẩu).  

 char  key[]=“secret!!!”  •  Lưu  ý  về  tính  “endian”  của  máy  thực  hiện  mã  hóa.  

4.1  Biểu  diễn  khóa  

57  

Page 58: Lập Trình an toàn - Secure programming

•  Chuyển  đổi  khóa  nhị  phân  sang  dạng  chuỗi  chữ  số  hexa    #define  MAX_KEY_LEN  32    unsigned  char  key[MAX_KEY_LEN];    char    result[MAX_KEY_LEN*2+1];    for  (int  i=0;i<MAX_KEY_LEN;i++)      sprintf(result+i*2,"%2X",key[i]);    printf("Key:%s",result);  

 

4.2  Chuyển  đổi  chuỗi  hexa  và  khóa  nhị  phân    

58  

Page 59: Lập Trình an toàn - Secure programming

•  Chuyển  đổi  chuỗi  hexa  sang  khóa  nhị  phân  

 char  Hex2Dec(char  c)  {            if  (('a'<=c)&&(c<='z'))  return  c  -­‐  'a'+10;            if  (('A'<=c)&&(c<='Z'))  return  c  -­‐  'A'+10;            if  (('0'<=c)&&(c<='9'))  return  c  -­‐  '0';            return  -­‐1;  }  …  #define  MAX_KEY_LENGTH  32    char  hexa[]="AF125C4D8E";  unsigned  char  key[MAX_KEY_LENGTH];  int  keylen  =  strlen(hexa);  char  c1,c2;  if  ((keylen%2!=0)||(keylen/2  >    

   MAX_KEY_LENGTH))  printf("Invalid  key  length");  keylen  =  keylen/2;  for  (int  i=0;i<keylen;i++)  {  

 c1  =  Hex2Dec(hexa[i*2]);    c2  =  Hex2Dec(hexa[i*2+1]);    if  ((c1==-­‐1)||(c2==-­‐1))    {                      printf("Invalid  character  !!!");                      break;    };    key[i]  =  (c1<<4)|c2;  

};    

4.2  Chuyển  đổi  chuỗi  hexa  và  khóa  nhị  phân    

59  

Page 60: Lập Trình an toàn - Secure programming

•  Mã  hóa  Base64      •  Sử  dụng  6-­‐bit  để  mã  hóa  dữ  liệu  và  biểu  diễn  dưới  dạng  các  chữ  cái  ASCII.  •  Cứ  3  byte  dữ  liệu  vào  sẽ  được  biểu  diễn  thành  4  byte  dữ  liệu  ra.  •  Các  ký  tự  ra  nằm  trong  khoảng:    

•  ‘A’  –  ‘Z’  tương  đương  các  giá  trị  của  từ  mã  từ  0-­‐25.  •  ‘a’  –  ‘z’  tương  đương  các  giá  trị  của  từ  mã  từ  26-­‐51.  •  ‘0’-­‐  ‘9’  tương  đương  các  giá  trị  từ  mã  từ  52-­‐61.  •  ‘+’  ,  ‘-­‐’  tương  ứng  với  các  giá  trị  mã  62,63.  

•  Nếu  dữ  liệu  vào  có  kích  thước  không  chia  hết  cho  3  sẽ  thì  được  thêm  vào  bằng  ký  tự  ‘=‘.  

•  VD    Dữ  liệu  gốc:  ‘A’  –  0100.0001    Dữ  liệu  mã  hóa  dạng  Base64:  010000.010000.000000.000000  ~  QQ==    Dữ  liệu  gốc:  ‘AA’  –  0100.0001.0100.0001    Dữ  liệu  mã  hóa  dạng  Base64:  010000.010100.000100.000000  ~  QUE=    Dữ  liệu  gốc:  ‘AAA’  –  0100.0001.0100.0001.0100.0001    Dữ  liệu  dạng  mã  hóa  Base64:  010000.010100.000101.000001  ~  QUFB                        

4.3  Mã  hóa  và  giải  mã  Base64  

60  

Page 61: Lập Trình an toàn - Secure programming

•  Mã  hóa  Base64                          

4.3  Mã  hóa  và  giải  mã  Base64  

61  

Value   Char  

   

Value   Char  

   

Value   Char  

   

Value   Char  

0   A   16   Q   32   g   48   w  

1   B   17   R   33   h   49   x  

2   C   18   S   34   i   50   y  

3   D   19   T   35   j   51   z  

4   E   20   U   36   k   52   0  

5   F   21   V   37   l   53   1  

6   G   22   W   38   m   54   2  

7   H   23   X   39   n   55   3  

8   I   24   Y   40   o   56   4  

9   J   25   Z   41   p   57   5  

10   K   26   a   42   q   58   6  

11   L   27   b   43   r   59   7  

12   M   28   c   44   s   60   8  

13   N   29   d   45   t   61   9  

14   O   30   e   46   u   62   +  

15   P   31   f   47   v   63   /  

Page 62: Lập Trình an toàn - Secure programming

•  Đoạn  chương  trình  mã  hóa  Base64:    P4.5  –  Secure  C  Programming  Cookbook  

•  Đoạn  chương  trình  giải  mã  Base64:  P4.6  –  Secure  C  Programming  Cookbook  

4.3  Mã  hóa  và  giải  mã  Base64  

62  

Page 63: Lập Trình an toàn - Secure programming

•  Mã  hóa  đối  xứng:  Sử  dụng  chung  một  khóa  cho  mã  hóa  và  giải  mã  •  Có  hai  loại:  Mã  khối  và  mã  dòng  •  Có  nhiều  chế  độ  mã  hóa:  ECB,  CBC,  CFB,  OFB,  CTR,  CWC…    •  Có  nhiều  giải  thuật:    

4.4  Các  phương  pháp  mã  hóa  đối  xứng  

63  

Cipher   Key  size   Speed[4]   Implementation   Notes  

AES   128  bits[5]  14.1  cpb  in  asm,  22.6  cpb  in  C  

Brian  Gladman's[6]  The  assembly  version  currently  works  only  on  Windows.  

AES   128  bits   41.3  cpb   OpenSSL  

Triple  DES   192  bits[7]   108.2  cpb   OpenSSL  

SNOW  2.0   128  or  256  bits   6.4  cpb  Fast  reference  implementation[8]  

This  implementation  is  written  in  C.  

RC4  Up  to  256  bits  (usually  128  bits)  

10.7  cpb   OpenSSL  

Serpent   128,  192,  or  256  bits   35.6  cpb  Fast  reference  implementation  

It  gets  a  lot  faster  on  64-­‐bit  platforms  and  is  at  least  as  fast  as  AES  in  hardware.  

Blowfish  Up  to  256  bits  (usually  128  bits)  

23.2  cpb   OpenSSL  

Page 64: Lập Trình an toàn - Secure programming

•  Thư  viện  OpenSSL:  Thư  viện  mã  nguồn  mở,  mạnh  mẽ  và  dễ  sử  dụng.  •  OpenSSL  hỗ  trợ:  

•  Nhiều  thuật  toán  mã  hóa:  AES,  DES  ,  3DES,  Blow}ish,  CAST,  Idea,  RC2,  RC5.  •  Nhiều  chế  độ  mã  hóa:  ECB,  CBC,  CFB,  OFB,  CTR…  •  Mã  hóa  dòng:  RC4.  •  Các  giải  thuật  băm:  MD2,  MD4,  MD5,SHA-­‐1,SHA-­‐224,SHA-­‐256…  •  MAC:  HMAC.  MDC2  •  Các  giải  thuật  mã  hóa  công  khai:  DH,  DSA,  RSA,  ECC  

•  Sử  dụng  thư  viện:  •  Trên  Unix/Linux:  Tải  source  về  và  biên  dịch.  Kết  quả  là  }ile    libcrypto.[so/a],  libssl.[so/a]  và  các  }ile  .h  để  include  vào  chương  trình.  

•  Trên  Windows:  Tải  bản  binary  đã  biên  dịch  sẵn:  libeay32.dll,  ssleay32.dll,  tệp  tiêu  đề  (.h)  và  tệp  thư  viện  (.lib).  Link  http://www.ie7pro.com/openssl.html  

 

4.5  Mã  hóa  đối  xứng  với  OpenSSL  

64  

Page 65: Lập Trình an toàn - Secure programming

•  Giao  diện  OpenSSL  EVP  •  Là  API  mức  cao  của  OpenSSL,  cho  phép  truy  nhập  đến  các  thuật  toán  ở  mức  thấp  một  cách  tập  trung,  dễ  dàng.  

•  Tệp  tiêu  đề  <openssl/evp.h>.  •  Tệp  thư  viện:  libeay32.lib,  ssleay32.lib  

•  Mã  hóa  AES  với  OpenSSL  EVP.  •  Khởi  tạo  khóa,  vector  khởi  tạo,  salt  với  EVP_BytesToKey  hoặc  tự  chọn  một  bộ  Key,  IV  nào  đó.  

•  Khởi  tạo  ngữ  cảnh  mã  hóa  với  hàm  EVP_EncryptInit_ex.  •  Khởi  tạo  ngữ  cảnh  giải  mã  với  hàm  EVP_DecryptInit_ex.  •  Mã  hóa  dữ  liệu  bằng  việc  liên  tục  gọi  hàm  EVP_EncryptUpdate,  kết  thúc  quá  trình  mã  hóa  bằng  hàm  EVP_EncryptFinal_ex.  

•  Giải  mã  dữ  liệu  bằng  việc  liên  tục  gọi  hàm  EVP_DecryptUpdate,  kết  thúc  quá  trình  giải  mã  bằng  hàm  EVP_DecryptFinal_ex.  

4.5  Mã  hóa  đối  xứng  với  OpenSSL  

65  

Page 66: Lập Trình an toàn - Secure programming

•  VD  •  Sinh  key  và  iv  bằng  hàm  EVP_BytesToKey  

char          key[32];  char          iv[32];      char  *  key_data  =  “nopass”;    unsigned  int  salt[]  =  {12345,  54321};  EVP_BytesToKey(EVP_aes_256_cbc(),  EVP_sha1(),  salt,  key_data,  6,  1,  key,  iv);  

•  Khởi  tạo  ngữ  cảnh  mã  hóa  với  key  và  iv  đã  chọn  EVP_CIPHER_CTX  e_ctx;  EVP_CIPHER_CTX_init(&e_ctx);  EVP_EncryptInit_ex(&e_ctx,  EVP_aes_256_cbc(),NULL,  key,  iv);  

•  Khởi  tạo  ngữ  cảnh  giải  mã  với  key  và  iv  đã  chọn  EVP_CIPHER_CTX  d_ctx;  EVP_CIPHER_CTX_init(&d_ctx);  EVP_DecryptInit_ex(&d_ctx,  EVP_aes_256_cbc(),NULL,  key,  iv);  

4.5  Mã  hóa  đối  xứng  với  OpenSSL  

66  

Page 67: Lập Trình an toàn - Secure programming

•  VD  (tiếp)  •  Mã  hóa  với  ngữ  cảnh  đã  được  khởi  tạo  

char  *    plaintext=“Hello”;  int  len  =  strlen(plaintext);  char  ciphertext[1024];  int    c_len  =  0,  f_len  =  0;  /*  Gọi  lại  hàm  này  để  cho  phép  OpenSSL  sử  dụng  lại  ngữ  cảnh  phiên  mã    hóa  trước  */  EVP_EncryptInit_ex(e,  NULL,  NULL,  NULL,  NULL);  …  //  Mỗi  chu  kỳ  Update,  c_len  sẽ  chứa  số  byte  của  xâu  mã  được  EVP_EncryptUpdate(e,  ciphertext,  &c_len,  plaintext,  len);  …  //  Cuối  chu  kỳ  Update,  f_len  sẽ  chưa  số  byte  còn  lại  của  xâu  mã  EVP_EncryptFinal_ex(e,  ciphertext+c_len,  &f_len);  …  

4.5  Mã  hóa  đối  xứng  với  OpenSSL  

67  

Page 68: Lập Trình an toàn - Secure programming

•  VD  (tiếp)  •  Giải  mã  với  ngữ  cảnh  đã  được  khởi  tạo  

 char  plaintext[1024];  int  p_len  =  0;  /*  Gọi  lại  hàm  này  để  cho  phép  OpenSSL  sử  dụng  lại  ngữ  cảnh  phiên  giãi  mã    hóa  trước  */  EVP_DecryptInit_ex(e,  NULL,  NULL,  NULL,  NULL);  …  //  Giải  mã  với  ciphertext  và  len  được  cung  cấp  trước  EVP_DecryptUpdate(e,  plaintext,  &p_len,  ciphertext,  *len);  …  //  Kết  thúc  quá  trình  giải  mã,  cập  nhật  dữ  liệu  còn  lại  vào  plaintext.  EVP_DecryptFinal_ex(e,  plaintext+p_len,  &f_len);  

4.5  Mã  hóa  đối  xứng  với  OpenSSL  

68  

Page 69: Lập Trình an toàn - Secure programming

•  Thư  viện  CryptoAPI  •  Cung  cấp  các  hàm  mật  mã  học  cơ  bản  thông  qua  các  Cryptographic  Service  Providers  (CSP).    •  Microsoft  Base  Cryptographic  Service  Provider:  RC2,  RC4,  DES  •  Microsoft  Enhanced  Cryptographic  Service  Provider:  Triple-­‐DES  •  Microsoft  AES  Cryptographic  Service  Provider:  AES  •  …  

•  Cung  cấp  các  hàm  mã  hóa  và  giải  mã  chứng  thư  số,  và  đồng  thời  bổ  sung  các  hàm  băm.  

•  Cung  cấp  các  hàm  quản  lý  và  lưu  trữ  chứng  thư  số.  •  Các  hàm  mã  thông  điệp  hóa  mức  cao  (Simpli}ied  Message  Functions).  •  Các  hàm  mã  hóa  thông  điệp  mức  thấp  (Low-­‐Level  Message  Functions).  

 

4.6  Microsoft  Crypto  API  

69  

Page 70: Lập Trình an toàn - Secure programming

•  Thư  viện  CryptoAPI    

4.6  Microsoft  Crypto  API  

70  

Page 71: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Tệp  tiêu  đề  wincript.h  •  Thư  viện  Crypt32.lib  •  Trình  tự  sử  dụng          

4.6  Microsoft  Crypto  API  

71  

Khởi  tạo  Provider  

Tạo  khóa  • Ngẫu  nhiên  • Từ  mật  khẩu  • Từ  bên  ngoài  

Đặt  chế  độ  mã  • CBC  • ECB  • …  

Thiết  lập  vector  khởi  tạo  

Thực  hiện  Mã  hóa/Giải  mã  

Page 72: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Khởi  tạo  ngữ  cảnh  Provider  thông  qua  hàm  CryptAcquireContext  

 BOOL  WINAPI  CryptAcquireContext(__out  HCRYPTPROV*  phProv,            __in  LPCTSTR  pszContainer,            __in  LPCTSTR  pszProvider,            __in  DWORD  dwProvType,            __in  DWORD  dwFlags  );  VD:  HCRYPTPROV    hProvider;  if  (!CryptAcquireContext(&hProvider,            0,            MS_ENH_RSA_AES_PROV,            PROV_RSA_AES,                                                        CRYPT_VERIFYCONTEXT))        return  0;      

4.6  Microsoft  Crypto  API  

72  

Page 73: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Sử  dụng  Key  thông  qua  một  trong  ba  hàm.  Kết  quả  trả  về  là  đối  tượng  HCRYPTKEY  •  CryptGenKey(  ):  Sinh  khóa  ngẫu  nhiên.  •  CryptDeriveKey(  ):  Sinh  khóa  từ  mật  khẩu.  •  CryptImportKey(  )  :  Sinh  khóa  từ  một  đối  tượng  trong  bộ  nhớ.  

 VD1.  Sinh  khóa  ngẫu  nhiên    DWORD  dwFlags;    HCRYPTKEY  hKey;    DWORD  dwSize  =  256;    dwFlags  =  ((dwSize  <<  16)  &  0xFFFF0000)  |  CRYPT_EXPORTABLE;    if  (!CryptGenKey(hProvider,  CALG_AES_256,  dwFlags,  &hKey))  return  0;        

4.6  Microsoft  Crypto  API  

73  

Page 74: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  VD2.  Sinh  khóa  từ  mật  khẩu:  Cần  phải  băm  mật  khẩu  và  truyền  vào  hàm  CryptDeriveKey  char    *  password  =  “nopass”;      BOOL  bResult;    DWORD  cbData;    HCRYPTKEY  hKey;      //  Lưu  Key  HCRYPTHASH  hHash;    //  Lưu  giá  trị  băm  của  mật  khẩu  if  (!CryptCreateHash(hProvider,  CALG_SHA1,  0,  0,  &hHash))  //  Khởi  tạo  hàm  băm  

 return  0;    cbData  =  lstrlen(password)  *  sizeof(TCHAR);    if  (!CryptHashData(hHash,  (BYTE  *)password,  cbData,  0))    //  Băm  mật  khẩu  

 {        CryptDestroyHash(hHash);        return  0;      }  

//  Tạo  key  từ  giá  trị  băm  của  mật  khẩu  bResult  =  CryptDeriveKey(hProvider,  CALG_AES_256,  hHash,  CRYPT_EXPORTABLE,  &hKey);    CryptDestroyHash(hHash);    

4.6  Microsoft  Crypto  API  

74  

Page 75: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Thiết  lập  chế  độ  mã  hóa  CBC  với  hàm  CryptSetKeyParam  

 DWORD  dwMode  =  CRYPT_MODE_CBC;    CryptSetKeyParam(hKey,  KP_MODE,  (BYTE  *)&dwMode,  0);  

•  Sinh  ngẫu  nhiên  vector  khởi  tạo  (IV)  BOOL  bResult;        //  Lưu  kết  quả  BYTE  *pbTemp;      //  Lưu  vector  khởi  tạo  DWORD  dwBlockLen,  dwDataLen;    dwDataLen  =  sizeof(dwBlockLen);  //  Lấy  kích  thước  block  của  thuật  toán  mã  hóa    if  (!CryptGetKeyParam(hKey,  KP_BLOCKLEN,  (BYTE  *)&dwBlockLen,  &dwDataLen,  0))  return  0;  dwBlockLen  /=  8;    if  (!(pbTemp  =  (BYTE  *)LocalAlloc(LMEM_FIXED,  dwBlockLen)))    return  FALSE;  //  Sinh  ngẫu  nhiên  IV    bResult  =  CryptGenRandom(hProvider,  dwBlockLen,  pbTemp);  //  Thiết  lập  IV  bResult  =  CryptSetKeyParam(hKey,  KP_IV,  pbTemp,  0);    LocalFree(pbTemp);    

4.6  Microsoft  Crypto  API  

75  

Page 76: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Mã  hóa  với  CryptEncrypt  

•  Với  các  giải  thuật  mã  hóa  dòng  thì  kích  thước  dữ  liệu  ra  =  kích  thước  dữ  liệu  vào.  •  Với  các  giải  thuật  mã  hóa  khối  thì  kích  thước  dữ  liệu  ra  <=    kích  thước  dữ  liệu  vào  

+  kích  thước  khối.  •  Hàm  CryptEncrypt  sẽ  ghi  đè  dữ  liệu  mã  hóa  được  vào  bộ  đệm  chứa  dữ  liệu  vào.  •  Đoạn  chương  trình  thực  hiện  mã  hóa  chung  cho  cả  hai  loại.  

4.6  Microsoft  Crypto  API  

76  

ALG_ID  Algid;      //  Giải  thuật  mã  char  *  pbData  =  "Hello  CryptAPI";    //  Xâu  nguồn  cần  mã  char  *  pbResult  =  0;    //  Xâu  kết  quả  DWORD  dwDataLen  =  0,dwBlockLen  =  0;  

 cbData  =  strlen(pbData);  //  Chiều  dài  xâu  nguồn      dwDataLen  =  sizeof(ALG_ID);  //  Lấy  thông  tin  về  giải  thuật  mã  hóa  với  key  cho  trước      if  (!CryptGetKeyParam(hKey,  KP_ALGID,  (BYTE  *)&Algid,  &dwDataLen,  0))    

 return  0;    

Page 77: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Mã  hóa  với  CryptEncrypt    

4.6  Microsoft  Crypto  API  

77  

if  (GET_ALG_TYPE(Algid)  !=  ALG_TYPE_STREAM)    //  Mã  hóa  khối      {            dwDataLen  =  sizeof(DWORD);                ret  =  CryptGetKeyParam(hKey,    KP_BLOCKLEN,  (BYTE*)&dwBlockLen,    

     &dwDataLen,  0);  //  Lấy  kích  thước  block  theo  bit    dwBlockLen  =  dwBlockLen/8;  //  Đổi  kích  thước  block  ra  đơn  vị  byte      //  Cấp  phát  bộ  nhớ  để  chứa  kết  quả        pbResult  =  (char*)malloc(cbData+dwBlockLen);    memcpy(pbResult,pbData,cbData);    //  Thực  hiện  mã  hóa,  kết  quả  là  dwDataLen  byte  lưu  trong  pbResult    dwDataLen  =  cbData;      CryptEncrypt(hKey,  0,  TRUE,  0,  (BYTE*)pbResult,  &dwDataLen,          cbData+16))  ;  

}  

Page 78: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Mã  hóa  với  CryptEncrypt  (tiếp)    

4.6  Microsoft  Crypto  API  

78  

else  //  Mã  hóa  dòng  {  

 //  Cấp  phát  bộ  nhớ  lưu  kết  quả    pbResult  =  (char*)malloc(cbData);    //  Bảo  toàn  dữ  liệu  nguồn    memcpy(pbResult,pbData,cbData);    //  Thực  hiện  mã  hóa    CryptEncrypt(hKey,0,TRUE,0,pbResult,&dwDataLen,cbData);  

 }  

Page 79: Lập Trình an toàn - Secure programming

•  Sử  dụng  thư  viện  CryptoAPI  để  thực  hiện  mã  hóa  đối  xứng  thông  điệp  với  thuật  toán  AES.  •  Giải  mã  với  CryptDecrypt  

•  Kích  thước  dữ  liệu  đích  <=  kích  thước  dữ  liệu  nguồn  •  Thực  hiện  đơn  giản  hơn  so  với  CryptEncrypt  •  Ví  dụ  

 

4.6  Microsoft  Crypto  API  

79  

char  *  pbData  ;      //  Dữ  liệu  nguồn  DWORD  cbData;    //  Kích  thước  nguồn  char  *  pbResult;      //  Dữ  liệu  đích  DWORD  dwDataLen;  //  Kích  thước  đích  …  //  Cấp  phát  bộ  nhớ  và  sao  chép  dữ  liệu  nguồn  vào  đích  pbResult  =  (char*)malloc(cbData);  memcpy(pbResult,  pbData,  cbData);  dwDataLen  =  cbDataLen;  //  Giải  mã,  kết  quả  là  dwDataLen  byte  lưu  trong  pbResult  CryptDecrypt(hKey,0,TRUE,0,pbResult,&dwDataLen);  

Page 80: Lập Trình an toàn - Secure programming

•  Trao  đổi  khóa  với  OpenSSL  •  CryptoAPI  không  cho  phép  nhập  và  xuất  khóa  dạng  thô  như  OpenSSL.  •  Để  trao  đổi  khóa  với  thư  viện  khác,  cần  mã  hóa  khóa  theo  giải  thuật  AT_KEYEXCHANGE,  và  thực  hiện  nhập  xuất  dưới  dạng  cấu  trúc  BLOB.  

•  Hàm  CryptImportKeyvà  CryptExportKey  dùng  để  thực  hiện  nhập  xuất  khóa.  

•  Xem  thêm  phần  5.26,  5.27  trong  Secure  Programming  Cookbook.    

4.6  Microsoft  Crypto  API  

80  

Page 81: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  5.  Hàm  băm  và  xác  thực  thông  điệp  

Hashes  and  Message  Authentication  

Page 82: Lập Trình an toàn - Secure programming

5.1  Các  loại  hàm  băm  và  MAC  thông  dụng  5.2  Băm  với  OpenSSL    5.3  Băm  dữ  liệu  với  CryptoAPI    5.4  Xác  thực  thông  điệp  với  HMAC  5.5  Salt  

Nội  dung  

82  

Page 83: Lập Trình an toàn - Secure programming

•  Hàm  băm  (hashes)  –  Nhận  đầu  vào  là  một  xâu  và  đầu  ra  là  một  chuỗi  bit  có  chiều  dài  xác  định.  

–  Tỉ  lệ  đụng  độ  rất  nhỏ.    –  Dùng  để  kiểm  tra  tính  toàn  vẹn  của  dữ  liệu  nhưng  không  đảm  bảo  tính  xác  thực  của  dữ  liệu.  

–  Thường  kết  hợp  với  mô  hình  mã  hóa  công  khai  chứ  không  sử  dụng  một  mình.  

–  Các  giải  thuật  băm  thông  dụng:  MD5,  SHA1  

5.1  Các  hàm  băm  và  MAC  thông  dụng  

83  

Page 84: Lập Trình an toàn - Secure programming

•  Hàm  băm  (hashes)  

5.1  Các  hàm  băm  và  MAC  thông  dụng  

84  

Algorithm   Digest  size   Security  conqidence  Small  message  

speed  (64  bytes),  in  cycles  per  byte[2]  

Large  message  speed  (8K),  in  cycles  per  byte  

Uses  block  cipher  

Davies-­‐Meyer-­‐AES-­‐128  

128  bits  (same  length  as  cipher  block  size)  

Good   46.7  cpb   57.8  cpb   Yes  

MD2   128  bits   Good  to  low   392  cpb   184  cpb   No  

MD4   128  bits   Insecure   32  cpb   5.8  cpb   No  

MD5   128  bits  Very  low,  may  be  insecure  

40.9  cpb   7.7  cpb   No  

MDC-­‐2-­‐AES-­‐128   256  bits   Very  high   93  cpb   116  cpb   Yes  

MDC-­‐2-­‐DES   128  bits   Good   444  cpb   444  cpb   Yes  

RIPEMD-­‐160   160  bits   High   62.2  cpb   20.6  cpb   No  

SHA1   160  bits   High   53  cpb   15.9  cpb   No  

SHA-­‐256   256  bits   Very  high   119  cpb   116  cpb   No  

SHA-­‐384   384  bits   Very  high   171  cpb   166  cpb   No  

SHA-­‐512   512  bits   Very  high   171  cpb   166  cpb   No  

Page 85: Lập Trình an toàn - Secure programming

•  Xác  thực  thông  điệp  (Message  Authentication  Code)  –  Nhận  đầu  vào  là  một  xâu  và  một  khóa  bí  mật,  đầu  ra  là  một  mã  có  chiều  dài  xác  định.  

–  Dùng  để  kiểm  tra  tính  toàn  vẹn  và  xác  thực  của  dữ  liệu.  –  Các  giải  thuật  thông  dụng:  OMAC,  CMAC,  HMAC  

5.1  Các  hàm  băm  và  MAC  thông  dụng  

85  

Page 86: Lập Trình an toàn - Secure programming

•  Xác  thực  thông  điệp  (Message  Authentication  Code)  

5.1  Các  hàm  băm  và  MAC  thông  dụng  

86  

MAC   Built  upon  Small  message  speed  (64  bytes)[4]  

Large  message  speed  (8K)  

Appropriate  for  hardware  

Patent  restric-­‐tions   Parallel-­‐izable  

CMAC  A  universal  hash  and  AES   ~18  cpb   ~18  cpb   Yes   No   Yes  

HMAC-­‐SHA1  Message  digest  function   90  cpb   20  cpb   Yes   No   No  

MAC127   hash127  +  AES   ~6  cpb   ~6  cpb   Yes   No   Yes  

OMAC1   AES   29.5  cpb   37  cpb   Yes   No   No  

OMAC2   AES   29.5  cpb   37  cpb   Yes   No   No  

PMAC-­‐AES   Block  cipher   72  cpb   70  cpb   Yes   Yes   Yes  

RMAC   Block  cipher   89  cpb   80  cpb   Yes   No   No  

UMAC32   UHASH  and  AES   19  cpb   cpb   No   No   Yes  

XMACC-­‐SHA1  Any  cipher  or  MD  function   162  cpb   29  cpb   Yes   Yes   Yes  

Page 87: Lập Trình an toàn - Secure programming

•  OpenSSL  cung  cấp  hai  loại  giao  diện  với  các  hàm  băm  –  Giao  diện  riêng  rẽ  với  mỗi  giải  thuật  băm  cụ  thể.  

•  Mỗi  giải  thuật  băm  có  tệp  tiêu  đề  riêng  •  Tên  gọi  các  hàm  là  khác  nhau  cho  các  giải  thuật  băm.  

–  Giao  diện  chung  EVP  cho  mọi  loại  hàm  băm.  •  Tệp  tiêu  đề  chung:  <openssl/evp.h>  •  Trình  tự  sử  dụng  như  nhau:  

–  Khởi  tạo  ngữ  cảnh:  EVP_DigestInit  –  Cập  nhật  dữ  liệu  băm:  EVP_DigestUpdate  –  Lấy  kết  quả:  EVP_DigestFinal.  

5.2  Băm  dữ  liệu  với  OpenSSL  

87  

Page 88: Lập Trình an toàn - Secure programming

•  VD:  Băm  với  SHA1  5.2  Băm  dữ  liệu  với  OpenSSL  

88  

 #include  <openssl/sha.h>    int                      i;    SHA_CTX              ctx;          unsigned  char  result[SHA_DIGEST_LENGTH];    /*  SHA1  has  a  20-­‐byte  digest.  */      unsigned  char  *s1  =  (unsigned  char*)"Testing";          unsigned  char  *s2  =  (unsigned  char*)"...1...2...3...";              SHA1_Init(&ctx);          SHA1_Update(&ctx,  s1,  strlen((char*)s1));      SHA1_Update(&ctx,  s2,  strlen((char*)s2));      /*  Yes,  the  context  object  is  last.  */      SHA1_Final(result,  &ctx);      printf("SHA1(\"%s%s\")  =  ",  s1,  s2);          for  (i  =  0;    i  <  SHA_DIGEST_LENGTH;    i++)  printf("%02x",  result[i]);      printf("\n");  

Page 89: Lập Trình an toàn - Secure programming

•  VD:  Băm  với  giao  diện  EVP  5.2  Băm  dữ  liệu  với  OpenSSL  

89  

#include  <openssl/evp.h>  #include  <stdio.h>  #include  <string.h>      int                      i  ,  ol;      EVP_MD_CTX        ctx;      unsigned  char  *result;      unsigned  char  *s1  =  (unsigned  char*)"Testing";      unsigned  char  *s2  =  (unsigned  char*)"...1...2...3...";      EVP_DigestInit(&ctx,  EVP_sha1());      EVP_DigestUpdate(&ctx,  s1,  strlen((char*)s1));      EVP_DigestUpdate(&ctx,  s2,  strlen((char*)s2));      if  (!(result  =  (unsigned  char  *)malloc(EVP_MD_CTX_block_size(&ctx))))abort();      EVP_DigestFinal(&ctx,  result,  &ol);      printf("SHA1(\"%s%s\")  =  ",  s1,  s2);      for  (i  =  0;    i  <  ol;    i++)  printf("%02x",  result[i]);      printf("\n");        free(result);  

Page 90: Lập Trình an toàn - Secure programming

•  Trình  tự  băm  với  CryptoAPI  –  Tệp  tiêu  đề:  Wincrypt.h  –  Khởi  tạo  ngữ  cảnh  Provider:  CryptAcquireContext  –  Tạo  đối  tượng  hash:  CryptCreateHash  –  Băm  liên  tiếp  với:  CryptHashData  –  Lấy  kết  quả:  CryptGetHashParam  –  Giải  phóng  đói  tượng  hash:  CryptDestroyHash  

5.3  Băm  dữ  liệu  với  CryptoAPI  

90  

Page 91: Lập Trình an toàn - Secure programming

•  Ví  dụ:  Băm  dữ  liệu  với  thuật  toán  SHA-­‐256  

5.3  Băm  dữ  liệu  với  CryptoAPI  

91  

   BYTE                    *pbData;      DWORD                  cbData  =  sizeof(DWORD),  cbHashSize,  i;      HCRYPTHASH        hSHA256;      HCRYPTPROV        hProvider;      unsigned  char  *s1  =  (unsigned  char*)"Testing";      unsigned  char  *s2  =  (unsigned  char*)"...1...2...3...";      //  Khởi  tạo  ngữ  cảnh  Provider      CryptAcquireContext(&hProvider,  0,  MS_ENH_RSA_AES_PROV,  PROV_RSA_AES,  0);      //  Tạo  đối  tượng  hàm  băm      CryptCreateHash(hProvider,  CALG_SHA_256,  0,  0,  &hSHA256);      //  Thực  hiện  băm      CryptHashData(hSHA256,  s1,  strlen((char*)s1),  0);      CryptHashData(hSHA256,  s2,  strlen((char*)s2),  0);    //  Thực  hiện  băm…        

Page 92: Lập Trình an toàn - Secure programming

•  Ví  dụ:  Băm  dữ  liệu  với  thuật  toán  SHA-­‐256  (tiếp)  

5.3  Băm  dữ  liệu  với  CryptoAPI  

92  

   //  Lấy  kích  thước  dữ  liệu  băm  được      CryptGetHashParam(hSHA256,  HP_HASHSIZE,  (BYTE  *)&cbHashSize,  &cbData,  0);      pbData  =  (BYTE  *)LocalAlloc(LMEM_FIXED,  cbHashSize);      //  Lấy  dữ  liệu  băm  được      CryptGetHashParam(hSHA256,  HP_HASHVAL,  pbData,  &cbHashSize,  0);      //  Giải  phóng  đối  tượng  băm  và  ngữ  cảnh  Provider      CryptDestroyHash(hSHA256);      CryptReleaseContext(hProvider,  0);              printf("SHA256(\"%s%s\")  =  ",  s1,  s2);      for  (i  =  0;    i  <  cbHashSize;    i++)  printf("%02x",  pbData[i]);      printf("\n");              LocalFree(pbData);            

Page 93: Lập Trình an toàn - Secure programming

•  Với  OpenSSL  –  Tệp  tiêu  đều  <openssl/hmac.h>  –  Gọi  hàm  HMAC_Init  để  khởi  tạo  ngữ  cảnh  và  key  sẽ  sử  dụng  –  Liên  tục  gọi  hàm  HMAC_Update  để  cập  nhật  dữ  liệu.  –  Gọi  hàm  HMAC_Final  để  kết  thúc  quá  trình  băm  –  Gọi  hàm  HMAC_cleanup  để  xóa  key  khỏi  bộ  nhớ.  –  Có  thể  gọi  hàm  All-­‐in-­‐one  HMAC  –  Bên  nhận  kiểm  tra  lại  bằng  cách  thực  hiện  băm  với  với  cùng  một  key  và  giải  thuật  và  so  sánh  kết  quả  

5.4  Xác  thực  thông  điệp  với  HMAC  

93  

Page 94: Lập Trình an toàn - Secure programming

•  Với  OpenSSL  

5.4  Xác  thực  thông  điệp  với  HMAC  

94  

   int                      i;      HMAC_CTX            ctx;      unsigned  int    len;      unsigned  char  out[20];      unsigned  char  *  key  =  (unsigned  char*)"secret";      int      keylen  =  strlen((char*)key);      //  Khởi  tạo  HMAC  với  key  là  secret      HMAC_Init(&ctx,  key,  keylen,  EVP_sha1(    ));      //  Thực  hiện  băm  xâu  "fr      HMAC_Update(&ctx,  (unsigned  char*)"hash  me  pls",  11);      //  Lấy  kết  quả      HMAC_Final(&ctx,  out,  &len);      for  (i  =  0;    i  <  len;    i++)  printf("%02x",  out[i]);      printf("\n");  

Page 95: Lập Trình an toàn - Secure programming

•  Với  CryptAPI  –  Tạo  đối  tượng  Hash  với  hàm  CryptCreateHash,  trong  đó  tham  số  hKey  là  một  key  đã  được  tạo  trước.  

–  Thiết  lập  thông  tin  về  giải  thuật  băm  với  hàm  CryptSetHashParam.  –  Thực  hiện  băm  với  hàm  CryptHashData  –  Lấy  kích  thước,  nội  của  dữ  liệu  băm  được  với  hàm  CryptGetHashParam.  

–  Giải  phóng  đói  tượng  Hash  và  Key    

5.4  Xác  thực  thông  điệp  với  HMAC  

95  

Page 96: Lập Trình an toàn - Secure programming

•  Với  CryptAPI    

5.4  Xác  thực  thông  điệp  với  HMAC  

96  

   BYTE              out[20];      DWORD            cbData  =  sizeof(out),  i;      HCRYPTKEY    hKey;      HMAC_INFO    HMACInfo;      HCRYPTHASH  hHash;      HCRYPTPROV  hProvider;      //  Lấy  ngữ  cảnh  provider    CryptAcquireContext(&hProvider,0,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,CRYPT_VERIFYCONTEXT);      //  Sinh  key  từ  mật  khẩu                  hKey  =  CreateKeyFromPassword(hProvider,"secret");      //  Tạo  đối  tượng  băm      CryptCreateHash(hProvider,  CALG_HMAC,  hKey,  0,  &hHash);        

Page 97: Lập Trình an toàn - Secure programming

•  Với  CryptAPI    

5.4  Xác  thực  thông  điệp  với  HMAC  

97  

//  Thiết  lập  giải  thuật  băm      HMACInfo.HashAlgid          =  CALG_SHA1;      HMACInfo.pbInnerString  =  HMACInfo.pbOuterString  =  0;      HMACInfo.cbInnerString  =  HMACInfo.cbOuterString  =  0;      CryptSetHashParam(hHash,  HP_HMAC_INFO,  (BYTE  *)&HMACInfo,  0);      //  Thực  hiện  băm        CryptHashData(hHash,  (BYTE  *)"Hash  me  plz",  11,  0);      //  Lấy  kết  quả      CryptGetHashParam(hHash,  HP_HASHVAL,  out,  &cbData,  0);      for  (i  =  0;    i  <  cbData;    i++)  printf("%02x",  out[i]);      printf("\n");              CryptDestroyHash(hHash);      CryptDestroyKey(hKey);      CryptReleaseContext(hProvider,  0);        

Page 98: Lập Trình an toàn - Secure programming

•  Salt  –  Chuỗi  dữ  liệu  thêm  vào  để  tăng  không  gian  khóa  và  chống  lại  hình  thức  replay-­‐attack.  

–  Hai  bên  có  thể  thỏa  thuận  chung  một  salt  nào  đó  thay  đổi  theo  thời  gian.  

–  Salt  thường  được  thêm  vào  đầu  thông  điệp  gốc,  sau  đó  thực  hiện  băm  cả  salt  cả  thông  điệp.  

 

5.5  Sử  dụng  Salt  

98  

Page 99: Lập Trình an toàn - Secure programming

1.  Viết  chương  trình  mã  hóa  và  giải  mã  tệp  tin  bằng  giải  thuật  AES-­‐256  bit.  Mật  khẩu  nhập  từ  bàn  phím.  Kiểm  tra  tính  đúng  đắn  của  kết  quả  bằng  giải  thuật  SHA-­‐256.  Sử  dụng  thư  viện  OpenSSL.  Khuôn  dạng  dữ  liệu  của  tệp  tin  sau  khi  mã  hóa  có  thể  như  sau:  

 <Kích  thước><Nội  dung  tệp  tin  đã  mã><Giá  trị  băm  SHA-­‐256>    2.  Viết  chương  trình  chat  client-­‐server  đơn  giản  trong  đó  kênh  truyền  được  mã  hóa  theo  giải  thuật  AES-­‐256.  Key  được  sinh  ra  từ  mật  khẩu  thỏa  thuận  trước  và  không  truyền  qua  mạng,  Vector  khởi  tạo  là  mã  BCD  được  thiết  lập  từ  ngày  và  giờ  hiện  tại  của  hệ  thống  (Hàm  API  GetSystemTime).  Ví  dụ:  Nếu  hiện  tại  là  07h  ngày  10/10/2011  thì  giá  trị  dưới  dạng  hexa  của  vector  khởi  tạo  là  

2011101007000….00    

Bài  tập  

99  

Page 100: Lập Trình an toàn - Secure programming

3.  Viết  chương  trình  băm  nội  dung  một  }ile  bằng  giải  thuật  HMAC-­‐AES256,  sử  dụng  thư  viện  OpenSSL.  Mật  khẩu  để  băm  nhập  từ  bàn  phím.Kết  quả  băm  được  lưu  vào  cuối  }ile.  4.  Viết  chương  trình  kiểm  tra  tính  toàn  vẹn  của  một  }ile  bằng  giải  thuật  HMAC-­‐AES256.  Mật  khẩu  để  kiểm  tra  nhập  từ  bàn  phím.  

 

Bài  tập  

100  

Page 101: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  6.  Mã  hóa  công  khai  Public  Key  Cryptography  

Page 102: Lập Trình an toàn - Secure programming

6.1  Mã  hóa  với  OpenSSL  RSA  6.2  Chữ  ký  số  6.3  Biểu  diễn  khóa  6.4  Kết  nối  SSL  6.5  Hạ  tầng  khóa  công  khai    

Nội  dung  

102  

Page 103: Lập Trình an toàn - Secure programming

•  Mã  hóa  bất  đối  xứng  •  Là  các  giải  thuật  sử  dụng  một  cặp  khóa  cho  việc  mã  hóa  và  giải  mã  •  Dữ  liệu  được  mã  hóa  bằng  khóa  công  khai  sẽ  được  giải  mã  bằng  

khóa  bí  mật  và  ngược  lại.  •  Các  giải  thuật  thông  dụng:  RSA,  DSA,  Dif}ie-­‐Hellman.  •  Không  sử  dụng  trực  tiếp  để  mã  hóa  dữ  liệu  vì  tốc  độ  rất  chậm.  •  Thường  được  sử  dụng  để  

•  Trao  đổi  khóa  đối  xứng  trong  phiên  truyền  mật  •  Chữ  ký  số  •  Xác  nhận  danh  tính  •  …  

6.1  Mã  hóa  với  OpenSSL  RSA    

103  

Page 104: Lập Trình an toàn - Secure programming

•  OpenSSL  RSA  •  Thường  được  sử  dụng  trao  đổi  khóa  •  Lưu  trữ  tất  cả  thông  tin  về  một  khóa  dưới  cấu  trúc  RSA.  •  Tệp  tiêu  đề  rsa.h  •  Sinh  cặp  khóa  đối  xứng  bằng  hàm      RSA  *RSA_generate_key(int  bits,      //  Kích  thước  khóa:  1024,2048…  

     unsigned  long  exp,//  Số  mũ:  3,  17,  65537          void  (*cb)(int,  int,  void),    //  Callback        void  *cb_arg);      

6.1  Mã  hóa  với  OpenSSL  RSA    

104  

Page 105: Lập Trình an toàn - Secure programming

•  Mã  hóa  với  khóa  công  khai  •  Sử  dụng  hàm  RSA_public_encrypt:  

 int  RSA_public_encrypt(int  l,  //  Chiều  dài  dữ  liệu          unsigned  char  *pt,  //  Xâu/số  cần  mã        unsigned  char  *ct,  //  Kết  quả        RSA  *r,            //  Cấu  trúc  RSA          int  p);          //  Kiểu  padding    Kết  quả  trả  về:  chiều  dài  xâu  mã  được.    

6.1  Mã  hóa  với  OpenSSL  RSA    

105  

Page 106: Lập Trình an toàn - Secure programming

•  Giải  mã  với  khóa  bí  mật  •  Sử  dụng  hàm  RSA_private_decrypt:  

 int  RSA_private_decrypt(int  l,            unsigned  char  *ct,          unsigned  char  *pt,          RSA  *r,          int  p);    Kết  quả  trả  về:  chiều  dài  xâu  giải  mã  được  

6.1  Mã  hóa  với  OpenSSL  RSA    

106  

Page 107: Lập Trình an toàn - Secure programming

•  Bài  tập  –  Viết  chương  trình  chat  console  client-­‐server  sử  dụng  giải  thuật  RSA.  Chỉ  chia  sẻ  public  key  trên  đường  truyền.  

6.1  Mã  hóa  với  OpenSSL  RSA    

107  

Page 108: Lập Trình an toàn - Secure programming

•  Chữ  ký  số  dữ  liệu  nhằm  xác  thực  danh  tính  của  người  gửi,  tương  tự  như  HMAC  nhưng  sử  dụng  giải  thuật  RSA  

•  Quá  trình  ký  số  dữ  liệu  nhận  đầu  vào  là  giá  trị  băm  của  thông  điệp,  khóa  bí  mật  của  người  gửi,  đầu  ra  là  giá  trị  hàm  băm  đã  được  mã  hóa.  

•  Bên  nhận  thực  hiện  quá  trình  ngược  lại:  tính  giá  trị  băm  của  thông  điệp,  giải  mã  giá  trị  băm  đã  mã  hóa  của  bên  gửi  bằng  khóa  công  khai  và  so  sánh  hai  giá  trị  băm  này.  

•  Hacker  không  thể  giả  mạo  giá  trị  băm  vì  không  có  khóa  bí  mật  của  bên  gửi.  

6.2  Chữ  ký  số    

108  

Page 109: Lập Trình an toàn - Secure programming

•  Sơ  đồ  ký  

6.2  Chữ  ký  số    

109  

Dữ  liệu  

Giá  trị  băm  (MD)  

Hash  

(SHA1)  

Chữ  ký  

Khóa  bí  mật  

Mã  hóa  

Dữ  liệu  +  Chữ  ký  

Page 110: Lập Trình an toàn - Secure programming

•  Thực  hiện  bằng  OpenSSL  RSA  –  Hàm  RSA_sign  là  hàm  mức  thấp    của  OpenSSL  thực  hiện  ký  số  dữ  liệu  

6.2  Chữ  ký  số    

110  

int  RSA_sign(int  md_type,    //  Loại  Message  Digest:  SHA1,  MD5…    unsigned  char  *dgst,  //  Bản  thân  dữ  liệu  (Message  Digest)    unsigned  int  dlen,            //  Kích  thước    unsigned  char  *sig,        //  Chữ  ký    unsigned  int  *siglen,    //  Chiều  dài  chữ  ký    RSA  *r);                                                      //  Khóa  bí  mật    

Page 111: Lập Trình an toàn - Secure programming

•  Thực  hiện  bằng  OpenSSL  RSA  –  Hàm  RSA_verify  thực  hiện  công  việc  ngược  lại:  kiểm  tra  tính  hợp  lệ  của  chữ  ký  

•  Thực  hiện  bằng  OpenSSL  DSA  –  Xem  thêm  trong  sách  (phần  7.15)  

6.2  Chữ  ký  số    

111  

int  RSA_verify(int  md_type,    //Loại  message  digest:  md5,sha1,…      unsigned  char  *dgst,  //  message  digest    unsigned  int  dlen,            //  kích  thước  message  digest    unsigned  char  *sig,        //  Chữ  ký    unsigned  int  siglen,        //  Chiều  dài  chữ  ký    RSA  *r);                                                    //  Khóa  công  khai  

Page 112: Lập Trình an toàn - Secure programming

•  Biểu  diễn  khóa  và  chứng  thực  –  DER  (Binary)  –  PEM  (Plaintext)  

•  Biểu  diễn  DER  –  Chuẩn  quốc  tế  thông  dụng    –  Các  hàm  OpenSSL  tương  ứng:  i2d  và  d2i  (internal  representation  ó  DER)  –  Ví  dụ  chuyển  khóa  công  khai  RSA  sang  lưu  trữ  dưới  dạng  DER    

6.3  Biểu  diễn  khóa  

112  

unsigned  char  *DER_encode_RSA_public(RSA  *rsa,  int  *len)    {    

 unsigned  char  *buf,  *next;      *len  =  i2d_RSAPublicKey(rsa,  0);      if  (!(buf  =  next  =  (unsigned  char  *)malloc(*len)))  return  0;    i2d_RSAPublicKey(rsa,  &next);      /*  If  we  use  buf  here,  return  buf;  becomes  wrong  */      return  buf;    

}  

Page 113: Lập Trình an toàn - Secure programming

•  Biểu  diễn  DER  –  Ví  dụ  chuyển  khóa  từ  dạng  DER  sang  dạng  khóa  công  khai  RSA    

6.3  Biểu  diễn  khóa  công  khai    

113  

RSA  *DER_decode_RSA_public(unsigned  char  *buf,  long  len)    {  

   return  d2i_RSAPublicKey(0,  &buf,  len);    }  

Page 114: Lập Trình an toàn - Secure programming

•  Biểu  diễn  PEM  (Privacy  Enhanced  Mail)  –  Thực  chất  là  biểu  diễn  DER  dưới  dạng  Base64  và  có  thêm  phần  header,  footer  và  có  thể  mã  hóa  

–  Ví  dụ  -­‐-­‐-­‐-­‐-­‐BEGIN  RSA  PRIVATE  KEY-­‐-­‐-­‐-­‐-­‐    Proc-­‐Type:  4,ENCRYPTED    DEK-­‐Info:  DES-­‐EDE3-­‐CBC,F2D4E6438DBD4EA8    LjKQ2r1Yt9foxbHdLKZeClqZuzN7PoEmy+b+dKq9qibaH4pRcwATuWt4/Jzl6y85  NHM6CM4bOV1MHkyD01tFsT4kJ0GwRPg4tKAiTNjE4Yrz9V3rESiQKridtXMOToEp  Mj2nSvVKRSNEeG33GNIYUeMfSSc3oTmZVOlHNp9f8LEYWNmIjfzlHExvgJaPrixX  QiPGJ6K05kV5FJWRPET9vI+kyouAm6DBcyAhmR80NYRvaBbXGM/MxBgQ7koFVaI5  zoJ/NBdEIMdHNUh0h11GQCXAQXOSL6Fx2hRdcicm6j1CPd3AFrTt9EATmd4Hj+D4  91jDYXElALfdSbiO0A9Mz6USUepTXwlfVV/cbBpLRz5Rqnyg2EwI2tZRU+E+Cusb  /b6hcuWyzva895YMUCSyDaLgSsIqRWmXxQV1W2bAgRbs8jD8VF+G9w==    -­‐-­‐-­‐-­‐-­‐END  RSA  PRIVATE  KEY-­‐-­‐-­‐-­‐-­‐  

6.3  Biểu  diễn  khóa  công  khai    

114  

Page 115: Lập Trình an toàn - Secure programming

•  Biểu  diễn  PEM  (Privacy  Enhanced  Mail)  –  Các  hàm  OpenSSL:  

•  Tệp  tiêu  đề  <openssl/pem.h>    •  PEM_read_***  •  PEM_write_***  

–  Ví  dụ  ghi  ra  bộ  nhớ  khóa  bí  mật  RSA  được  mã  hóa  dưới  dạng  PEM  –  AES256-­‐CBC  

6.3  Biểu  diễn  khóa  công  khai    

115  

#include  <openssl/pem.n>  #include  <openssl/bio.h>  int  password_cb(char  *buf,  int  len,  int  rwqlag,  void  *cb_arg)  {  

 strcpy(buf,"hello");    return  strlen(buf);  

}  BIO  *  mem  =  BIO_new(BIO_s_mem());  BUF_MEM  *  bp;  BIO_get_mem_ptr(mem,&bp);  PEM_write_bio_RSAPrivateKey(mem,key,EVP_aes_256_cbc(),  

       0,0,password_cb,0);  

Page 116: Lập Trình an toàn - Secure programming

•  Secure  Socket  Layer  (SSL)  là  giao  thức  ở  tầng  ứng  dụng  cung  cấp  dịch  vụ  kết  nối  an  toàn  giữa  hai  ứng  dụng  trên  cơ  sở  hạ  tầng  khóa  công  khai.  

•  OpenSSL  cung  cấp  SSL  API  để  có  thể  viết  ứng  dụng  SSL  nhanh  chóng.  •  http://www.ibm.com/developerworks/linux/library/l-­‐openssl/

index.html#ibm-­‐pcon  •  OpenSSL  common  commands  –  NSA  Cyber  Security  

6.4  Kết  nối  SSL  

116  

Page 117: Lập Trình an toàn - Secure programming

•  Sử  dụng  bên  thứ  ba  để  chứng  thực  danh  tính  các  bên.  •  Chống  được  hình  thức  tấn  công  Man-­‐In-­‐The  Middle  •  Một  số  lệnh  thông  dụng  với  OpenSSL  

–  http://security.ncsa.illinois.edu/research/grid-­‐howtos/usefulopenssl.html  

6.5  Hạ  tầng  khóa  công  khai    

117  

Page 118: Lập Trình an toàn - Secure programming

Lương  Ánh  Hoàng  [email protected]  

Chương  7.  Anti-­‐Tampering    

Page 119: Lập Trình an toàn - Secure programming

7.1  Phát  hiện  thay  đổi  (Detecting  modi}ication)  7.2  Che  giấu  mã  (Code  hiding)  7.3  Sử  dụng  con  trỏ  hàm  (Function  Pointer)  7.4  Giấu  xâu  (String  hiding)  7.5  Phát  hiện  debugger  (Anti-­‐Debugger)  7.6  Self-­‐modifying  code  7.7  Giải  pháp  tổng  thể    

Nội  dung  

119  

Page 120: Lập Trình an toàn - Secure programming

•  Mục  tiêu:  Phát  hiện  chương  trình  đã  bị  crack  chưa  (Detecting  modi}ication)  

•  Kỹ  thuật:  –  Tính  MD5,  SHA1,  hoặc  HMAC  mã  lệnh  của  }ile  thực  thi.  –  Đánh  dấu  một  đoạn  trong  chương  trình  sẽ  dùng  để  lưu  mã  băm  }ile  thực  thi  và  ghi  

giá  trị  băm  vào  đó  bằng  một  chương  trình  Hex  edit  khác.  –  Tại  thời  điểm  runtime  tính  lại  giá  trị  băm  của  }ile  thực  thi  và  so  sánh  với  mã  băm  

trước  đó.  •  Ví  dụ:  

     

7.1  Phát  hiện  thay  đổi  mã  lệnh  

120  

//  Khai  báo  xâu  đánh  dấu  mã  băm  char  *  md5hash  =  "AAAAXXXXXXXXXXXXXXXX";  int  _tmain(int  argc,  _TCHAR*  argv[])  {  

 unsigned  char  hash[16];//  Giá  trị  băm  tính  được    unsigned  char  expectedhash[16];//  Giá  trị  băm  lưu  trong  }ile        FILE  *  fp  =  fopen(argv[0],"rb");//  Mở  }ile  để  tính  lại  giá  trị  băm    unsigned  char  *  pFile  ;    fseek(fp,0,SEEK_END);    int  len  =  ftell(fp);  

Page 121: Lập Trình an toàn - Secure programming

•  Ví  dụ:        

7.1  Phát  hiện  thay  đổi  mã  lệnh  

121  

pFile  =  (unsigned  char*)malloc(len);  fseek(fp,0,SEEK_SET);  fread(pFile,1,len,fp);  md5hash  =  0;  for  (int  i=0;i<len-­‐20;i++)  //  Dò  tìm  giá  trị  băm  trong  }ile  

 if  ((pFile[i]=='A')&&(pFile[i+1]=='A')&&        (pFile[i+2]=='A')&&(pFile[i+3]=='A'))    {    memcpy(expectedhash,pFile+i+4,16);  //  Lưu  ra  mảng  khác    memset(pFile+i+4,0,16);    //  Xóa  trắng  giá  trị  này  trong  }ile    }  

MD5(pFile,len,hash);        //  Tính  lại  giá  trị  băm      printf("File  hash:");    print_md5(hash);              printf("Expected  hash:");    print_md5(expectedhash);    if  (memcmp(hash,expectedhash,16))    {      printf("File  veri}ication  failed");    }    getch();    return  0;  

}  

Page 122: Lập Trình an toàn - Secure programming

•  Hạn  chế  –  Dễ  bị  đánh  bại  nếu  sử  dụng  hash  vì  cracker  cũng  có  thể  tính  lại  giá  trị  băm  và  sửa  }ile  

cho  chính  xác.  –  Nếu  sử  dụng  HMAC  thì  phải  lưu  mật  khẩu  ở  đâu  đó  

•  Lưu  trong  }ile:  Cũng  sẽ  bị  cracker  dò  ra  •  Lưu  trên  internet:  cần  có  kết  nối  internet  và  dễ  dàng  bị  dò  ra  nếu  dùng  sniffer.  •  CURL  

     

7.1  Phát  hiện  thay  đổi  mã  lệnh  

122  

Page 123: Lập Trình an toàn - Secure programming

•  Mục  tiêu  –  Gây  khó  khăn  cho  quá  trình  dịch  ngược  và  phân  tích  bằng  các  disassembler  

(Obfuscating  code).  Windasm,  OllyDbg,  IDA  –  Che  giấu  các  cấu  trúc  điều  khiển  quan  trọng  trong  chương  trình.  

•  Cấu  trúc  điều  kiện  •  Cấu  trúc  lặp  

•  Kỹ  thuật    –  Cần  sự  hỗ  trợ  của  trình  biên  dịch  –  Thực  hiện  ở  mức  hợp  ngữ  –  Sử  dụng  các  điều  kiện  so  sánh  “bất  thường”  

•  So  sánh  khác  thay  vì  bằng  •  Vòng  lặp  giảm  thay  vì  tăng.  •  Vòng  lặp  có  chỉ  số  tăng  khác  1.  •  …  

   

     

7.2  Che  giấu  mã  

123  

Page 124: Lập Trình an toàn - Secure programming

•  Mục  tiêu  –  Gây  khó  khăn  cho  các  công  cụ  disassembler  trong  việc  phân  tích  lời  gọi  hàm  

•  Kỹ  thuật    –  Không  thực  hiện  lời  gọi  hàm  trực  tiếp  trong  chương  trình  mà  sử  dụng  các  con  trỏ  

hàm.  –  VD      

     

7.3  Sử  dụng  con  trỏ  hàm  

124  

void  my_func()  {  }  typedef  void  (*FUNC)();  int  _tmain(int  argc,  _TCHAR*  argv[])  {  

 FUNC  ptr;    ptr  =  my_func;    printf("ptr  address:%p",ptr);    ptr();                                            /*  make  the  function  call  */    return  0;  

}    

Page 125: Lập Trình an toàn - Secure programming

•  Mục  tiêu  –  Gây  khó  khăn  cho  các  công  cụ  disassembler  trong  việc  phân  tích  các  xâu  nhạy  cảm  

trong  chương  trình.VD  •  Invalid  cd-­‐key  •  Registration  successful  •  …  

•  Kỹ  thuật    –  Mã  hóa  các  xâu  trong  chương  trình    

•  Base64  •  RC4  •  Giải  thuật  tự  chọn  •  …  

   

     

7.4  Giấu  xâu  

125  

Page 126: Lập Trình an toàn - Secure programming

•  Ví  dụ:  dịch  mã  các  ký  tự  trong  xâu  đi  0x19    

7.4  Giấu  xâu  

126  

#include  <stdio.h>  #de}ine  A(c)                        (c)  -­‐  0x19  #de}ine  UNHIDE_STR(str)  do  {  char  *p  =  str;    while  (*p)  *p++  +=  0x19;  }  while  (0)  #de}ine  HIDE_STR(str)      do  {  char  *p  =  str;    while  (*p)  *p++  -­‐=  0x19;  }  while  (0)    int  main(int  argc,  char  *argv[    ])  {  char  str[    ]  =  {          A('/'),  A('e'),  A('t'),  A('c'),  A('/'),          A('p'),  A('a'),  A('s'),  A('s'),  A('w'),  A('d'),  0      };              UNHIDE_STR(str);      printf("%s\n",  str);      HIDE_STR(str);              return  0;  }  

Page 127: Lập Trình an toàn - Secure programming

•  Mục  đích:  Phát  hiện  sự  tồn  tại  của  debugger  •  Kỹ  thuật:  rất  nhiều  (google  :  anti-­‐debugger)  

–  Kernel32!IsDebuggerPresent  –  PEB!IsDebugged  –  PEB!NtGlobalFlags  –  Self-­‐debugging  –  ….  

•  Ví  dụ    

 

7.5  Phát  hiện  debugger  

127  

#include  <windows.h>  int  _tmain(int  argc,  _TCHAR*  argv[])  {  

 if(IsDebuggerPresent())    {      printf("Program  is  being  debugged");    }    return  0;  

}  

Page 128: Lập Trình an toàn - Secure programming

•  Mục  đích:  –  Mã  hóa  lệnh  quan  trọng,  chỉ  giải  mã  khi  cần  thực  hiện  

•  Kỹ  thuật  –  Không  có  sự  trợ  giúp  của  trình  biên  dịch.  –  Gần  như  không  thể  thực  hiện  bằng  C/C++  –  Cần  hiểu  rất  sâu  về  hệ  điều  hành  +  hợp  ngữ  –  Googe:  shellcode  

•  Ưu  điểm  –  Không  thể  dissassembler  nếu  chưa  giải  mã.  –  Không  dành  cho  amater  cracker.  

•  Nhược  điểm  –  Rất  khó  bảo  trì  –  Vẫn  có  thể  crack  được  nếu  đặt  đúng  breakpoint  tại  điểm  decrypt  –  Xung  đột  với  DEP  (Data  Execution  Preventation)  

7.6  Self-­‐modifying  code  

128  

Page 129: Lập Trình an toàn - Secure programming

•  Các  kỹ  thuật  trên  nếu  kết  hợp  lại  có  thể  có  kết  quả  rất  tốt.  •  Trên  Windows:  

–  Sử  dụng  các  chương  trình  all-­‐in-­‐one:  “Packer”  •  ASPack  •  ASProtect  •  PECompact  •  PECrypt  •  Themida  •  …  

–  Code-­‐sign  ứng  dụng  bằng  chữ  ký  số  http://msdn.microsoft.com/en-­‐us/library/ms537361%28v=vs.85%29.aspx  

•  Trên  các  hệ  điều  hành  khác  –  Đang  tiến  dần  đến  xu  hướng  code-­‐sign:  VD  iOS,  MacOS…  

7.7  Giải  pháp  tổng  thể  

129  

Page 130: Lập Trình an toàn - Secure programming

•  Các  kỹ  thuật  trên  nếu  kết  hợp  lại  có  thể  có  kết  quả  rất  tốt.  •  Trên  Windows:  

–  Sử  dụng  các  chương  trình  all-­‐in-­‐one:  “Packer”  •  ASPack  •  ASProtect  •  PECompact  •  PECrypt  •  Themida  •  …  

–  Code-­‐sign  ứng  dụng  bằng  chữ  ký  số  http://msdn.microsoft.com/en-­‐us/library/ms537361%28v=vs.85%29.aspx  

•  Trên  các  hệ  điều  hành  khác  –  Đang  tiến  dần  đến  xu  hướng  code-­‐sign:  VD  iOS,  MacOS…  

7.7  Giải  pháp  tổng  thể  

130  

Page 131: Lập Trình an toàn - Secure programming

1.      Tìm  hiểu  và  minh  hoạ  các  kỹ  thuật  SQL  Injection  hiện  nay  (đặc  biệt  là  blind  sql  injection).(Tuần  14  -­‐  Thuý)  2.    Tìm  hiểu  và  minh  hoạ  kỹ  thuật  tấn  công  tràn  bộ  đệm  buffer  over}low  và  khai  thác  qua  shellcode.  Có  thể  dùng  Metasploit  để  thử  nghiệm.(Tuần  15-­‐  Xuan  Hiep)  3.      Tìm  hiểu  cơ  chế  leo  thang  đặc  quyền  trên  một  thiết  bị  chạy  hệ  điều  hành  Android  (rooting,  tìm  cái  dễ  root  nhất).(Tuần  15  –  Phi  Hiệp)  4.    Sử  dụng  một  trong  các  kỹ  thuật  đồng  bộ  để  thực  hiện  thuật  toán  quicksort  trên  bộ  vi  xử  lý  đa  nhân.  Yêu  cầu  tốc  độ  sắp  xếp  phải  đạt  được  tuyến  tính  với  số  nhân  của  bộ  vi  xử  lý.(Tuần  12  –  Ngọc  Anh)  5.    Sử  dụng  thuật  toán  HMAC  để  phát  hiện  thay  đổi  trong  mã  lệnh  của  chương  trình.  Với  key  và  giá  trị  băm  được  tải  về  từ  internet  trong  mỗi  lần  kiểm  tra.(Tuần  12  -­‐  Linh)  6.    Sử  dụng  chữ  ký  số  để  phát  hiện  thay  đổi  trong  mã  lệnh  của  chương  trình.  Với  public  key  được  tải  về  từ  internet  trong  mỗi  lần  kiểm  tra.(Tuần  13  –  Quynh,  Thành)  7.    Tìm  hiểu  các  kỹ  thuật  phát  hiện  debugger  (anti-­‐debugger)  và  các  kỹ  thuật  chống  phát  hiện  debugger  (anti-­‐anti-­‐debugger).(Tuần  13  –  Hoa,  Tùng)  8.    Xây  dựng  hệ  thống  cấp  phát  chứng  thực  số  dựa  trên  openssl  với  CA  sinh  sẵn  Chỉ  yêu  cầu  viết  bằng  php/html  để  nhận  tham  số  của  chứng  thực  qua  form,  sau  đó  sinh  ngay  cặp  chứng  thực/key  cho  client  và  biểu  diễn  dưới  dạng  PEM  (.crt,  .key)  (Tuần  14  –  Dat)  

Các  đề  tài  tìm  hiểu  

131