Trong chương này, tôi sẽ chỉ cho bạn làm thế nào để ngăn chặn những người ngẫu nhiên từ việc sử dụng các chức năng quản trị bằng mật khẩu bảo vệ quyền truy cập vào toàn bộ quyền điều khi
Trang 1CHƯƠNG 12
Nhóm 6b: Huỳnh Văn Thành
Ngô Nguyễn Thanh Tùng
SportsStore: An ninh & Chạm hoàn thiện
Trong chương trước, tôi đã thêm hỗ trợ cho việc quản lý các ứng dụng SportsStore, và nó sẽ không thoát khỏi sự chú ý của bạn và bất cứ ai cũng có thể sửa đổi các danh mục sản phẩm nếu tôi đã triển khai các ứng dụng như thế Tất cả họ sẽ cần phải biết rằng tính năng của quản trị viên luôn sẵn sàng bằng cách sử dụng Admin / Index URL Trong chương này, tôi sẽ chỉ cho bạn làm thế nào để ngăn chặn những người ngẫu nhiên từ việc sử dụng các chức năng quản trị bằng mật khẩu bảo vệ quyền truy cập vào toàn bộ quyền điều khiển của quản trị viên Với quyền bảo mật
đó, tôi sẽ hoàn thành các ứng dụng SportsStore bằng cách thêm vào các hỗ trợ về hình ảnh sản phẩm Điều này dường như giống với một tính năng cơ bản, nhưng nó đòi hỏi một số kĩ thuật thú
vị về MVC
Bảo mật về Quyền quản trị
Bởi vì ASP.NET MVC được xây dựng dựa trên nền tảng cốt lõi ASP.NET tôi có quyền truy cập
để xác thực và ủy quyền tính năng ASP.NET, thứ được đóng gói như là một hệ thống có mục đích chung cho việc theo dõi những người đang đăng nhập
PHÂN TÍCH VỀ TÍNH NĂNG BẢO MẬT CỦA ASP.NET Trong chương này, tôi chỉ sử dụng các tính năng bảo mật sẵn có Điều này một phần là vì những tính năng đó là nền tảng ASP.NET chứ không phải là MVC Framework và một phần nữa là vì có sẵn những cách tiếp cận khác nhau Tôi bao gồm tất cả các tính năng xác thực và
ủy quyền chi tiết trong cuốn sách Pro ASP.NET MVC 5 Platform của tôi, sẽ được Apress xuất bản vào năm 2014 Nhưng tôi không muốn bạn phải mua một cuốn sách thứ 2 để tìm hiểu về một thứ gì đó đại loại như ứng dụng bảo mật web, và chính vì thế Apress đã đồng ý gói gọn các chương bảo mật quan trọng từ cuốn Platform và phân phối chúng miễn phí từ Apress.com
Họ sẽ không sẵn sàng cho đến khi tôi viết xong cuốn sách, tất nhiên, nhưng nó là dự án tiếp theo của tôi và nó sẽ không còn xa nữa vào năm 2014 trước khi họ sẵn sàng cho phép tải xuống
Tạo một chính sách an ninh cơ bản
Tôi sẽ bắt đầu bằng cách cấu hình các hình thức xác thực, đây là một trong những cách mà người dùng có thể được xác nhận trong ứng dụng ASP.NET Trong Bảng 12-1, bạn có thể thấy những
bổ sung mà tôi đã thực hiện cho các tập tin Web.config trong dự án SportsStore.WebUI (một trong các thư mục gốc của dự án và không phải là thư mục views)
Trang 2Bảng 12-1: Cấu hình xác thực trong tập tin Web.config
Xác thực được thiết lập bằng cách sử dụng các yếu tố xác thực và tôi đã sử dụng các thuộc tính
để xác định rằng tôi muốn các hình thức xác thực, đây là loại thường được sử dụng cho các ứng dụng web trực tiếp với Internet Trong ASP.NET 4.5.1, Microsoft thêm hỗ trợ cho một phạm vi rộng lớn hơn của các tùy chọn xác thực Internet phù hợp, điều mà tôi mô tả trong cuốn Pro ASP.NET MVC 5 Platform, như đã nói ở chương trước Tôi sẽ gắn bó với hình thức xác thực bởi
vì nó vận hành tốt với người bản địa và đơn giản để thiết lập và quản lý
Chú ý: Lựa chọn thay thế chính cho các hình thức xác thực là xác thực Windows, nơi mà các
thông tin hệ điều hành được sử dụng để xác định người sử dụng và xác thực tổ chức, nơi người dùng được chứng thực bằng cách sử dụng một dịch vụ đám mây như Windows Azure Tôi sẽ không vào được một trong các tùy chọn này, vì họ không được sử dụng rộng rãi trong các ứng
Trang 3Các thuộc tính loginUrl cho thấy ASP.NET là nơi để chuyển hướng người dùng khi họ cần phải
tự xác thực (trong trường hợp này ~ / Tài khoản / URL Đăng nhập) và các thuộc tính xác định thời gian chờ của một người dùng là bao lâu một lần để họ có thể đăng nhập thành công, thể hiện trong vài phút (2880 phút là 48 giờ)
Bước tiếp theo là để nói về ASP.NET, nơi nó sẽ được chi tiết hóa ứng dụng của người dùng Tôi
đã phá vỡ điều này để tạo một bước riêng biệt vì điều đó không bao giờ được thực hiện trong một dự án thực tế: Tôi sẽ xác định một tên người dùng và mật khẩu trong tập tin web.config Bạn
có thể thấy những thay đổi trong Bảng 12-2
Bảng 12-2: Xác định tên người dùng và mật khẩu trong tập tin Web.config
Tôi muốn giữ các ví dụ đơn giản và tập trung vào cách mà MVC Framework cho phép bạn áp dụng xác thực và ủy quyền cho một ứng dụng web Nhưng việc đưa các thông tin trong tập tin Web.config là một công thức cho thảm họa, đặc biệt là nếu bạn thiết lậpcác thuộc tính
passwordFormat trên các yếu tố thông tin để Clear, nghĩa rằng mật khẩu được lưu trữ như văn bản
Cảnh báo: Không lưu trữ thông tin người dùng trong tập tin Web.config và không lưu trữ mật
khẩu dưới dạng văn bản Xem chương ngoài cuốn Pro ASP.NET MVC 5 Platform (như mô tả ở phần đầu của phần này) để biết chi tiết về quản lý người dùng thông qua một cơ sở dữ liệu Mặc dù không thích hợp cho các dự án thực tế, bằng cách sử dụng các tập tin Web.config để lưu trữ thông tin cho phép tôi tập trung vào các tính năng MVC mà không bị chệch hướng vào các khía cạnh của nền tảng cốt lõi ASP.NET Kết quả của việc bổ sung vào file Web.config là tôi có một tên người dùng mã hóa cứng (admin) và mật khẩu (bí mật)
Áp dụng Quyền sở hữu với bộ lọc
MVC Framework có một tính năng mạnh mẽ được gọi là bộ lọc Đây là những thuộc tính NET
mà bạn có thể áp dụng cho một phương pháp hành động hoặc một lớp điều khiển và họ có thể giới thiệu những bổ sung logic khi yêu cầu được xử lý để thay đổi hành vi của các MVC
Framework
Trang 4Có nhiều loại khác nhau của các bộ lọc có sẵn và bạn có thể tạo các bộ lọc tùy chỉnh của riêng bạn, như tôi đã giải thích trong Chương 18 Các bộ lọc mà tôi quan tâm vào lúc này là bộ lọc cho phép mặc định, Authorize Trong Bảng 12-3, bạn có thể thấy tôi đã áp dụng bộ lọc này cho bộ điều khiển quản trị
Bảng 12-3: Thêm thuộc tính quyền sở hữu vào tập tin AdminControl.cs
Khi áp dụng mà không có tham số, thuộc tính ủy quyền cho phép truy cập đến các phương pháp điều khiển hành động cho tất cả người dùng xác thực Điều này có nghĩa là nếu bạn được chứng thực, bạn được phép tự động sử dụng các tính năng quản trị Điều này tốt cho SportsStore, nơi chỉ có một tập hợp các phương pháp hành động bị hạn chế và chỉ có một người dùng
Chú ý: Bạn có thể áp dụng các bộ lọc với phương pháp hành động cá nhân hoặc với bộ điều
khiển Khi bạn áp dụng bộ lọc với bộ điều khiển, nó hoạt động như là bạn đã áp dụng nó cho mọi phương thức hành động trong lớp điều khiển Trong Ví dụ 12-3, tôi áp dụng các bộ lọcủuy quyền đến các lớp, vì vậy tất cả các phương pháp hành động trong bộ điều khiển quản trị chỉ dành cho những người dùng xác thực
Bạn có thể thấy những hiệu ứng mà bộ lọc ủy quyền có bằng cách chạy các ứng dụng và điều hướng đến / Admin / Index URL Bạn sẽ thấy một lỗi tương tự như trong Hình 12-1
Trang 5Hình 12-1: Hiệu ứng của bộ lọc ủy quyền
Khi bạn cố gắng truy cập vào các phương pháp hành động Index của bộ điều khiển quản trị, các MVC Framework phát hiện bộ lọc ủy quyền Bởi vì bạn đã không được chứng thực, bạn được chuyển hướng đến URL được chỉ định trong Web.config phần hình thức xác thực: / Account / Login Tôi đã không tạo bộ điều khiển Account (đó là những gì gây ra lỗi như trong hình), nhưng thực tế là các MVC Framework đã cố gắng chuyển hướng yêu cầu cho thấy bộ lọc ủy quyền đang làm việc
Tạo các nhà cung cấp xác thực
Sử dụng tính năng xác thực yêu cầu cuộc gọi đến hai phương pháp tĩnh của lớp
System.Web.Security.FormsAuthentication:
Các phương pháp xác nhận thông tin được cung cấp bởi người sử dụng
Phương pháp SetAuthCookie thêm một cookie để đáp ứng các trình duyệt, do đó người dùng không cần phải xác thực mỗi khi họ thực hiện một yêu cầu
Vấn đề với phương thức gọi tĩnh từ bên trong phương thức hành động làm cho đơn vị kiểm tra
bộ điều khiển khó khăn: mocking frameworks thường chỉ mock các thành viên nhất định Các lớp bao gồm các MVC Framework đã được thiết kế với các thử nghiệm trong đầu, nhưng lớp FormsAuthentication ra trước khi thiết kế thử nghiệm thân thiện của MVC
Trang 6Cách tốt nhất để giải quyết vấn đề là tách các bộ điều khiển từ phương pháp tĩnh bằng cách sử dụng một giao diện, trong đó cung cấp các lợi ích bổ sung rằng điều này phù hợp với các mẫu thiết kế MVC rộng hơn và làm cho nó dễ dàng hơn để chuyển sang hệ thống xác thực khác nhau sau này
Tôi bắt đầu bằng cách xác định các giao diện của nhà cung cấp chứng thực Tạo một thư mục mới có tên gọi Abstract trong tập tin Infrastructure của dự án SportsStore.WebUI và thêm một giao diện mới gọi là IAuthProvider Nội dung của giao diện này được hiển thị trong Bảng 12-4
Bảng 12-4: Nội dung của tập tin IAuthProvider.cs
Bây giờ tôi có thể tạo ra một thực hiện của giao diện này hoạt động như bao phủ xung quanh các phương thức tĩnh của lớp FormsAuthentication Tạo một thư mục mới trong Infrastucture – được gọi là thời gian Concrete - và tạo ra một lớp mới gọi là FormsAuthProvider Nội dung của lớp này được hiển thị trong Bảng 12-5
Bảng 12-5: Nội dung của tập tin FormsAuthProvider.cs
Chú ý: Bạn sẽ thấy một cảnh báo từ Visual Studio là phương pháp có
FormsAuthentication.Authenticate bị phản đối Đây là một phần trong nỗ lực liên tục của
Microsoft để hợp lý hóa bảo mật người dùng, đó là một khu vực hóc búa cho bất kỳ ứng dụng
Trang 7Việc thực hiện các phương pháp Authenticate gọi phương pháp FormsAuthentication tĩnh mà tôi muốn để tách ra bộ điều khiển Bước cuối cùng là đăng ký FormsAuthProvider trong phương pháp AddBindings của lớp NinjectDependencyResolver, như thể hiện trong Bảng 12-6
Bảng 12-6: Đăng ký nhà cung cấp xác thực trong tập tin NinjectDependencyResolver.cs
Trang 8Tạo Bộ điều khiển tài khoản
Nhiệm vụ tiếp theo là tạo ra bộ điều khiển tài khoản và phương pháp hành động Login được nêu trong tập tin Web.config Thực tế, tôi sẽ tạo ra hai phiên bản của phương pháp Login Việc đầu tiên sẽ đưa ra một quan điểm có chứa một dấu nhắc đăng nhập, và một phần khác xử lý các yêu cầu POST khi người dùng gửi các thông tin của họ
Để bắt đầu, tôi tạo ra một lớp mà tôi sẽ đi qua giữa bộ điều khiển và giao diện Thêm một tập tin lớp mới gọi là LoginViewModel.cs vào thư mục Models của dự án SportsStore.WebUI và chỉnh sửa nội dung để nó phù hợp với Bảng 12-7
Bảng 12-7: Nội dung của tập tin LoginViewModel.cs
Lớp này chứa các thuộc tính cho tên người dùng và mật khẩu, và sử dụng dữ liệu chú thích các thuộc tính để xác định rằng giá trị cho cả hai được yêu cầu Cho rằng chỉ có hai thuộc tính, bạn
có thể bị cám dỗ để làm mà không có một mô hình điểm và dựa trên ViewBag để truyền dữ liệu
để xem Tuy nhiên, nó là tốt cho việc thực hành để xác định xem các mô hình của các dữ liệu được truyền từ các bộ điều khiển đến giao diện và từ các mô hình ất kết dính để các phương pháp hành động được viết một cách nhất quán
Tiếp theo, tôi tạo ra bộ điều khiển tài khoản sẽ xử lý xác thực Tạo một tập tin lớp mới gọi là AccountController.cs trong thư mục Controllers và chỉnh sửa nội dung tập tin để phù hợp với Bảng 12-8
Trang 9Bảng 12-8: Nội dung của tập tin AccountController.cs
Tạo Giao diện
Để tạo ra giao diện thì nó sẽ yêu cầu người dùng cho thông tin của họ, tạo ra các thư mục Views / Account trong thư mục SportsStore.WebUI Nhấp chuột phải vào thư mục mới, chọn Thêm → MVC 5 View Page (Razor) từ menu, đặt tên để đăng nhập và nhấn OK để tạo ra các tập tin Login.cshtml Chỉnh sửa nội dung của tập tin mới để phù hợp với Bảng12-9
Trang 10Bảng 12-9: Nội dung của File Login.cshtml
Giao diện này sử dụng cách bố trí _AdminLayout.cshtml và lớp Bootstrap để tạo kiểu nội dung Không có kỹ thuật mới trong giao diện này, khác hơn so với việc sử dụng các phương thức helper Html.PasswordFor, phương thức mà tạo ra một yếu tố đầu vào mà thuộc tính được thiết lập mật khẩu Tôi mô tả phương pháp helper hoàn chỉnh của HTML trong Chương 21 Bạn có thể thấy cách giao diện xuất hiện bằng cách bắt đầu ứng dụng và điều hướng đến các URL / Admin / Index, như thể hiện trong Hình 12-2
Trang 11Hình 12-2: Giao diện đăng nhập
Thuộc tính Required mà tôi áp dụng cho các thuộc tính của các mô hình giao diện được thực thi bằng cách sử dụng xác nhận phía máy khách (Hãy nhớ rằng các thư viện JavaScript cần có trong
bố trí _AdminLayout.cshtml tạo ra trong chương trước.) Người dùng có thể gửi mẫu chỉ sau khi
họ đã cung cấp cả tên người dùng và mật khẩu, và việc chứng thực được thực hiện tại máy chủ khi tôi gọi phương thức FormsAuthentication.Authenticate
Cảnh báo: Nói chung, sử dụng dữ liệu xác nhận phía khách hàng là một ý tưởng tốt Nó giảm tải một số công việc từ máy chủ của bạn và cung cấp cho người sử dụng thông tin phản hồi ngay lập tức về những dữ liệu mà họ đang cung cấp Tuy nhiên, bạn không nên bị cám dỗ để thực hiện chứng thực tại khách hàng, vì điều này sẽ thường liên quan đến việc gửi thông tin hợp lệ cho khách hàng để họ có thể được sử dụng để kiểm tra tên người dùng và mật khẩu mà người dùng
đã nhập, hoặc ít nhất là tin tưởng vào báo cáo của khách hàng cho dù họ đã được xác thực thành công Xác thực luôn luôn phải được thực hiện tại máy chủ
Trang 12Khi tôi nhận được thông tin xấu, tôi thêm một lỗi cho ModelState và trả lại giao diện Điều này gây ra một thông điệp tới hiển thị trong khu vực chung, mà tôi tạo ra bằng cách gọi phương thức helper Html.ValidationSummary trong giao diện Điều này sẽ chăm sóc bảo vệ các chức năng quản lý của SportsStore Người dùng sẽ được phép truy cập vào các tính năng này chỉ sau khi họ
đã cung cấp thông tin hợp lệ và nhận được một cookie đó sẽ được gắn liền với yêu cầu tiếp theo
UNIT TEST: XÁC THỰC
Kiểm tra Bộ điều khiển Tài khoản yêu cầu tôi phải kiểm tra hai hành vi: một người sử dụng nên được xác nhận khi cung cấp thông tin hợp lệ và người dùng không nên được xác nhận khi các thông tin được cung cấp không hợp lệ Tôi thực hiện những thử nghiệm này bằng cách triển khai thực hiện mô hình của giao diện IAuthProvider và kiểm tra các loại giao diện và tính chất của các kết quả của bộ điều khiển Login Tôi tạo ra các thử nghiệm sau đây trong một tập tin kiểm tra mới gọi là AdminSecurityTests.cs:
Trang 13Tải ảnh lên
Tôi sẽ hoàn thành trải nghiệm người dùng SportsStore với một cái gì đó phức tạp hơn một chút: Tôi sẽ thêm khả năng cho quản trị để tải lên hình ảnh sản phẩm và lưu trữ chúng trong cơ sở dữ liệu để họ được hiển thị trong danh mục sản phẩm Đây không phải làmột cái gì đó đặc biệt thú
vị hay hữu dụng theo đúng nghĩa của nó, nhưng nó cho phép tôi để chứng minh một số tính năng Framework MVC
Mở rộng cơ sở dữ liệu
Mở cửa sổ Visual Studio Server Explorer và điều hướng đến bảng Products trong cơ sở dữ liệu được tạo ra trong Chương 7 Các tên của kết nối dữ liệu có thể thay đổi được EFDbContext, đó
là tên được gán cho kết nối trong file Web.config Visual Studio có một chút không phù hợp khi
nó đặt lại tên cho kết nối, vì vậy bạn cũng có thể thấy tên ban đầu được xuất hiện khi kết nối đã được tạo ra Nhấp chuột phải vào bảng Products và chọn New Query từ menu pop-up và nhập vào SQL sau vào vùng văn bản:
Trang 14ALTER TABLE [dbo] [Products]
ADD [imageData] VARBINARY (MAX) NULL,
[ImageMimeType] VARCHAR (50) NULL;
Nhấn vào nút Execute (được đánh dấu bằng một mũi tên) ở mặt trên cùng bên trái của cửa sổ và Visual Studio sẽ cập nhật cơ sở dữ liệu, thêm hai cột mới vào bảng Để kiểm tra các cập nhật, nhấn chuột phải vào bảng Products trong cửa sổ Server Explorer và chọn Open Table Definition
từ menu Bạn sẽ thấy rằng hiện nay có các cột gọi là imageData và ImageMimeType, như thể hiện trong Hình 12-3
Hình 12-3: Thêm cột vào cơ sở dữ liệu Mẹo: Nếu các cột không nhìn thấy được, đóng cửa sổ thiết kế, kích chuột phải vào kết nối dữ
liệu trong cửa sổ Server Explorer và chọn Refresh từ trình đơn Các cột mới có thể nhìn thấy khi bạn chọn menu Open Table Definition một lần nữa
Tăng cường Domain Model
Tôi cần phải thêm hai miền mới để các lớp sản phẩm trong dự án SportsStore.Domain tương ứng với các cột cơ sở dữ liệu mới, như trong Bảng 12-10