Chương 13 : Bảomật Mục tiêu chính của Microsoft .NET Framework là làm cho việc lập trình trở nên an toàn hơn—đặc biệt lưu tâm đến việc sử dụng mobile code 1[1][5] và các hệ thống phân tán. Hầu hết các hệ điều hành hiện đại (bao gồm Microsoft Windows) đều hỗ trợ bảomật dựa-trên- người-dùng (User-Based Security), cho phép bạn kiểm soát các hành động và các tài nguyên mà một người dùng truy xuất đến. Tuy nhiên, do sự phát triển của mạng máy tính, đặc biệt là Internet, sự bảomật nếu chỉ dựa vào định danh của người dùng trên hệ thống là chưa đủ. Khi quan tâm đến bảo mậ t, mã lệnh không nên tự động nhận mức tin cậy như mức tin cậy mà bạn đã ấn định cho người đang chạy mã lệnh này. .NET Framework kết hợp hai mô hình bảomật bổ sung lẫn nhau (thực hiện nhiều vấn đề liên quan đến bảomật người dùng và mã lệnh): • CAS (Code Access Security—Bảo mật truy xuất mã lệnh) • RBS (Role-Based Security—Bảo mật dựa-trên-vai-trò) CAS và RBS không thay th ế hay sao lại các phương tiện bảomật do hệ điều hành nằm dưới cung cấp. Chúng là các cơ chế độc lập nền, cấp thêm các khả năng bảomật để nâng cao tính bảomật tổng thể trong các giải pháp được-quản-lý. CAS sử dụng các thông tin về nguồn gốc của một assembly đã được thu thập lúc thực thi—đây là chứng cứ (evidence)—để xác định xem mã lệnh có th ể truy xuất các hành động và tài nguyên nào—đây là quyền (permission). Chính sách bảomật của .NET Framework—một tập hợp phân cấp các quy tắc cấu hình—định nghĩa phép ánh xạ giữa chứng cứ và quyền. Thư viện lớp .NET Framework sử dụng các yêu cầu quyền (permission demand hay permission request) để bảo vệ các chức năng quan trọng nhất của nó không bị truy xuất trái phép. Một yêu cầu buộc bộ thực thi bảo đảm rằng: nếu muốn gọi một phương thức được-bảo-vệ thì mã lệnh phải có một quyền cụ thể nào đó. CAS bảo đảm rằng: khả năng thực thi của mã lệnh tùy thuộc vào mức độ tin cậy của bạn đối với người tạo ra mã và nguồn gốc của nó, chứ không phải mức độ tin cậy đối với ng ười dùng đang chạy mã. Các mục liên quan đến CAS trong chương này thảo luận các vấn đề sau: Cho phép mã lệnh có-độ-tin-cậy-một-phần (partially trusted code) truy xuất các assembly tên mạnh của bạn (mục 13.1). Vô hiệu hoàn toàn CAS (mục 13.2) hoặc chỉ vô hiệu việc kiểm tra quyền thực thi (mục 13.3). Yêu cầu các quyền truy xuất mã lệnh cụ thể và xác định xem bộ thực thi đã cấp các quyền nào cho mã lệnh của bạn (mục 13.4, 13.5, 13.6, và 13.7). Kiểm soát sự thừa kế và chép đè thành viên bằng CAS (mục 13.8). Xem xét và xử lý chứng cứ của assembly (mục 13.9 và 13.10). Xử lý bảomật bộ thực thi bằng miền ứng dụng (mục 13.11 và 13.12). RBS cho phép bạn thực hiện các quyết định lúc thực thi (runtime decision) dựa trên định danh (identity) và các vai trò (role) của người dùng mà ứng dụng đang chạy trên danh nghĩa người dùng này. Trên hệ điều hành Windows, đây chính là việc thực hiện các quyết định dựa trên tên người dùng Windows và các nhóm Windows mà người dùng đó thuộc về . Tuy nhiên, RBS cung cấp một cơ chế bảomật chung không lệ thuộc vào hệ điều hành nằm dưới, cho phép bạn tích hợp vào bất kỳ hệ thống tài khoản người dùng nào. Các mục trong chương này thảo luận các vấn đề sau đây của .NET RBS: Tích hợp RBS với các tài khoản người dùng Windows và xác định xem một người dùng có là thành viên của một nhóm Windows nào đó hay không (mục 13.13). Kiểm soát việc truy xuất đến các chức năng của ứng dụng dựa trên người dùng hiện hành và các vai trò mà người dùng này là một thành viên (mục 13.14). Giả nhận một người dùng Windows để thực hiện các tác vụ hệ điều hành trên danh nghĩa người dùng đó (mục 13.15). Các mục liên quan đến RBS và CAS trong chương này trình bày một số công việc thông thường mà bạn sẽ cần thực hiện trong các ứng dụng, nhưng chúng chỉ mô tả một phần nhỏ trong các khả năng bảomật của .NET Framework. Để hiểu rõ hơn, bạn hãy tham khảo một quyển sách khác chuyên về bảomật trong .NET Framework. 1.1 Cho phép mã lệnh có-độ-tin-cậy-một-phần sử dụng assembly tên mạnh của bạn V V Bạn cần viết một assembly chia sẻ sao cho nó là khả truy xuất đối với mã lệnh có-độ-tin-cậy-một-phần (theo mặc định, bộ thực thi không cho phép mã lệnh có-độ-tin-cậy-một-phần truy xuất các kiểu và các thành viên nằm trong một assembly tên mạnh). # # Áp dụng đặc tính System.Security.AllowPartiallyTrustedCallersAttribute cho assembly chia sẻ của bạn. Để giảm thiểu các nguy cơ bảomật do mã lệnh nguy hiểm bày ra, bộ thực thi không cho phép các assembly có-độ-tin-cậy-một-phần truy xuất đến các assembly tên mạnh. Hạn chế này làm giảm nguy cơ mã lệnh nguy hiểm tấn công vào hệ thống của bạn, nhưng đối với một cách tiếp cận áp chế như thế cần phải có lời giải thích. Theo quy tắc, các assembly tên m ạnh được cài đặt trong Global Assembly Cache (GAC) và chứa các chức năng quan trọng được dùng chung giữa nhiều ứng dụng. Điều này hoàn toàn đúng với các assembly cấu thành thư viện lớp .NET Framework. Các assembly tên mạnh khác từ các sản phẩm được-phân-bổ-rộng-rãi cũng sẽ nằm trong GAC và là khả truy xuất đối với các ứng dụng được-quản-lý. Khả năng hiện diện trong GAC cao, tính khả truy xuất dễ dàng, và tầm quan trọng đối với nhiều ứng dụng khác nhau khiến cho các assembly tên mạnh là mục tiêu có khả năng nhất đối với bất cứ hành động phá hoại nào của mã lệnh nguy hiểm được-quản-lý. Thông thường, mã lệnh có khả năng nguy hiểm là mã được nạp từ các nơi xa—nh ư Internet—ở đó bạn có ít (hay không có) sự kiểm soát nào. Với chính sách bảomật mặc định, tất cả mã lệnh chạy từ máy cục bộ đều có độ tin cậy toàn phần (full trust), trong khi mã lệnh được nạp từ các nơi xa chỉ có độ tin cậy một phần (partial trust). Ngăn mã lệnh có-độ-tin-cậy-một-phần truy xuất đến các assembly tên mạnh; nghĩa là mã lệnh có-độ-tin- cậy-một-phầ n không có cơ hội sử dụng các tính năng của assembly cho các mục đích nguy hiểm, và không thể khảo sát assembly để tìm các lỗ hổng có thể khai thác được. Dĩ nhiên, lý thuyết này giả định rằng bạn quản lý chính sách bảomật một cách phù hợp. Nếu bạn gán tất cả mã lệnh có độ tin cậy toàn phần, không chỉ bất kỳ assembly nào cũng có thể truy xuất assembly tên mạnh của bạn, mà mã lệnh này còn có thể truy xuất tất c ả các chức năng của .NET Framework. Điều này sẽ là một tai họa bảo mật! # Nếu bạn thiết kế, hiện thực, và thử nghiệm assembly chia sẻ của bạn một cách phù hợp bằng CAS để giới hạn việc truy xuất đến các thành viên quan trọng, bạn không cần áp đặt một hạn chế bao trùm để ngăn mã lệnh có-độ-tin-cậy- một-phần sử dụng assembly của bạn. Tuy nhiên, đối với một assembly bất kỳ, không thể chứng minh rằng không có lỗ h ổng bảomật nào để mã nguy hiểm có thể lợi dụng. Do đó, bạn nên xem xét cẩn thận nhu cầu cho phép mã lệnh có- độ-tin-cậy-một-phần truy xuất assembly tên mạnh trước khi áp dụng đặc tính AllowPartiallyTrustedCallersAttribute. Bộ thực thi ngăn mã lệnh có-độ-tin-cậy-một-phần truy xuất các assembly tên mạnh bằng cách đặt LinkDemand vào tập quyền FullTrust trên mọi thành viên công-khai (public) và được-bảo-vệ (protected) của mỗi kiểu khả-truy-xuất-công-khai đượ c định nghĩa trong assembly. Điều này có nghĩa là chỉ những assembly được cấp các quyền tương đương với tập quyền FullTrust thì mới có thể truy xuất các kiểu và thành viên trong assembly tên mạnh. Việc áp dụng AllowPartiallyTrustedCallersAttribute vào assembly tên mạnh báo với bộ thực thi không buộc LinkDemand có hiệu lực trên các thành viên và các kiểu bên trong. # Bộ thực thi chịu trách nhiệm buộc các hoạt động bảomật ngầm LinkDemand có hiệu lực để bảo vệ các assembly tên mạnh; C# assembler không sinh ra các lệnh khai báo LinkDemand lúc biên dịch. Đoạn mã dưới đây trình bày một ứng dụng có sử dụng đặc tính AllowPartiallyTrustedCallersAttribute. Chú ý rằng, bạn phải sử dụng tiền tố assembly: để báo với trình biên dịch rằng đích của đặc tính này là assembly (còn được gọi là đặc tính toàn cục—global attribute). Ngoài ra, không cần thêm phần Attribute vào tên của đặc tính—mặc dù bạn có thể thêm vào nếu muốn. Vì bạn nhắm đến assembly nên đặc tính này phải được đặt sau các lệnh using mức trên, nhưng trước các khai báo không gian tên và kiểu. using System.Security; [assembly:AllowPartiallyTrustedCallers] public class AllowPartiallyTrustedCallersExample { § } Í Thực tế, tất cả các đặc tính toàn cục đều nằm trong một file độc lập với phần mã lệnh còn lại của ứng dụng. Microsoft Visual Studio .NET sử dụng cách tiếp cận này: tạo một file có tên là AssemblyInfo.cs để chứa tất cả các đặc tính toàn cục. Nếu sau khi áp dụng AllowPartiallyTrustedCallersAttribute cho assembly, bạn muốn mã lệnh có-độ-tin-cậy-một-phần chỉ gọi được một số thành viên nào đó, b ạn cần bổ sung LinkDemand cho tập quyền FullTrust trên các thành viên cần thiết, như được trình bày trong đoạn mã dưới đây: [System.Security.Permissions.PermissionSetAttribute (System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")] public void SomeMethod() { § } 1.2 Vô hiệu bảomật truy xuất mã lệnh V V Bạn cần vô hiệu CAS. # # Thiết lập thuộc tính SecurityEnabled của lớp System.Security.SecurityManager là false và lưu lại bằng phương thức SecurityManager.SavePolicy. Bạn cũng có thể sử dụng công cụ Code Access Security Policy (Caspol.exe) và thực thi lệnh caspol –s off. CAS là phần then chốt trong mô hình bảomật của bộ thực thi .NET, và cũng là phần đặc trưng của nền tảng .NET mà nhiều nền tảng khác không có. Mặc dù CAS được xây dựng với tiêu chí đảm b ảo hiệu năng thực thi cao nhất và đã được sử dụng một cách cẩn trọng trong thư viện lớp .NET, nhưng vẫn có một chi phí cho mỗi yêu cầu bảomật (security demand) và stack walk (kết quả) mà bộ thực thi phải thực hiện. Đôi lúc, bảomật mức-mã-lệnh có thể không là điều bạn bận tâm, hoặc nhu cầu hiệu năng có thể vượt quá nhu cầu CAS. Trong các trường hợp này, bạn có thể vô hiệu hoàn toàn CAS và loại bỏ chi phí cho việc kiểm tra bảomật mức-mã-lệnh. Vô hiệu CAS có tác dụng trao cho mã lệnh khả năng thực hiện bất kỳ hành động nào mà .NET Framework hỗ trợ (tương đương với t ập quyền FullTrust), bao gồm khả năng nạp mã lệnh khác, gọi các thư viện nguyên sinh, và sử dụng con trỏ để trực tiếp truy xuất bộ nhớ. # Bạn chỉ nên vô hiệu CAS vì các lý do hiệu năng sau khi đã tiêu hết tất cả các chừng mực có thể khác để đạt được các đặc điểm hiệu năng mà ứng dụng của bạn đòi hỏi. Việc lập profile cho mã lệnh thường sẽ nhận biết những vùng mà bạn có thể cải thiện đáng kể hiệu năng nhưng không phải vô hiệu CAS. Ngoài ra, bạn c ần bảo đảm các tài nguyên hệ thống đã được bảo vệ bằng các cơ chế bảomật của hệ điều hành (như Windows ACLs) trước khi vô hiệu CAS. Caspol.exe là một tiện ích được cấp cùng với .NET Framework, cho phép bạn cấu hình chính sách bảomật truy xuất mã lệnh từ dòng lệnh. Khi bạn nhập lệnh caspol –s off hoặc caspol –s on, tiện ích này sẽ xác lập thuộc tính SecurityEnabled của lớ p SecurityManager. Lớp SecurityManager cung cấp tập các phương thức tĩnh để truy xuất dữ liệu và chức năng bảomật quan trọng. Đoạn mã dưới đây trình bày cách sử dụng thuộc tính SecurityEnabled để vô hiệu và kích hoạt CAS: // Vô hiệu CAS. System.Security.SecurityManager.SecurityEnabled = false; // Lưu cấu hình. System.Security.SecurityManager.SavePolicy(); // Kích hoạt CAS. System.Security.SecurityManager.SecurityEnabled = true; // Lưu cấu hình. System.Security.SecurityManager.SavePolicy(); Để vô hiệu CAS, mã lệnh của bạn phải có phần tử ControlPolicy của System.Security.Permissions.SecurityPermission. Để kích hoạt CAS, bạn không cần phải có quyền cụ thể nào. Thay đổi SecurityEnabled sẽ không ảnh hưởng đến hoạt động của CAS trong các tiến trình hiện có, và cũng không ảnh hưởng đến các tiến trình mới cho đến khi bạn gọi phương thức SavePolicy để lưu trạng thái của SecurityEnabled vào Windows Registry. Đáng ti ếc, .NET Framework không bảo đảm những thay đổi của SecurityEnabled sẽ tác động đúng đến hoạt động của CAS trong tiến trình hiện hành. Do đó, bạn phải thay đổi SecurityEnabled rồi mở một tiến trình mới để có được hoạt động đúng như mong muốn. Hình 13.1 Registry Editor (CAS đã bị vô hiệu) # Trạng thái hiện hành của CAS (on/off) được lưu trong khóa HKEY_ LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\Security\Policy của Windows Registry. Nếu khóa này không tồn tại, mặc định CAS là on. 1.3 Vô hiệu việc kiểm tra quyền thực thi V V Bạn cần ngăn bộ thực thi kiểm tra mỗi assembly được nạp vào có quyền thực thi (execution permission) hay không. # # Thiết lập thuộc tính CheckExecutionRights của lớp System.Security. SecurityManager là false rồi lưu lại bằng phương thức SecurityManager. SavePolicy. Bạn cũng có thể sử dụng công cụ Code Access Security Policy (Caspol.exe) và thực thi lệnh caspol –e off. Mỗi khi nạp assembly, bộ thực thi bảo đảm grant-set của assembly này có chứa phần tử Execution của SecurityPermission. Bộ thực thi hiện thực một quá trình phân giải chính sách “lười” (lazy policy resolution process), nghĩa là grant-set của một assembly không được tính cho đến khi có một yêu cầu bảomật (security demand) được thực hiện trên assembly này. Việc kiểm tra quyền thực thi không chỉ buộc bộ thực thi kiểm tra mỗi assembly có quyền thực thi hay không, mà còn gián tiếp tạo ra việc phân giải chính sách đối với mỗi assembly được nạp, phủ nhận lợi ích của việc phân giải chính sách “lười”. Các yếu tố này có thể gây ra sự trì hoãn đáng kể khi các assembly được nạp, đặc biệt khi bộ thực thi nạp nhiều assembly cùng một lúc. Trong nhiều trường hợp, việc cho phép mã lệnh nạp và chạy không phải là một nguy cơ đáng kể miễn là tất cả các hoạt động và các tài nguyên quan trọng khác đã được bảo vệ bằng CAS và bằng cơ chế bảomật của hệ điều hành. Bộ thực thi .NET cho phép bạn vô hiệu việc tự động kiểm tra các quyền thực thi ngay bên trong mã lệ nh, hay bằng công cụ Caspol.exe. The image part with relationship ID rId7 was not fo und in the file. Khi bạn nhập lệnh caspol –e off hoặc caspol –e on, Caspol.exe sẽ xác lập thuộc tính CheckExecutionRights của lớp SecurityManager. Bạn có thể thực hiện công việc này bên trong mã lệnh như sau: // Vô hiệu việc kiểm tra quyền thực thi. System.Security.SecurityManager.CheckExecutionRights = false; // Lưu cấu hình. System.Security.SecurityManager.SavePolicy(); // Kích hoạt việc kiểm tra quyền thực thi. System.Security.SecurityManager.CheckExecutionRights = true; // Lưu cấu hình. System.Security.SecurityManager.SavePolicy(); Để thay đổi giá trị của CheckExecutionRights thì mã lệnh của bạn phải có phần tử ControlPolicy của SecurityPermission. Thay đổi này sẽ có tác dụng với tiến trình hiện hành ngay tức thì, cho phép bạn nạp các assembly trong lúc thực thi mà bộ thực thi không phải kiểm tra chúng có quyền thực thi hay không. Tuy nhiên, thay đổi này sẽ không ảnh hưởng đến các tiến trình hiện có. Do vậy, bạn phải lưu thay đổi vào Windows Registry (bằng phương thức SavePolicy) để nó có tác dụng với các tiến trình mớ i. . CAS (mục 13 .8). Xem xét và xử lý chứng cứ của assembly (mục 13 .9 và 13 .10 ). Xử lý bảo mật bộ thực thi bằng miền ứng dụng (mục 13 .11 và 13 .12 ). RBS. hai mô hình bảo mật bổ sung lẫn nhau (thực hiện nhiều vấn đề liên quan đến bảo mật người dùng và mã lệnh): • CAS (Code Access Security Bảo mật truy xuất