Chương 13 : Bảo mậ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ảo mậ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ảo mậ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ả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 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ảo mậ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ảo mật để nâng
cao tính bảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mật (security
demand) và stack walk (kết quả) mà bộ thực thi phải thực hiện.
Đôi lúc, bảo mậ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ảo mậ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ảo mậ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ảo mậ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ảo mậ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.