15 ky thuat lap trinh an toan

250 10 0
15 ky thuat lap trinh an toan

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

MỤC LỤC CHƯƠNG 1 TỔNG QUAN VỀ KỸ THUẬT LẬP TRÌNH AN TOÀN 1.1 Xây dựng phần mềm an toàn 1.1.1 Phân loại lỗi lập trình mất an toàn Trong quá trình xây dựng một phần mềm an toàn nói chung hay sử dụng các kỹ thuật lập trình an toàn cho phần mềm nói riêng, vấn đề loại bỏ và hạn chế các nguy cơ là rất quan trọng Để thực hiện được việc này, đòi hỏi người lập trình cần có các kiến thức căn bản về các nguy cơ gây ra mất an toàn, trong đó việc phân loại nguy cơ đóng vai trò quan trọng trong việc giảm thiếu công sức và phân bổ tài nguyên để hạn chế và loại bỏ các nguy cơ đe dọa Thông thường, người ta thường chia nguy cơ mất an toàn phần mềm do lỗi lập trình gây ra thành hai nhóm: nhóm chứa các lỗi phổ biến và lỗi do ngữ cảnh gây ra Nhóm chứa lỗi phổ biến là một vấn đề có thể xảy ra trong gần như bất kỳ chương trình viết bằng một ngôn ngữ nhất định Lỗi tràn bộ đệm là một ví dụ rõ nét nhất cho một khiếm khuyết chung của các chương trình C và C ++ Lỗi tràn bộ đệm đại diện cho một vấn đề bảo mật trong hầu hết mọi hoàn cảnh, và nhiều chức năng và cấu trúc mã chương trình đều có thể dẫn đến lỗi tràn bộ đệm là như nhau, không phân biệt về mục đích của chương trình Mặt khác, việc tìm kiếm các lỗi dựa trên ngữ cảnh cụ thể đòi hỏi một kiến thức cụ thể về ngữ nghĩa của chương trình Ví dụ, chúng ta hãy tưởng tượng một phần mềm xử lý các số thẻ tín dụng Để tuân thủ tiêu chuẩn bảo vệ dữ liệu cho thẻ thanh toán (PCI – Payment Card Industry), chương trình sẽ không bao giờ hiển thị một số thẻ tín dụng hoàn lại cho người sử dụng Bởi vì không có tiêu chuẩn chung về chức năng phần mềm dạng này hay cấu trúc dữ liệu để lưu trữ hoặc hiển thị dữ liệu cho thẻ tín dụng, tất cả các phần mềm đều có cách làm việc riêng của nó Do đó, việc tìm kiếm một vấn đề với việc xử lý thẻ tín dụng đòi hỏi sự hiểu biết ý nghĩa của các chức năng và cấu trúc dữ liệu được xác định bởi phần mềm Lỗi dựa trên ngữ cảnh cụ Lỗi phổ thể biến Ngoài số lượng ngữ cảnh cần thiết để xác định một khiếm khuyết phần mềm, nhiều lỗi có thể được tìm thấy chỉ trong một đại diện cụ thể của chương trình Bảng 1 bên dưới xem xét các ma trận hình thành bởi loại nguy cơ và khả năng hiển thị lỗi Tìm thấy trong mã phần mềm Phân tích tĩnh Quy tắc xây dựng sẵn khiến các công cụ dễ dàng tìm thấy những lỗi này mà không cần Có thể tìm thấy với phân tích tĩnh, nhưng có thể yêu cầu việc tùy biến Ví dụ: Thiếu kiểm soát các thông tin về thẻ tín dụng Chỉ tìm thấy trong thiết kế Phần lớn được tìm thấy thông qua việc phân tích kiến trúc, thiết kế chương trình phần mềm Yêu cầu hiểu những nguyên tắc an ninh chung cùng với phân tích từng lĩnh vực cụ thể Ví dụ: Khóa mật mã được lưu giữ trong quá trình sử dụng cho một thời gian không an toàn Bảng 1 Vấn đề ở mức cao thường chỉ có thể phát hiện trong thiết kế của chương trình, trong khi các lỗi khi triển khai như bỏ qua xác nhận đầu vào thường có thể được tìm thấy bằng cách kiểm tra mã nguồn của chương trình Ngôn ngữ lập trính hướng đối tượng như Java có lớp lớn thư viện, giúp cho chúng ta dễ dàng hiểu được thiết kế chương trình bằng cách kiểm tra mã nguồn Tuy nhiện, các lớp dẫn xuất từ các bộ thư viện chuẩn mang ngữ nghĩa quan trọng, nhưng ngay cả trong trường hợp tốt nhất, cũng không phải dễ dàng (hoặc mong muốn) sử dụng kỹ thuật reverse – engineer để thu được bản thiết kế từ bản triển khai Khiếm khuyết an ninh chia sẻ các chủ đề và các mẫu phổ biến đủ để nó có thể xác định một danh mục để mô tả chúng Chúng ta đã tạo ra hệ thống phân loại cho các lỗi, lỗ hổng an ninh ít nhất từ những năm 1970, nhưng những phân loại cũ này thường lạc hậu và không phù hợp, bắt kịp với những phân loại ngày nay Trong vài năm qua, chúng ta đã thấy một quan tâm mới trong lĩnh vực này Dự án liệt kê điểm yếu phổ biến (CWE) (http://cve.mitre.org/cwe/) đang xây dựng danh sách chính thức và phân loại cho các điểm yếu và lỗ hổng phần mềm Dự án OWASP Honeycomb (http://www.owasp.org/index.php/Category:OWASP_Honeycomb_Project) sử dụng cách tiếp cận dựa vào cộng đồng để xác định các thuật ngữ và các mối quan hệ giữa các nguyên tắc bảo mật, các mối đe dọa, tấn công, lỗ hổng, và biện pháp đối phó Chúng ta luôn hướng tới một tổ chức đơn giản cung cấp đủ kiến thức và thông tin hỗ trợ cho các lập trình viên về các loại lỗi lập trình mà có khả năng dẫn đến các vấn đề an ninh Đạt được phần mềm bảo mật tốt đòi hỏi việc bảo đảm tích hợp an ninh trong suốt vòng đời phát triển phần mềm Các phương pháp bảo mật khác nhau nhấn mạnh các bước quy trình khác nhau, nhưng tất cả các phương pháp này đêu chung một điểm: Các nhà phát triển cần phải kiểm tra mã nguồn để xác định an ninh có liên quan khuyết tật, lỗ hổng phần mềm Phân tích tĩnh có thể giúp xác định các vấn đề mà có thể phát hiện trong các mã nguồn chương trình Mặc dù bất kỳ các sai lầm đều có khả năng về mặt lý thuyết gây ra một vấn đề an ninh, tuy nhiên các loại lỗi mà thực sự dẫn đến vấn đề an ninh thường vây quanh một số ít đối tượng Bảng 1.2 dưới đây minh họa một số vấn đề trong kỹ thuật lập trình được thống kê Bảng 1.2 Một số lỗi phần mềm phổ biến 1.1.2 Lập trình phòng thủ là không đủ Thuật ngữ “lập trình phòng thủ” thường được đề cập trong các khóa học giới thiệu về lập trình Mặc dù nó ngày càng được đưa ra một ý nghĩa an ninh, lịch sử nó đã được gọi chỉ để thực hành mã hóa với những suy nghĩ rằng lỗi là không thể tránh khỏi và rằng, sớm hay muộn, một cái gì đó sẽ đi sai và dẫn đến tình huống bất ngờ trong chương trình Kernighan và Plauger gọi nó là "viết chương trình để nó có thể đối phó với thảm họa nhỏ" [Kernighan và Plauger, 1981] Chương trình phòng thủ tốt đòi hỏi phải thêm mã để kiểm tra các giả định Thuật ngữ “lập trình phòng thủ” là thích hợp, đặc biệt trong các khóa học giới thiệu lập trình, bởi vì các lập trình viên thường mới là có kẻ thù tồi tệ nhất của chính họ, và lớn hơn, tư duy phòng thủ phục vụ tiết lộ lỗi logic được thực hiện bởi các lập trình viên Chương trình phòng thủ tốt làm cho lỗi dễ dàng hơn trong việc tìm thấy và chẩn đoán Nhưng lập trình phòng thủ không đảm bảo phần mềm an toàn (mặc dù khái niệm bất thường mong đợi rất nhiều một bước đi đúng hướng) Khi chúng ta nói về an ninh, chúng tôi giả định sự tồn tại của một kẻ thù - những người đang cố tình tìm cách lật đổ hệ thống Thay vì cố gắng để bù đắp cho các loại điển hình của sự đổ vỡ (trên một phần của một trong hai người lập trình hoặc người sử dụng), phần mềm bảo mật là về việc tạo ra các chương trình cư xử một cách chính xác ngay cả trong sự hiện diện của hành vi nguy hiểm Xem xét các chức năng C sau đó in một thông điệp đến một đầu ra ở đây là tập tin mà không cần thực hiện bất kỳ kiểm tra lỗi: void printMsg(FILE* file, char* msg) { fprintf(file, msg); } Nếu một trong hai đối số cho chức năng này là giá trị NULL, chương trình sẽ gây lỗi hoặc bị sụp đổ Đối với kỹ thuật lập trình phòng thủ, chúng ta có thể kiểm tra để đảm bảo rằng cả hai thông số đầu vào là không NULL trước khi in thông điệp như sau: void printMsg(FILE* file, char* msg) { if (file == NULL) { logError("attempt to print message to null file"); } else if (msg == NULL) { logError("attempt to print null message"); } else { fprintf(file, msg); } } Từ góc độ an ninh, việc kiểm tra này khá đơn giản và không đi đủ xa Mặc dù chúng ta đã ngăn chặn việc gọi hàm với tham số không phù hợp làm hỏng chương trình bằng cách cung cấp các giá trị null, tuy nhiên việc này không thể chống lại việc kẻ tấn công đưa các đoạn mã độc hại vào tham số để truyền vào hàm chương trình và nó sẽ gây ra những lỗi hoặc chương trình hoạt động theo ý đồ của kẻ tấn công Bằng cách cung cấp msgas chuỗi định dạng theo yêu cầu của hàm fprintf (), chương trình đã để ngỏ khả năng kẻ tấn công có thể truyền vào một chuỗi độc hại được thiết kế để thực hiện một cuộc tấn công chuỗi định dạng Nếu kẻ tấn công có thể truyền vào một chuỗi tin nhắn trông giống như thế này, kẻ tấn công có khả năng kiểm soát của chương trình: AAA1_%08x.%08x.%08x.%08x.%08x.%n Những nỗ lực trong kỹ thuật lập trình phòng thủ cho thấy cách tiếp cận đơn giản để giải quyết một vấn đề lập trình có thể được an toàn Những người tạo ra ngôn ngữ lập trình, thư viện, chuẩn, các giao thức, và quy ước hầu hết các lập trình viên xây dựng dựa trên chúng không lường trước tất cả những cách làm này vẫn còn vấn đề Vì một giám sát thiết kế, chuỗi định dạng trở thành một vector tấn công, và dường như nỗ lực kiểm soát lỗi tạo ra những bất cập trước cuộc tấn công Một lập trình viên an ninh có ý thức sẽ làm kẻ tấn công mất đi các cơ hội gây tổn hại cho chương trình, ví dụ nguy cơ này gây ra bởi một chuỗi định dạng cố định Trong việc xem xét phạm vi của đoạn mã viết sai hoặc thiếu sót, lập trình viên có xu hướng sử dụng kinh nghiệm vốn có của mình như cho rằng: chương trình đổ vỡ, nó có thể rơi vòng lặp mãi mãi, hay đơn gian nó gây ra kết quả không mong muốn Tất cả các chế độ thất bại này đều quan trọng, nhưng ngăn ngừa chúng không giúp các phần mềm đứng vững trước các cuộc tấn công Trong lịch sử, các lập trình viên chưa được đào tạo để xem xét lợi thế hoặc khả năng của kẻ tấn công Điều này dẫn đến đoạn mã của chương trình có thể được bảo vệ tốt chống lại các vấn đề mà một lập trình quen thuộc nhưng vẫn dễ dàng cho kẻ tấn công để phá vỡ chương trình Bất cứ ai đã từng viết một chương trình biết rằng sai lầm là không thể tránh khỏi Bất cứ ai viết phần mềm chuyên nghiệp biết rằng sản xuất tốt phần mềm đòi hỏi một cách tiếp cận có hệ thống để tìm kiếm lỗi Nhiều nhất phương pháp sử dụng rộng rãi để phát hiện lỗi là kiểm tra năng động, trong đó bao gồm chạy phần mềm và so sánh sản lượng của nó chống lại một kết quả mong đợi Những người ủng hộ lập trình cực đoan muốn nhìn thấy rất nhiều bài kiểm tra nhỏ (đơn vị kiểm tra) được viết bởi các lập trình viên ngay cả trước khi các mã được viết đến tổ chức phần mềm có các tập đoàn lớn của các kỹ sư bảo đảm chất lượng là người chịu trách nhiệm về viết các bài kiểm tra, chạy thử nghiệm và đánh giá kết quả thử nghiệm Nếu chúng ta luôn luôn nghĩ đến an ninh như chỉ là một khía cạnh của phần mềm chất lượng, chúng ta có thể ngạc nhiên khi biết rằng nó gần như không thể cải thiện bảo mật chỉ bằng cách cải thiện đảm bảo chất lượng Trong thực tế, hầu hết các nỗ lực nâng cao chất lượng phần mềm đang hướng về phía thử nghiệm chức năng chương trình Mục đích là để tìm các lỗi đó sẽ ảnh hưởng đến người sử dụng nhất trong những trường hợp tồi tệ nhất Kiểm tra chức năng hoạt động tốt để đảm bảo rằng người sử dụng với nhu cầu thông thường sẽ được đáp ứng các yêu cầu của họ, nhưng nó sẽ không hoạt động cho việc tìm kiếm khiếm khuyết an ninh mà không liên quan đến tính năng bảo mật Hầu hết các phần mềm thử nghiệm là nhằm mục đích so sánh việc thực hiện các yêu cầu, và điều này phương pháp tiếp cận là không đủ cho việc tìm kiếm các vấn đề an ninh Phần mềm (thực hiện) có một danh sách những thứ đó là nghĩa vụ phải làm (yêu cầu) Hãy tưởng tượng thử nghiệm một phần của phần mềm bằng cách chạy các danh sách các yêu cầu và đảm bảo việc thực hiện hoàn thành từng yêu cầu một Nếu phần mềm không đáp ứng một yêu cầu cụ thể, bạn đã tìm thấy một lỗi Hoạt động này tốt để thử nghiệm chức năng phần mềm, ngay cả chức năng bảo mật, nhưng nó sẽ bỏ lỡ rất nhiều vấn đề an ninh bởi vì vấn đề an ninh thường không vi phạm các yêu cầu Thay vào đó, các vấn đề an ninh thường xuyên "chức năng ngoài ý muốn" mà làm cho chương trình không an toàn Whittaker và Thomson mô tả nó với sơ đồ trong hình 1.1 Hình 1.2 Tích hợp an ninh vào quy trình phát triển phần mềm Cách duy nhất đáng tin cậy để đảm bảo rằng phần mềm hoặc ứng dụng được xây dựng an toàn và linh hoạt là tích hợp an ninh và khả năng phục hồi vào quá trình phát triển phần mềm thông qua toàn bộ vòng đời phát triển (SDLC) Từ quan niệm về phát triển phần mềm, như các nghiên cứu đã chỉ ra rằng chi phí của các lỗ hổng khắc phục hậu quả hoặc sai sót trong phần mềm / ứng dụng trong giai đoạn thiết kế là thấp hơn trong giai đoạn sản xuất và đưa sản phẩm phần mềm ra thị trường Vì vậy, chúng ta cần phải tích hợp các quy trình an ninh vào vòng đời phát triển phẩn mềm sẽ giúp phần mềm trở nên rẻ hơn và an toàn hơn Nhiều trong số các quy trình bảo mật thường chỉ sử dụng phương châm chung là cải tiến dần từng bước, và bất kỳ tổ chức có thể áp dụng chúng vào môi trường hiện tại của mình Không có một cách đúng đắn duy nhất để thực hiện các quá trình này - mỗi tổ chức sẽ phải tinh chỉnh và tùy biến chúng cho sự phát triển cụ thể và môi trường hoạt động Những cải tiến quy trình này sẽ bổ sung thêm nhiều trách nhiệm và cơ cấu vào hệ thống Hình 1 cung cấp một cái nhìn tổng quan của quy trình bảo mật cơ bản và khả năng phục hồi, thích ứng cần được tích hợp vào các giai đoạn SDLC khác nhau, từ yêu cầu thu thập đến triển khai Mỗi quá trình mang trong nó những đặc điểm riêng, và khuyến nghị sẽ được đưa ra cho những thay đổi phù hợp với thiết kế, kiến trúc, mã nguồn, sử dụng của các thành phần của bên thứ ba hay cấu hình triển khai, đồng thời đưa ra các khuyến cáo để giúp chúng ta hiểu rõ hơn và giảm rủi ro xuống mức chấp nhận được Ở đây chúng ta sẽ tìm thấy hướng dẫn trong thực thi mà chúng ta cần nên xem xét thực hiện trong mỗi giai đoạn của SDLC : Hình An toàn trong các giai đoạn phát triển phần mềm SDLC Điều quan trọng cần lưu ý là mỗi kỹ thuật kiểm tra an ninh đều có ưu và khuyết điểm riêng của họ Bất kỳ một kỹ thuật kiểm tra an ninh riêng lẻ nào cũng không đủ để mang lại kiểm thử an toàn Đây là lý do tại sao SDL sử dụng một loạt các kỹ thuật kiểm tra an ninh, thay vì dựa trên một kỹ thuật đơn lẻ để tiến hành kiểm thử an ninh, nhằm đảm bảo tốt hơn các ứng dụng giao cho khách hàng được an toàn hơn và đáng tin cậy a) Kiểm thử mờ (Fuzzy testing) Phần lớn các lỗ hổng ứng dụng tồn tại ngày nay xuất phát từ việc các nhà phát triển không xác nhận, kiểm tra đầu vào Kiểm thử mờ là một phương pháp thử nghiệm có thể giúp xác định các vấn đề an ninh do đầu vào không được xác nhận đúng Kiểm thử mờ là một kỹ thuật thử nghiệm cốt lõi trong giai đoạn xác nhận, đánh giá trong SDL Có một số phương pháp tiếp cận để thực hiện kiểm thử mờ, tuy nhiên, hai phương pháp phổ biến nhất được biết đến đó là phương pháp "Kiểm thử mờ thông minh" và phương pháp "Kiểm thử mờ ngu ngốc" Kiểm thử mờ thông minh thực hiện kiểm tra đầu vào hợp lệ cho một ứng dụng và sau đó thay đổi các yếu tố đầu vào để tạo ra đầu vào không hợp lệ Mỗi một trong những yếu tố đầu vào không hợp lệ được nhập vào ứng dụng đang được thử nghiệm và hành vi của ứng dụng đối với những đầu vào được quan sát bởi các thử nghiệm an ninh Ví dụ, nếu một đầu vào hợp lệ của một ứng dụng là một số thẻ tín dụng (16 chữ số) sau đó kiểm thử mờ thông minh sẽ tạo ra các biến thể không hợp lệ của đầu vào, chẳng hạn như 16 ký tự, một hỗn hợp của 16 ký tự và con số, 16 biểu tượng, v.v Những đầu vào không hợp lệ là đầu vào cho các ứng dụng và phản ứng của ứng dụng cho những đầu vào được quan sát thấy Thông thường, nếu một đầu vào không hợp lệ gây cho một ứng dụng xuất hiện ngoại lệ, sự đổ vỡ chương trình, hoặc phát ra một số lỗi không quản lý được, một lỗ hổng, chẳng hạn như lỗi tràn bộ đệm, một định dạng chuỗi tấn công vector, hoặc sự từ chối của vector dịch vụ đã được xác định Kiểm thử mờ ngu ngốc tương tự như kiểm thử mờ thông minh, ngoại trừ các biến thể đầu vào không hợp lệ trong phương pháp này được tạo ra ngẫu nhiên chứ không phải là một cách nhắm tới một mục tiêu và có chủ ý Trở lại với ví dụ thẻ tín dụng ở trên, kiểm thử mờ câm sẽ sử dụng đầu vào không hợp lệ, chẳng hạn như nhập không có dữ liệu, 1.000 ký tự, và một ký tự duy nhất Song, đây là những giá trị ngẫu nhiên mà không xem xét đầu vào hợp lệ thực tế hoặc làm thế nào chúng được xử lý bởi các ứng dụng trước khi tạo biến thể đầu vào không hợp lệ Như bất kỳ kỹ thuật kiểm tra an ninh nào khác, kiểm thử mờ có ưu và nhược điểm của nó Một trong những điểm mạnh của kiểm thử mờ là các loại điểm yếu bảo mật mã nguồn mà nó xác định thường rất nghiêm trọng trong ứng dụng Ví dụ, các điểm yếu của mã nguồn, chẳng hạn như tràn bộ đệm, lỗi số học số nguyên hay SQL injection, đều là những lỗ hổng cho phép một người sử dụng ác ý có thể nắm quyền kiểm soát hoàn toàn của một ứng dụng Một tổn hại quan trọng của kiểm thử mờ là để xác định những điểm yếu bảo mật mã, ứng dụng cần phải sụp đổ hoặc xuất hiện lỗi khi một đầu vào không hợp lệ Điều này có nghĩa rằng bất kỳ dễ bị tổn thương hoặc suy yếu ứng dụng mà không kết quả trong một vụ tai nạn hoặc tình trạng lỗi thường không thể được tìm thấy sử dụng thử nghiệm mờ Ví dụ về các điểm yếu mã như vậy bao gồm những điểm yếu mật mã và tiết lộ thông tin Một lần nữa điều này là một trong những lý do tại sao SDL sử dụng một số kỹ thuật kiểm tra an ninh thay vì dựa vào một phương pháp kiểm thử duy nhất để đảm bảo tốt hơn các ứng dụng giao cho khách hàng được an toàn hơn và đáng tin cậy Phương pháp thực hiện kiểm thử mờ Cách tiếp cận chung để kiểm thử mờ lần đầu tiên xác định tất cả các điểm vào một ứng dụng Bước thứ hai, để xác định các yếu tố đầu vào hợp lệ với mỗi điểm vào ứng dụng được mong đợi và tạo ra một tập hợp các yếu tố đầu vào hợp lệ Ví dụ, nếu một textbox trong một ứng dụng được mong đợi một tên người dùng, sau đó tên người dùng hợp lệ có thể là Steve, Lenny, và Kevin Bước thứ ba là để sửa đổi các đầu vào hợp lệ được tạo ra ở bước 2 vào đầu vào không hợp Trở lại với ví dụ trước, đầu vào không hợp lệ có thể là Steve, Lenny và Kevin, nhưng với mỗi chữ "e" thay thế bằng số "3", tức là, St3v3, L3nny, và K3vin Bước cuối cùng chúng ta sẽ đưa các đầu vào không hợp lệ vào các ứng dụng và quan sát chương trình sẽ phản ứng như thế nào với các dữ liệu đầu vào trên Nếu ứng dụng bị treo, tạo ra một ngoại lệ, hoặc gây ra một số lỗi không mong muốn, sau đó một vấn đề tiềm tàng đối với an toàn mã sẽ được xác định Nếu kiểm thử mờ câm đang được sử dụng, thì các bước 2 và 3 có thể được bỏ qua và dữ liệu ngẫu nhiên có thể được sử dụng cho bước 4 Số lượng đầu vào không hợp lệ được sử dụng trong kiểm thử mờ (thông minh hay ngu ngốc) có thể rất lớn, đôi khi vượt quá hàng trăm ngàn đầu vào không hợp lệ khác nhau Ngoài ra, việc đưa những yếu tố đầu vào không hợp lệ vào các ứng dụng và sau đó quan sát phản ứng của ứng dụng theo giá trị đầu vào có thể được lặp đi lặp lại Vì vậy, trong SDL khuyến sử dụng hoặc phát triển các công cụ kiểm thử mờ nhằm tiến hành kiểm thử mờ tự động Tự động hóa và các công cụ chúng ta có thể sử dụng sẽ được thảo luận sau trong bài này b) Kiểm thử xâm nhập Kỹ thuật kiểm thử an ninh tiếp theo trong SDL là thử nghiệm thâm nhập Thử nghiệm thâm nhập mô phỏng một cuộc tấn công chống lại một ứng dụng thực tế và đánh giá khả năng của ứng dụng để chống lại những cuộc tấn công Thử nghiệm xâm nhập sẽ sử dụng một loạt các kỹ thuật hướng dẫn và các công cụ tự động để kiểm tra và khai thác lỗ hổng tiềm tàng trong ứng dụng Trong khi kiểm thử thâm nhập có thể hữu ích để hiểu được thế trận an ninh của một ứng dụng, điều quan trọng là cũng hiểu rằng các kết quả của thử nghiệm xâm nhập là chỉ liên quan đến trạng thái của ứng dụng tại thời điểm kiểm tra Điều này có nghĩa rằng nếu một ứng dụng thay đổi hoặc tái thiết kế, kết quả từ thử nghiệm xâm nhập có thể sẽ không còn được áp dụng được nữa Do đó, nếu một thử nghiệm thâm nhập là cần phải tiến hành một ứng dụng, thì chúng ta nên được thực hiện khi ứng dụng sắp tới trạng thái cuối cùng của nó Lúc này, chúng ta có thể tự hỏi sự khác biệt giữa kiểm thử thâm nhập và các kỹ thuật kiểm tra an ninh khác, chẳng hạn như kiểm thử mờ là gì Các mục tiêu của từng loại kiểm thử là tương tự, thậm chí chồng chéo, và tất cả có thể sử dụng để phân tích và cải tiến an ninh của một ứng dụng Sử dụng công cụ tự động kiểm tra bộ và các phương pháp mã hóa cứng để phát hiện ra lỗ hổng bảo mật, trong khi thử nghiệm thâm nhập sử dụng sự khéo léo của người thử nghiệm xâm nhập Yếu tố con người cho phép thử thâm nhập vượt qua được những khám phá đơn giản của các lỗ hổng và tạo ra khả năng kết nối các lỗ hổng với nhau để minh họa cho kịch bản có nhiều khả năng gây hại Khả năng này để kết nối các lỗ hổng khác nhau và hành vi ứng dụng với nhau để mô phỏng các cuộc tấn công phức tạp hơn là một cái gì đó mà các công cụ tự động thiếu hoặc không thực hiện được c) Xác thực trong thời gian thực thi Xác thực trong thời gian thực thi phần mềm được sử dụng để mô phỏng các điều kiện lỗi khi một phần mềm đang hoạt động Mục đích là để quan sát một phần mềm hoạt động theo những điều kiện đưa ra và phát hiện ra bất kỳ vấn đề bảo mật mã nào đó có thể tồn tại Các công cụ thường được sử dụng trong quá trình xác thực thời gian thực thi, ví dụ: công cụ AppVerifier của Microsoft là một trong những công cụ quan trọng được sử dụng trong SDL AppVerifier là công cụ được sử dụng để mô phỏng các điều kiện lỗi thời gian chạy đó sẽ là khó khăn để tạo ra dưới tình huống thử nghiệm bình thường d) Phân tích mã nguồn (Source Code Analysis) Phân tích mã nguồn là quá trình kiểm tra thủ công mã nguồn của một ứng dụng phần mềm để tìm các vấn đề an ninh Với mã nguồn, một người kiểm thử có thể xác định chính xác những gì đang xảy ra (hoặc cho rằng có thể xảy ra) và loại bỏ công việc phỏng đoán của kiểm thử hộp đen Phân tích mã nguồn cũng có thể cực kỳ hiệu quả để tìm các vấn đề thực hiện, như những nơi nào xác nhận đầu vào không thực hiện hoặc khi nào thủ tục kiểm soát không mở Phân tích tĩnh là quy trình phân tích một đoạn mã nguồn mà không cần thực hiện nó Việc phân tích tĩnh bao gồm: • Kiểm tra kiểu (Type checking) • Kiểm tra văn phong (Style checking) • Hiểu nội dung chương trình (Program Understanding) • Xác nhận chương trình (Program Verification) • Kiểm tra thuộc tính (Property Checking) • Tìm lỗi (Bug Finding) • Xét lại an ninh (Security Review) Đánh giá lại mã liên quan đến việc xem xét mã nguồn của một ứng dụng để xác định những điểm yếu phổ biến mà có thể cho phép một người sử dụng ác ý lợi dụng tấn công các ứng dụng Phân tích mã nguồn liên quan đến một số lượng đáng kể các nỗ lực và lý tưởng nên được thực hiện cho các mã ưu tiên cao Phân tích mã nguồn là một kỹ thuật kiểm tra an ninh rất hiệu quả Có truy cập trực tiếp vào mã nguồn của một ứng dụng mang lại xét nghiệm an ninh một lợi thế khác biệt Với xem xét mã, kiểm tra an ninh có thể thấy rõ những gì ứng dụng nào , và họ chính xác có thể tập trung nỗ lực vào các lĩnh vực đang được đánh giá cao khả năng bị tấn công Tuy nhiên , đối với tất cả các lợi ích của việc xem xét mã, có một khía cạnh tiêu cực nghiêm trọng trong quá trình xem xét mã : nó có thể là một quá trình tốn rất nhiều lao động và thời gian Ứng dụng ngày nay có thể dễ dàng vượt quá hàng trăm ngàn dòng mã Như vậy, khả năng của một người xem mã mất tích lỗ hổng nhất định có thể cao Khả năng này tăng lên nhiều hơn sau khi phiên xét mã dài và gian khổ được tiến hành bằng cách nhận xét mã Microsoft đã phát triển một số công cụ phân tích mã nguồn được sử dụng trong SDL có sẵn để tải về để hỗ trợ khách hàng của mình, đây là công cụ hỗ trợ đắc lực cho việc tự động hóa kiểm thử trong SDL 4.1.5 Tự động hóa kiểm thử trong SDL Microsoft đã phát triển một số công cụ sử dụng để xác định điểm yếu bảo mật phổ biến của ứng dụng khi phát triển các ứng dụng với mô hình SDL Để giúp khách hàng của Microsoft đạt được mức độ thành công tương tự, một số những công cụ này đã được thực hiện một cách tự do có sẵn để tải về Những công cụ này có thể được phân loại như phân tích mã nguồn, phân tích nhị phân, và các công cụ phân tích thời gian chạy (run-time) Điều quan trọng cần lưu ý là bất kỳ một trong những công cụ trên là không đủ để đảm bảo rằng một ứng dụng là không chứa các lỗ hổng hoặc được xem là "an toàn" Trong thực tế, không có công cụ từ Microsoft hoặc bất kỳ công ty nào khác có thể cung cấp sự bảo đảm như vậy, và mỗi công cụ bao gồm những điểm mạnh và điểm yếu nhất định Đây lại là lý do tại sao SDL không dựa trên bất kỳ một kỹ thuật kiểm tra hoặc công cụ, nhưng thay vì sử dụng một sự kết hợp của hướng dẫn, công cụ và quy trình để giúp cung cấp an toàn hơn và các ứng dụng đáng tin cậy hơn cho khách hàng của Microsoft 4.2 Kỹ thuật bảo vệ phần mềm 4.2.1 Vấn đề bảo vệ phần mềm Bảo vệ phần mềm chống lại kỹ thuật dịch ngược (reverse enginnering) là một chủ đề lập trình thường bị bỏ qua Mặc dù hiện nay, vấn đề này vẫn chưa có giải pháp tuyệt đối, toàn diện nhưng nó vẫn rất thú vị để khám phá các kỹ thuật có thể giúp ngăn chặn người khác hiểu và sửa đổi mã nhị phân của chương trình Những lý do để bảo vệ mã đã được biên dịch rất đa dạng như bảo vệ dữ liệu độc quyền hoặc các thuật toán, hay chúng ta muốn đảm bảo chương trình thực hiện đúng theo thiết kế ban đầu mà không bị can nhiễu bởi kẻ tấn công bên ngoài Ngoài ra, mã chương trình mà các chuyên gia bảo mật tạo ra sẽ phải có có một số hình thức, cơ chế chống giả mạo Trong những chương trình còn lại trên một hệ thống bị xâm người ta thường sẽ thấy chuỗi mã hóa, chống gỡ lỗi, tự sửa đổi mã, và các kỹ thuật khác nhằm ngăn chặn kẻ tấn công hiểu rõ những gì mã nhị phân thực hiện Thông tin sai lệch, làm rối gây khó khăn cho kẻ tấn công như biểu tượng gỡ lỗi giả mạo, chuỗi câu lệnh không được sử dụng, tên hàm mà không bao giờ liên kết động, trong khi các dữ liệu thực tế được lưu trữ dạng mã hóa như là dữ liệu tùy ý Chúng ta phải làm chủ các kỹ thuật che dấu và bảo vệ nhằm giúp nâng cao tính an toàn của chương trình, phần mềm Chúng ta xem xét phương pháp bổ sung bảo vệ cho phần mềm để giúp ngăn chặn kẻ tấn công, phá vỡ hoạt động của phần mềm hay sử dụng trái phép phần mềm để khám phá phần mềm hoạt động ra sao, thay đổi cách thức mà phần mềm hoạt động, v.v Giải pháp cho vấn đề này xác định điều kiện hoạt động cho các phần mềm được đáp ứng Có một số phương pháp khác nhau để bảo vệ phần mềm, mỗi phương pháp có những ưu điểm và nhược điểm của nó Không có phương pháp hay kỹ thuật nào là toàn năng, kết quả tốt nhất thu được bằng cách kết hợp một số kỹ thuật khác nhau: ví dụ, bằng cách sử dụng chữ ký để xác nhận tính toàn vẹn như là chìa khóa để giải mã phần của phần mềm trong quá trình xác nhận đầu vào Các mục tiêu bảo vệ phần mềm Mục tiêu của bảo vệ phần mềm không phải là bảo vệ tuyệt đối phần mềm mà thay vào đó nó hướng tới làm nản lòng các cracker khi tấn công vào phần mềm Đối với bất kỳ ứng dụng cho rằng đã được bảo vệ, bạn nên cho rằng các cracker đã kiểm soát tuyệt đối trong thành phần vật lý và phần mềm của hệ thống mà trên đó các ứng dụng đang chạy Phần cứng có thể được mô phỏng hoặc tùy chỉnh thiết kế, hệ điều hành và các công cụ liên quan có thể được vá hoặc viết từ đầu, mạng lưới có thể là một mạng LAN cô lập hoặc thậm chí một loạt các thiết bị loopback trên một máy duy nhất Những gì bóng nước này xuống đến là có rất ít , nếu có , các thành phần của hệ thống mà ứng dụng có thể giả định được tin cậy Điều này không có nghĩa là bảo vệ các phần mềm là vô ích, đúng hơn, nó có nghĩa là chúng ta phải thiết lập mục tiêu thực tế để bảo vệ phần mềm Mục tiêu cơ bản nhất của bảo vệ phần mềm là tăng mức độ kỹ năng cần thiết để crack các ứng dụng Bất cứ ai có kiến thức lập trình hợp lý và một trình gỡ lỗi tốt có thể theo dõi thông qua một ứng dụng, tìm nhảy có điều kiện mà một bảo vệ làm trong quá trình xác nhận của nó, và vô hiệu hóa chúng Một tiện ích đóng gói tùy chỉnh mà giải nén chỉ có một vài hướng dẫn tại một thời gian , có một số tiền hợp lý của mã chống gỡ lỗi , và tái sử mã và dữ liệu địa chỉ để xây dựng lại một hình ảnh quá trình khó khăn , đòi hỏi phải có một lượng kinh nghiệm trong bảo vệ nứt để đánh bại Mục tiêu cuối cùng là để che giấu bản chất của việc bảo vệ bản thân Bảo vệ phần mềm thất bại chủ yếu là do chúng rất dễ phát hiện Khi vị trí chính xác của một bảo vệ được biết, việc áp dụng là 90 % bị nứt Các mã hóa mạnh và các kỹ thuật chống gỡ lỗi tiên tiến nhất chỉ phục vụ để dẫn các cracker trực tiếp để bảo vệ phần mềm của bạn Vào thời điểm đó , nó chỉ đơn giản là một vấn đề thời gian trước khi bảo vệ được phá vỡ Kiểm tra bảo vệ nên càng không thể đoán trước càng tốt, do đó, các cracker thấy khó khăn để luôn kích hoạt bảo vệ, tương tự như vậy, ảnh hưởng của việc bảo vệ nên được ẩn , thực hiện mã dài hạn hoặc hư hỏng dữ liệu mà cuối cùng sẽ làm cho các ứng dụng vô dụng, thay vì hiển thị một tin nhắn hoặc từ chối thực hiện các phần của ứng dụng Có bốn phương pháp chính để bảo vệ phần mềm: • Phát hiện sửa đổi mã nhị phân đã biên dịch • Che dấu cản trở sự hiểu biết về thuật toán trong chương trình • Che dấu dữ liệu trong chương trình • Vô hiệu hóa các công cụ phân tích Các kỹ thuật được cung cấp trên đây vẫn chưa đầy đủ hết, nhưng thay vì được dùng để chứng minh các tùy chọn có sẵn cho các lập trình viên, và để cung cấp dễ dàng để sử dụng mã và macro để bảo vệ tập tin nhị phân Phần lớn các mã được cung cấp nhằm phục vụ như mã ví dụ , trong đó, vì lợi ích của sự rõ ràng , hạn chế các mã để các kỹ thuật đang được thảo luận Các ứng dụng an toàn của rất nhiều các kỹ thuật , chẳng hạn như xác định nơi để lưu trữ các khóa và tổng kiểm tra hợp lệ , hoặc làm thế nào để phát hiện sự thành công hay thất bại của một kiểm tra xác nhận mà không cần sử dụng một bước nhảy yêu cầu có điều kiện kết hợp các kỹ thuật khác nhau trong một bảo vệ duy nhất Hãy để cho người đọc để đưa ra những kết hợp này dựa trên các ví dụ được cung cấp Nhiều người trong số các kỹ thuật trình bày ở đây , đáng chú ý nhất trong chống gỡ lỗi phần - không đại diện cho sáng tạo nhất của công nghệ bảo vệ phần mềm bởi vì sự phức tạp của chủ đề nâng cao 4.2.2 Kỹ thuật bảo vệ phần mềm 4.2.2.1 Xác định tính toàn vẹn của phần mềm Các bản vá lỗi nhị phân có thể được áp dụng cho các chương trình biên dịch để thay đổi nội dung của mã hoặc dữ liệu chương trình Chương trình cần một cách để xác minh tính toàn vẹn của nó trong thời gian chạy Phát hiện các phần của mã nhị phân đã được sửa đổi hay không về cơ bản là một vấn đề phát hiện lỗi, do đó, một thuật toán checksum như CRC32, MD5 hoặc SHA1 có thể được sử dụng để tạo ra một chữ ký cho một khối tùy ý của đoạn mã hoặc dữ liệu Chữ ký này sau đó có thể được kiểm tra trong thời gian chạy để xác định xem bất kỳ sửa đổi nào đã diễn ra 4.2.2.2 Che giấu mã, chống dịch ngược a) Che giấu mã Hầu hết các chương trình C sử dụng cú pháp lập trình phổ biến dựa trên câu lệnh ngôn ngữ C, kiểu dữ liệu mặc định, và quy ước chức năng gọi / trả lại dựa trên các thư viện chuẩn C Những người quen thuộc với C dựa vào cách thức mã nguồn C được biên dịch sang ngôn ngữ hợp ngữ assembly có thể dễ dàng xác định các cú pháp trong mã nhị phân biên dịch Giải pháp Che giấu mã biên dịch đòi hỏi sự hiểu biết làm thế nào để xem xét ở mức ngôn ngữ hợp ngữ assembly Mục đích của che giấu mã C là để tạo ra mã nguồn có khả năng bảo hành khi thực thi có tốc độ gần giống như bản gốc, nhưng tạo ra sự khó hiểu khi biểu diễn hoặc dịch ra trong ngôn ngữ assembly Sự khó hiểu để che dấu này có thể sinh ra từ sự gia tăng sự phức tạp của thuật toán, hoặc từ một trình bày sai lạc của các hằng số, các kiểu dữ liệu, và biểu thức điều kiện được sử dụng trong một thuật toán b) Che dấu hằng và biến Giá trị như byte, short, và số nguyên rất khó để che giấu trong khi trải qua biến đổi toán học Điều này làm cho các giá trị hoặc phạm vi của các hằng số, các chỉ số, và biến đếm dễ dàng để xác định trong mã nhị phân biên dịch Thư viện Obcode bởi Pawel Krawczyk (http://echelon.pl/pubs/) cung cấp một API cho phép che dấu giá trị bit và byte, ngay cả trong các toán tử Kích thước của các biến đang tăng lên gấp tám lần, để một biến kiểu byte sẽ trở thành 8 byte và một biến kiểu số nguyên trở thành 32 byte Thư viện cung cấp cho các hoạt động cho kiểu byte như XOR, AND, OR và NOT, và hoạt động cho kiểu số nguyên bao gồm ADD, XOR, sao chép, và hoán đổi Thư viện Obcode vẫn còn đang phát triển và do đó thiếu một vài tính năng, tuy nhiên, ngay cả trong trạng thái hiện tại của nó cung cấp một phương tiện rất tốt cho che dấu giá trị nhỏ trong bộ nhớ Giá trị bị che dấu có thể được lưu trữ trong tập tin dữ liệu hoặc trong chương trình riêng của mình Ngoài ra, chúng ta biết biến được sử dụng thường xuyên, chẳng hạn như trong vòng lặp hoặc quầy, rất khó để xáo trộn mà không ảnh hưởng đến hiệu suất của chương trình Giải pháp cho vấn đề này là thay đổi các biến bằng một giá trị không đổi Ví dụ: #define SET_VAR(var) (((var) * 3) + 0x01040200) #define GET_VAR(var) (((var) - 0x01040200) / 3) for (i = SET_VAR(0); GET_VAR(i) < 10; i = SET_VAR(j + 1)) { j = GET_VAR(i); printf("2 + %d = %d\n", i, 2 + GET_VAR(i)); } c) Che dấu xâu ký tự Khi xem một tập tin trong một trình soạn thảo nhị phân, chuỗi ASCII là cấu trúc dữ liệu có thể được nhận ra ngay lập tức mà không cần kiến thức về các định dạng tập tin hoặc bất kỳ quen thuộc với mã máy Giải pháp cho việc này thực hiện che dấu chuỗi ký tự Chuỗi có thể được tạo ra tự động từ một tập hợp các chuỗi con hoặc các ký tự ngẫu nhiên Ngoài ra, chuỗi có thể được mã hóa trong hệ nhị phân và giải mã cho chương trình khi cần thiết Các kỹ thuật cho che dấu chuỗi ký tự được trình bày nhằm mục đích ngăn chặn phát hiện bởi phân tích bình thường, và không nên được coi là một cách an toàn choc he dấu các chuỗi Trong trường hợp một chuỗi phải được che dấu an toàn, chúng ta nên đối xử với chuỗi như thể nó là một mật khẩu, và sử dụng một phương pháp mã hóa mạnh d) Sử dụng con trỏ hàm Khi biết hàm được gọi -một cách trực tiếp hoặc gián tiếp-một lập trình viên có thể hiểu được hoạt động của một chương trình biên dịch mà không cần phân tích thời gian chạy Giải pháp đưa ra là sử dụng con trỏ hàm Địa chỉ của một hàm sẽ luôn luôn được hiển thị trong bộ nhớ trước khi nó được gọi là, tuy nhiên, bằng cách lưu trữ một phiên bản che dấu của con trỏ hàm, disassemblers và các công cụ phân tích tham chiếu chéo sẽ không nhận ra con trỏ được lưu trữ như một địa chỉ mã chương trình Lưu ý rằng kỹ thuật này sẽ không làm việc với con trỏ hàm yêu cầu phải thiết lập lại vị trí, chẳng hạn như địa chỉ của các hàm trong thư viện chia sẻ 4.2.2.3 Kỹ thuật chống debugging a) Phát hiện sự có mặt của debugger Kẻ tấn công vào việc bảo vệ phần mềm thường xuyên dựa vào gỡ rối (debugging) để quan sát hành vi trong thời gian chạy của một ứng dụng và kiểm tra các bản vá nhị phân để loại bỏ hoặc bỏ qua sự bảo vệ Chúng ta muốn ngăn chặn phân tích thủ công của ứng dụng bằng cách tích hợp mã chống gỡ rồi (anti-debugger) Tập lệnh Intel x86 sử dụng các int3 opcode (0xCC) như một điểm dừng nhúng một byte Địa chỉ quan trọng trong chương trình, chẳng hạn như địa chỉ đầu tiên trong một hàm có thể được kiểm tra để xem liệu họ đã được thay thế bằng một int3 opcode b) Kỹ thuật chống Disassembly Một tập tin đối tượng disassembler (bộ phân tách) có thể tạo ra một phiên bản ngôn ngữ assembler của mã nhị phân, sau đó có thể được sử dụng để hiểu và có thể thay đổi mã nhị phân của chương trình Phương pháp chống disassembler rất hữu ích trong phân tích tự động, nhưng chúng thường không xem xét đến yếu tố Hãy chắc chắn để kết hợp các phương pháp được trình bày ở trên với các dữ liệu hoặc kỹ thuật che dấu mã c) Kỹ thuật chống tự sửa đổi mã Chúng ta muốn ẩn các phần nhị phân sử dụng mã tự biến đổi mà không cần viết lại mã hiện có trong assembler Việc sử dụng hiệu quả nhất của mã tự sửa đổi này nhằm để ghi đè lên phần của mã này bằng phần của mã khác, sao cho cả hai bộ phần này không tồn tại cùng một lúc Điều này có thể tốn nhiều thời gian và chi phí để thực hiện, một kỹ thuật thích hợp hơn có thể đạt được điểu này với các macro C giải mã các byte thu hồi trong phần mã thực thi trong thời gian chạy Quá trình này bao gồm việc mã hóa các đoạn mã được bảo vệ sau khi mã nhị phân đã được biên dịch, sau đó giải mã nó chỉ sau khi nó đã được thực hiện ... TỔNG QUAN VỀ KỸ THUẬT LẬP TRÌNH AN TỒN 1.1 Xây dựng phần mềm an tồn 1.1.1 Phân loại lỗi lập trình an tồn Trong q trình xây dựng phần mềm an tồn nói chung hay sử dụng kỹ thuật lập trình an tồn... Nguyên tắc 3: Thất bại an toàn Lỗi xử lý an tồn khía cạnh quan trọng ứng dụng an toàn linh hoạt Hai loại lỗi cần đặc biệt ý: • Trường hợp ngoại lệ xảy việc xử lý kiểm sốt an ninh • Trường hợp ngoại... tạo an ninh điều kiện tiên để thực MSDL Khái niệm tảng cho việc xây dựng phần mềm tốt bao gồm thiết kế an tồn, mơ hình hóa mối đe dọa, mã hóa an tồn, kiểm tra an ninh, thực hành tốt xung quanh

Ngày đăng: 02/10/2021, 19:50

Mục lục

    CHƯƠNG 1 TỔNG QUAN VỀ KỸ THUẬT LẬP TRÌNH AN TOÀN

    1.1 Xây dựng phần mềm an toàn

    1.1.1 Phân loại lỗi lập trình mất an toàn

    1.1.2 Lập trình phòng thủ là không đủ

    1.2 Tích hợp an ninh vào quy trình phát triển phần mềm

    1.2.1 Giai đoạn khởi tạo – Tập huấn, đào tạo cho người phát triển

    1.2.2 Giai đoạn 1: Tập hợp yêu cầu và phân tích

    1.2.3 Giai đoạn 2: Thiết kế hệ thống

    1.2.4 Giai đoạn 3: Phát triển (lập trình)

    1.2.5 Giai đoạn 4: Thử nghiệm

Tài liệu cùng người dùng

Tài liệu liên quan