7 Tổng kết
3.5 Lưu dữ liệu cây AST vào mảng
Ngoài việc tìm cách biểu diễn lại mã nguồn và tự động trích xuất đặc trưng từ đó cho các mô hình học máy, học sâu, một số nghiên cứu thực hiện đề xuất trực tiếp các đặc trưng để nhận diện lỗ hổng bảo mật. Ví dụ, nghiên cứu [24] đề xuất sẵn một bộ các thuộc tính đặc trưng nhận diện lỗ hổng. Sau đó, mã nguồn được phân tích theo phương pháp của Balzarotti [4] để xác định có hay không có sự tồn tại của từng đặc trưng: các thuộc tính thuộc về phân tích tĩnh được xem xét trước, nếu bị nghi ngờ không chính
xác, thực hiện phân tích động bằng cách mô phỏng lại hiệu ứng của các hàm có chức năng lọc dữ liệu nhận vào bằng cách thực thi đoạn mã với nhiều bộ dữ liệu kiểm tra khác nhau. Vector chứa các giá trị thể hiện thuộc tính đặt ra có hay không có trong mã nguồn đang xem xét chính là vector đặc trưng để đưa vào mô hình học máy phân loại.Tương tự, trong nghiên cứu [25], hai tác giả L. K. Shar và H. B. K. Tan cũng đề xuất một bộ các thuộc tính (Bảng 3.1) liên quan đến việc kiểm tra và sàng lọc giá trị đầu vào nhạy cảm, được lấy từ quá trình phân tích tĩnh mã nguồn của chương trình. Sau đó, thông tin về các thuộc tính này được sử dụng để huấn luyện mô hình dự đoán hai lỗ hổng bảo mật là SQL injection (SQLi) và cross site scripting (XSS). Điểm chung giữa hai nghiên cứu này là các đặc trưng dùng cho mô hình học nhận diện các lỗ hổng đều được định sẵn, dựa theo nghiên cứu hoặc kinh nghiệm về đặc điểm của một số lỗ hổng xác định. Việc tự định nghĩa một bộ các thuộc tính khiến cho độ chính xác của mô hình phụ thuộc nhiều vào việc các đặc trưng được đề ra có thể hiện được đặc điểm nhận diện của một lỗ hổng bảo mật hay không. Một nhược điểm nữa của việc sử dụng các đặc trưng được định sẵn là sự thiếu linh hoạt trong việc cập nhập lỗ hổng mới. Nếu muốn mô hình có thể nhận diện được một lỗ hổng chưa được phân tích, các bước như thu thập dữ liệu về lỗ hổng, phân tích đặc điểm, tổng quát hóa đặc điểm của lỗ hổng thành đặp trưng cụ thể đều phải làm thủ công và đưa liệu vào huấn luyện mô hình lại.
Chương 3
Bảng 3.1: Bộ thuộc tính mã nguồn được đề xuất.
Attribute Description
Client The number of nodes which access data from external users File The number of nodes which access data from files
Database The number of nodes which access data from database
Textdatabase Boolean value ‘TRUE’ if there is any textbased data accessed from database; ‘FALSE’ otherwise
Otherdatabase Boolean value ‘TRUE’ if there is any data except text-based data accessed from database; ‘FALSE’ otherwise
Session The number of nodes which access data from persistent data objects
Uninit The number of nodes which reference uninitialized program variable
SQL The number of SQL sink nodes HTML The number of HTML sink nodes
SQLIsanitization The number of nodes that apply language provided SQLI pre- vention functions
XSSsanitization The number of nodes that apply language provided XSS pre- vention functions
... ...
Vulnerable? Target attribute which indicates a class label—Vulnerable or Not-Vulnerable
3.3 Ứng dụng các kĩ thuật hướng dữ liệu3.3.1 Phương pháp học sâu 3.3.1 Phương pháp học sâu
Trong xây dựng công cụ nhận diện lỗ hổng bảo mật, một số nghiên cứu lựa chọn áp dụng kĩ thuật học sâu để tự động tạo ra các đặc trưng để phân loại mã nguồn. Ví dụ, nghiên cứu [16] được đề cập trước đó, coi mã nguồn như ngôn ngữ tự nhiên, sau đó sử dụng kết hợp các mô hình CNN để học các đặc trưng cần thiết. Cũng với phương pháp xử lí mã nguồn bằng học sâu, các nhà nghiên cứu của công cụ VulDeePecker [18] sử dụng ý tưởng từ LSTM để xây dựng nên mô hình mạng neuron phân loại mã nguồn.
3.3.2 Phương pháp học máy
Hầu hết các nghiên cứu khác [13, 25], không lựa chọn biểu diễn mã nguồn ở dạng cấu trúc tuần tự như ngôn ngữ tự nhiên, sẽ hướng đến cách vector hóa các thông tin có trong mã nguồn và thực hiện huấn luyện các mô hình học máy cơ bản để phân loại. Cách tiếp cận này đòi hỏi dữ liệu được vector hóa trong bước biểu diễn mã nguồn phải có giá trị thông tin cao do chất lượng phân loại của các mô hình học máy cơ bản phụ thuộc rất lớn vào điều này.
4
Phương pháp đề xuất
4.1 Phát biểu bài toán
Trong luận văn này, một công cụ thực hiện phân tích và dự đoán dự tồn tại của lỗ hổng trong mã nguồn được đề xuất và hiện thực. Dữ liệu được sử dụng làm đầu vào cho công cụ là các file mã nguồn có chứa hoặc không chứa lỗ hổng bảo mật. Kết quả mong đợi sau khi công cụ thực hiện phân tích xử lí trên mã nguồn đưa vào là dự đoán về sự tồn tại của lỗ hổng trong đó. Công cụ dự đoán lỗ hổng trên mã nguồn với sự hỗ trợ của học máy sẽ gồm ba bài toán chính cần giải quyết.
• Biểu diễn mã nguồn.
• Trích xuất đặc trưng từ biểu diễn của mã nguồn.
• Huấn luyện mô hình học máy để dự đoán lỗ hổng trong mã nguồn.
4.2 Mô tả Tập dữ liệu4.2.1 SARD 4.2.1 SARD
SARD (Software Assurance Reference Dataset) là một bộ dữ liệu liên tục được cập nhật và bổ sung từ gần hai trăm nghìn chương trình thử nghiệm với những lỗ hổng đã được ghi nhận với các trường hợp kiểm thử khác nhau, từ các chương trình tổng hợp nhỏ đến lớn. Tập dữ liệu SARD cho phép người dùng, các nhà nghiên cứu và các nhà phát triển đánh giá các công cụ và kiểm tra các phương pháp rà soát lỗ hổng được đề xuất.
Tập dữ liệu sử dụng trong luận văn này được lấy từ SARD, bao gồm các đoạn mã tổng hợp cho các lỗ hổng bảo mật SQLi và XSS của ngôn ngữ PHP, được tạo ra bởi một công cụ do Bertrand Stivalet xây dựng [27]. Các mẫu kiểm thử được chia thành hai loại: an toàn và không an toàn. Toàn bộ mã nguồn được chứa trong một file duy nhất, với thông tin về loại lỗ hổng và vị trí dòng chứa đoạn mã bị lỗi. Số lượng các file và phân bố của mỗi loại được thể hiện như trong Bảng 4.1.
Bảng 4.1: Phân bố các file theo loại lỗ hổng trong bộ dữ liệu
Phân loại SQLi (CWE-89) XSS (CWE-79)
An toàn 8640 6176
Không an toàn 912 3904
4.2.2 Xử lí Tập dữ liệu
Từ bảng thống kê 4.1, số lượng file an toàn và không an toàn của cả hai loại lỗi chênh lệnh tương đối lớn, nghĩa là đây là bộ dữ liệu không cân bằng (imbalance dataset). Điều này cho thấy mô hình học máy phân loại dựa trên tập dữ liệu này có khả năng không hiệu quả và chỉ số đo lường về độ chính xác sẽ không phản ánh đúng khả năng của mô hình. Để giải quyết vấn đề này, chúng tôi sử dụng phương pháp undersampling: đối với tập các file an toàn, chúng tôi sẽ lấy mẫu ngẫu nhiên để làm cho số lượng file của lớp an toàn ngang bằng với lớp không an toàn (lớp thiểu số). Điều này có nghĩa là chúng tôi chỉ sử dụng một tập hợp con ngẫu nhiên của các file an toàn này để tạo nên tập dữ liệu chính thức. Bên cạnh đó, vì số lượng tệp là rất lớn, việc lấy mẫu ngẫu nhiên này là cần thiết để tránh gặp phải vấn đề về bộ nhớ ở các bước sau. Bên cạnh đó, để đánh giá độ hiệu quả của mô hình, nhiều chỉ số liên quan khác ngoài độ chính xác đều sẽ được xem xét. Các chỉ số này sẽ được trình bày trong Chương??.
Sau đó, chúng tôi thực hiện chia tập dữ liệu đã qua xử lí thành các tập huấn luyện (training) / điều chỉnh (validating) / kiểm tra (testing) theo tỷ lệ tương ứng là 70%, 10% và 20%. Danh sách các file thuộc các tập dữ liệu với thông tin về dòng chứa lỗi và loại lỗi sau đó được “pickle” 1 và lưu trữ trong một file hệ thống. Điều này giúp tiết kiệm thời gian quét lại các thư mục lưu trữ file và các file được chia vào các tập vẫn được giữ cố định.
4.3 Biểu diễn thông tin mã nguồn
4.3.1 Mức độ chi tiết trong phân tích mã nguồn
Như đã đề cập ở Mục 3.2, khi sử dụng học máy để phát hiện lỗ hổng bảo mật, chúng ta cần biểu diễn mã nguồn theo cách có thể bảo toàn được đầy đủ nhất thông tin cú pháp và ngữ nghĩa liên quan đến lỗ hổng. Việc xác định mức độ chi tiết (granularity) để xem xét mã nguồn là bước đầu trong quá trình này.
Với tiêu chí đảm bảo thông tin về cấu trúc và mối liên hệ giữa các thành phần được toàn vẹn, lựa chọn đơn giản nhất chính là coi toàn bộ mã nguồn là một đơn vị để xem xét. Tuy nhiên, đối với một ứng dụng trong thực tế, số lượng mã nguồn là tương đối lớn. Điều này khiến việc phân tích không hiệu quả do chứa quá nhiều đoạn mã dư thừa và không cung cấp thông tin về lỗ hổng.
1Pickle là một phần quan trong trong thư viện của Python. Pickling là quá trình chuyển đổi một đối tượng phân cấp trong Python thành dạng binary. Pickle sử dụng cách thức chuyển đổi riêng (chỉ dành riêng cho Python), không gắn với bất cứ một chuẩn chuyển đổi nào.
Chương 4
Một lựa chọn khác là xem xét mã nguồn ở mức độ hàm, nghĩa là coi mỗi chức năng trong chương trình là một vùng riêng lẻ để phân tích. Ưu điểm của nó nằm ở việc các câu lệnh, các biến trong một hàm thường có mối quan hệ chặt chẽ hơn và khối lượng công việc khi phân tích một hàm sẽ giảm đi rất nhiều so với toàn bộ mã nguồn. Tuy nhiên như đã tìm hiểu ở Tiểu mục 2.4.2 , đặc điểm các loại lỗ hổng trong ứng dụng web PHP là sự di chuyển mã độc từ đầu vào của người dùng tới đoạn mã nhạy cảm, nghĩa là luồng di chuyển của dữ liệu độc hại không thể được thể hiện đầy đủ nếu chỉ phân tích ở mức độ hàm. Mặt khác, cũng có thể đề xuất xử lý từng dòng lệnh như một đơn vị phát hiện lỗ hổng bảo mật. Tuy nhiên, cách này còn tồn tại nhược điểm chính là hầu hết các câu lệnh trong một chương trình không chứa bất kỳ lỗ hổng nào.
Để có thể biểu diễn khái quát được phần lớn dòng chảy của dữ liệu trong chương trình nhưng cũng không khiến phạm vi phân tích quá rộng làm giảm hiệu quả, chúng tôi lựa chọn mức độ chi tiết để xem xét mã nguồn là theo từng file. Đây đồng thời cũng là lựa chọn phù hợp nhất sau khi cân nhắc đặc điểm đã được trình bày ở Tiểu mục 4.2 của bộ dữ liệu được sử dụng trong đề tài này.
4.3.2 Tạo đồ thị CPG từ mã nguồn
Để biểu diễn thông tin của mã nguồn trong bộ dữ liệu mã nguồn PHP đã được gán nhãn các lỗi bảo mật tương ứng, chúng tôi sử dụng mô hình đồ thị CPG [2], là sự kết hợp của các đồ thị AST, CFG và PDG, giúp cung cấp đầy đủ các thông tin về cú pháp, luồng điều khiển và sự phụ thuộc dữ liệu trong chương trình. Như vậy, với một đồ thị CPG bất kì được lưu trữ trong cơ sở dữ liệu đồ thị Neo4j, việc thực hiện các câu lệnh truy vấn nhằm tìm ra vị trí các luồng thực thi trong chương trình dễ bị kẻ tấn công khai thác trở nên nhanh chóng và dễ dàng hơn rất nhiều.
Công cụ PHPJoern 2. Song song với việc đề xuất mô hình đồ thị CPG, nhóm tác giả của nghiên cứu [2] đã hiện thực công cụ hỗ trợ sinh đồ thị CPG từ mã nguồn PHP là PHPJoern. Để thuận tiện, chúng tôi sẽ sử dụng công cụ này trong quá trình hiện thực đề tài ở bước sinh đồ thị CPG từ mã nguồn. Thông tin của đồ thị tạo ra sẽ được lưu trong 3 file là node.csv - chứa thông tin về đỉnh của đồ thị, rels.csv- chứa thông tin về quan hệ AST giữa các nút, vàcpg_edge.csvchứa thông tin về luồng điều khiển, luồng dữ liệu. Theo tài liệu hướng dẫn được cung cấp cho công cụ [13], cấu trúc của đồ thị CPG được lưu trữ trong các file này như sau.
• Các nút File và Thư mục (type:File/Directory). Hệ thống phân cấp thư mục được thể hiện bằng cách tạo một nút cho mỗi File/Thư mục và kết nối các nút này bằng các cạnh PARENT_DIR_OF và FILE_OF. Các nút này cho phép xác định vị trí của mã nguồn trong hệ thống phân cấp các thư mục và tệp.
• Các nút khai báo Cấu trúc/ Lớp (type: Class). Một nút Lớp được tạo cho mỗi cấu trúc/lớp được xác định và kết nối với các nút File bằng các cạnh FILE_OF. Các khai báo thuộc tính và phương thức của lớp được kết nối với các nút lớp bằng các cạnh CLASS_OF.
2
Hình 4.1: Minh họa đồ thị tạo bởi PHPJoern
• Các nút hàm (type: Function). Một nút được sinh ra cho mỗi hàm. Bản thân nút hàm chỉ giữ tên và chữ ký của hàm. Nút hàm còn là nút gốc trong cây AST và Đồ thị luồng điều khiển tương ứng của hàm.
• Các nút AST (type:various). Cây cú pháp trừu tượng AST đại diện cho cấu trúc cú pháp của mã nguồn. Biểu diễn phân cấp của AST cho thấy cách cấu trúc ngôn ngữ được cấu tạo để tạo thành cấu trúc lớn hơn. Ví dụ: một câu lệnh có thể bao gồm một biểu thức gán, bản thân nó bao gồm một giá trị bên trái và bên phải trong đó giá trị bên phải có thể chứa một biểu thức phép nhân. Các nút cây cú pháp trừu tượng được kết nối với các nút con của chúng bằng các cạnh AST_PARENT_OF. • Các nút Câu lệnh. Đây là một tập hợp con của các nút cây AST. Các nút câu lệnh được kết nối với các nút câu lệnh khác thông qua các cạnh FLOWS_TO và REACHES để chỉ ra luồng điều khiển và luồng dữ liệu tương ứng.
Chương 4
toàn cục được lưu trong các nút của câu lệnh khai báo và được kết nối với File nguồn mà chúng được chứa trong đó bằng cách sử dụng các cạnh FILE_OF.
Gắn tag thay cho tên biến và tên hàm cụ thể
Như đã trình bày ở Mục 2.1, thông tin thu được từ đồ thị cho ta cái nhìn tương đối đầy đủ về chương trình. Tuy nhiên, vì tên hàm, biến,... được thể hiện ở dạng chi tiết, cụ thể trong các nút của AST nên nếu ta trực tiếp đem CPG để tìm mẫu đồ thị con phổ biến đặc trưng cho các loại lỗ hổng hoặc trực tiếp dùng huấn luyện mô hình thì có thể xảy ra trường hợp không tìm được mẫu chung nào hoặc mô hình bị overfit, chỉ dự đoán theo chính xác tên các hàm, biến được được huấn luyện.
Vì vậy, chúng tôi thực hiện thay thế các nhãn thể hiện chức năng của hàm/ biến vào nút chứa các tên cụ thể này trong đồ thị CPG. Dựa theo nghiên cứu [10], để xác định token của từng thành phần trong câu lệnh, ta có thể sử dụng hàm có sẵn trong PHP token_get_all() và thực hiện gán các giá trị token tương ứng vào cho các nút. Hàm token_get_all()không thể lấy thông tin của tên hàm, vì tất cả các tên hàm đều được phân tích cú pháp thành mãT_STRING. Chúng tôi sử dụng hàm function_exists() để đánh giá liệu một hàm nào đó có phải là hàm được định nghĩa sẵn bởi PHP hay không. Tiếp theo, tokenizer của chúng tôi sẽ giữ tên hàm khi nó là một hàm được xác định hoặc mã thông báo của nó là T_STRING. Trên thực tế, một số hàm thực hiện có chức năng gần giống nhau nhưng lại được phân tích ra thành các tên khác nhau. Để ngăn không cho khi huấn luyện mô hình gặp khó khăn khi vướng vào các tên khác nhau của các chức năng gần tương tự nhau, chúng tôi xem xét sử dụng một danh sách dùng để thống nhất cácmột số hàm có sự khác biệt về chức năng không đáng kể. Bảng 4.2 thống nhất nhãn của một số hàm quan trọng cần chú ý của lỗ hổng SQLi và XSS.