CỘNG ĐỒNG CÔNG NGHỆ THÔNG TIN VIỆT NAM VIETNETWORK.VN

Bảo mật ASP.NET

0 Thành viên và 1 Khách đang xem chủ đề.

Ngủ rồi CCNACCNP

  • Hero Member
  • *****
    • Bài viết: 3980
    • Số Lần: +73/-0
Bảo mật vốn là chủ đề cực kỳ phức tạp và bảo mật trong ASP.NET cũng không phải ngoại lệ. Các lập trình viên .NET chắc hẳn cũng đã quen thuộc với những khó khăn gặp phải khi tìm kiếm tài liệu tiếng Việt trong lĩnh vực này. Hôm nay, Quản Trị Mạng xin giới thiệu nôi dung chương 9, chương về Bảo mật ASP.NET trong cuốn “ASP.NET in a Nutshell” của hai tác giả Andrew Duthie và Matthew MacDonald, nhà xuất bản O’Reilly. 


Trong chương này, chúng ta sẽ đề cập đến một số phương thức giúp đảm bảo an toàn cho các ứng dụng ASP.NET. Để nhấn mạnh vào nội dung trọng tâm của chương, chúng ta sẽ không bàn về bảo mật mạng, bảo mật máy chủ và bảo mật cơ sở hạ tầng ASP.NET. Nói như thế không có nghĩa là các chủ đề đó không quan trọng. Ngược lại, nếu không cấu hình hỗ trợ bảo mật phù hợp cho máy chủ và cơ sở hạ tầng mạng, những gì cố gắng thực hiện để đảm bảo an toàn cho ứng dụng ASP.NET thông qua các công cụ .NET Framework cung cấp sẽ trở nên vô ích. Tuy nhiên, nằm trong phạm vi giới hạn của một chương nên chúng ta chỉ đi sâu vào vấn đề bảo mật các chương trình ứng dụng ASP.NET. 

Sự quan trọng của bảo mật không lời nào nói hết. Nếu không đầu tư thời gian cũng như tài nguyên thích đáng cho nhiệm vụ này có thể dẫn tới những kết quả không mong muốn như thất thoát dữ liệu, sai hỏng trong thực thi ứng dụng hoặc ứng dụng bị chiếm quyền điều khiển và giảm doanh thu lợi nhuận của doanh nghiệp, làm cho doanh nghiệp bị mất uy tín với khách hàng. Xem xét vấn đề bảo mật ngay từ khi bắt đầu xây dựng ứng dụng cũng là điều hết sức quan trọng.

Đảm bảo an toàn trong truy cập ứng dụng hay truy cập tài nguyên thuộc ứng dụng tập trung vào hai quá trình: thẩm định (authentication) và cấp phép (authorization). Chúng ta sẽ quan tâm tới ba phương thức thẩm định mà bộ thực thi ASP.NET cung cấp: Windows, Form và Passport. Còn với cấp phép, chúng ta sẽ thảo luận chủ yếu về hai cơ chế: sử dụng đường dẫn URL và  sử dụng danh sách điều khiển truy cập ACL. 

9.1. Các phương thức thẩm định 

Thẩm định (authentication) là quá trình nhận dạng người hay chương trình đưa ra yêu cầu. Nó không gán quyền truy cập tài nguyên (là chức năng của cơ chế cấp phép) mà kiểm tra định danh đã biết để đưa ra quyết định xem liệu có chấp nhận yêu cầu này hay không. Nói một cách đơn giản, thẩm định trả lời cho câu hỏi: “Bạn là ai?”.

Trong ứng dụng ASP cổ điển, có hai phương thức thẩm định chính: một là dựa trên IIS để thẩm định người dùng theo tài khoản Windows, sau đó sử dụng các danh sách điều khiển truy cập (ACL) NT để hoàn tất quá trình thẩm định; hai là đưa ra kiểu thẩm định riêng, so sánh để khớp với thông tin thẩm định người dùng lưu trữ trên máy chủ (có thể nằm trong Microsoft Active Directory). Mỗi phương thức đều có những điểm hạn chế riêng. Mô hình an toàn nhất của thẩm định Windows, Intergrated Security, đòi hỏi tất cả người dùng phải sử dụng Internet Explorer và không làm việc với quá nhiều proxy server. Còn phương thức thẩm định riêng đòi hỏi phải tự xây dựng và kiểm tra một lượng lớn công việc.

ASP.NET cung cấp ba cơ chế thẩm định:

Thẩm định Windows

Cung cấp tính năng tương tự như thẩm định IIS trong ASP cổ điển, tuy nhiên cũng có một số điểm khác nhau quan trọng. Thẩm định Windows làm việc cùng với thẩm định tích hợp sẵn trong IIS và dùng định danh do thẩm định IIS cung cấp để thực hiện quá trình thẩm định.

Thẩm định Forms

Chủ yếu được dùng cho cơ chế thẩm định riêng. Thẩm định Form hỗ trợ trang đăng nhập chung, cung cấp nhiều tuỳ chọn về lưu trữ thông tin thẩm định, từ cơ sở dữ liệu với định dạng XML, file cấu hình và một số phương thức trợ giúp để quản lý các hoạt động thẩm định. Cơ chế thẩm định này hầu hết được dùng cho các trường hợp liên quan đến Internet.

Thẩm định Passport

Cho phép các nhà phát triển ASP.NET sử dụng kỹ thuật tiên tiến trong giải pháp đăng nhập đơn Passport của Microsoft.

Cơ chế thẩm định ASP.NET thường được cấu hình ở mức máy, dùng file machine.config hoặc mức ứng dụng, dùng file web.config. Chúng ta có thể cấu hình các thiết lập thẩm định sử dụng phần tử <authentication> cùng với các thuộc tính và phần tử con của nó.

Các thiết lập thẩm định không được phép cấu hình bên dưới mức ứng dụng. Tức là nếu muốn áp dụng quy chế thẩm định cho thư một mục con của một ứng dụng, chúng ta cần phải cấu hình nó như một ứng dụng trong IIS. Các thiết lập cấp phép (authorization) không gặp phải hạn chế này.

9.1.1. Thẩm định Windows

Như đã đề cập tới ở trên, thẩm định Windows có chức năng giống như thẩm định IIS trong ASP cổ điển. Thẩm định IIS sử dụng thông tin tài khoản người dùng lưu trữ trên server cục bộ hoặc Domain Controller và đưa nhân dạng người dùng vào bộ thực thi ASP.NET để dùng cho quá trình thẩm định. Lý do chính để chọn thẩm định Windows là bởi nó cần lượng mã triển khai thấp nhất. Trong ba cơ chế thẩm định ASP.NET cung cấp, chỉ có thẩm định Windows đòi hỏi phải cấu hình IIS cho các thiết lập thẩm định trong file machine.config hoặc web.config.

Giống như thẩm định IIS trong ASP, thẩm định Windows chủ yếu được dùng trong các trường hợp:

    Tất cả client đều dùng Internet Explorer 4.0 hoặc cao hơn và không có quá nhiều proxy server, chủ yếu phổ biến ở các mạng Intranet, không mấy khi gặp trong các ứng dụng Internet.
    Yêu cầu bảo mật trong ứng dụng ở mức thấp, chỉ đòi hỏi thẩm định IIS Basic hoặc Digest (cả hai đều có hạn chế là kém an toàn hơn so với bảo mật hợp nhất).
    Yêu cầu bảo mật không cho phép người dùng nặc danh truy cập toàn bộ ứng dụng.

Thẩm định Windows chủ yếu được dùng cùng với impersonation (tức một ngữ cảnh bảo mật cụ thể). Chúng ta có thể giới hạn quyền truy cập tài nguyên bằng cách dùng Danh sách điều khiển truy cập NTFS  (NTFS ACL) hoặc gán quyền truy cập cơ sở dữ liệu cho từng tài khoản Windows của người dùng khi đăng nhập vào cơ sở dữ liệu.

Thẩm định Windows hoạt động theo nguyên tắc sử dụng ngữ cảnh bảo mật của người dùng lấy ra từ IIS. Bước đầu tiên trong cấu hình một ứng dụng để sử dụng thẩm định Windows là phải thay đổi các thiết lập cấu hình IIS để nó đáp ứng được một trong các phương thức thẩm định không nặc danh. Chúng ta có thể thực hiện như sau:

    Mở Internet Services Manager.
     
    Ở khung bên trái, trỏ chuột xuống website hoặc thư mục gốc ảo muốn cấu hình.
     
    Kích phải chuột lên thư mục muốn cấu hình và chọn Properties để hiển thị hộp thoại thuộc tính <application name>.
     
    Bấm chọn thẻ Directory Security, sau đó là nút Edit trong phần “Anonymous access and authentication control” (Điều khiển thẩm định và truy cập nặc danh).
     
    Bỏ dấu chọn ở ô “Anonymous access” và đặt dấu chọn cho một hay nhiều cơ chế thẩm định (Basic, Digest, Integrated Windows).
     
    Bấm OK để đóng hộp thoại phương thức thẩm định lại, sau đó bấm OK lần nữa để đóng hộp thoại Properties. Bây giờ chúng ta có đủ điều kiện để cấu hình ứng dụng ASP.NET.

Có ba mức độ trong thẩm định Windows là Basic, Digest và Integrated. Trong đó thẩm định Windows Basic là mức cơ bản nhất. Nó cho phép sử dụng các tài khoản Windows ở nhiều trường hợp hơn nhưng thông tin username, password được gửi đi dưới dạng văn bản thuần tuý. Đây là điểm cực kỳ nguy hiểm, nhất là khi ứng dụng không dùng cơ chế mã hoá Secure Sockets Layer (SSL) để bảo vệ các hoạt động truyền thông. Chọn mức Basic thường có nhiều rủi ro hơn so với các mức khác.

Tương tự, mức Digest đòi hỏi mật khẩu phải được lưu trữ ở dạng văn bản thuần tuý trên Domain Controller, nơi chứa các tài khoản. Khi dùng thẩm định Digest, chúng ta phải cẩn thận với các cuộc tấn công mạng lên Domain Controller và phải đảm bảo an toàn về mặt vật lý trước các nhóm xâm nhập trái phép có thể truy cập để lấy cắp thông tin mật khẩu.

Như trên sơ đồ, trình tự của quá trình thẩm định Windows bắt đầu khi máy khách gửi yêu cầu tới máy chủ. IIS sẽ thẩm định thông tin trên máy khách, sau đó đưa yêu cầu tới bộ thực thi của ASP.NET trong đó có cả ngữ cảnh bảo mật, ASP.NET sử dụng ngữ cảnh bảo mật, kiểm tra các yếu tố như ACL… và đáp ứng yêu cầu của client.

Để ASP.NET sử dụng ngữ cảnh bảo mật do IIS cung cấp, ứng dụng ASP.NET phải được cấu hình cơ chế thẩm định Windows. Cấu hình này được thực hiện bằng cách thêm phần tử  <authentication> vào file  web.config của ứng dụng và thiết lập thuộc tính mode là Windows, có thể viết như sau:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.web>
      <authentication mode="Windows"/>
      <!--
         Other configuration elements
      -->
   </system.web>
</configuration>

Do yếu tố <authentication> không đòi hỏi bất kỳ phần tử con nào cho mô hình Windows, nên chúng ta có thể dùng một thẻ đơn với dấu đóng “/” thay vì một thẻ đóng đầy đủ. 

9.1.1.1 Impersonation 

Impersonation là thực tế của mã nguồn chạy trong ngữ cảnh bảo mật của một tài khoản cụ thể. Trong ASP.NET, impersonation được dùng để cho phép mã chương trình của ứng dụng được thực thi ở ngữ cảnh bảo mật cụ thể của người dùng đã qua thẩm định. 

Mặc định, chương trình thực thi ASP.NET chạy trong ngữ cảnh của một tài khoản đặc biệt gọi là ASPNET. Tài khoản này có rất ít đặc quyền. Vì thế các yêu cầu về tài nguyên bảo vệ bởi Danh sách điều khiển truy cập (ACL) (chẳng hạn như file trong file hệ thống) sẽ thất bại, trừ phi tài khoản ASPNET được gán đặc quyền tường minh. Cơ chế này giúp các ứng dụng ASP.NET an toàn hơn. 

Khi gán đặc quyền tường minh cho tài khoản ASPNET, tài khoản sẽ có mức ưu tiên cao, cho phép nhiều kiểu yêu cầu được thực hiện thành công mà không cần dùng đến impersonation. Ví dụ, SQL Sever mặc định cho phép truy cập bất cứ người dùng nào trong nhóm quản trị cục bộ (local administrator) chạy bộ thực thi ASP.NET với vai trò SYSTEM, làm cho nó có thể kết nối tới một cơ sở dữ liệu SQL Sever cục bộ sử dụng một kết nối đáng tin cậy mà không cần dùng impersonation. 

Chạy hệ thống với vai trò SYSTEM có thể giải quyết được một số vấn đề về đặc quyền nhưng không phải là một ý tưởng hay. Bởi vì nó cung cấp nhiều đặc quyền hơn mức cần thiết cho hầu hết các ứng dụng ASP.NET. Khi đó, bất kỳ lỗ hổng nào cũng có thể xuất hiện trong IIS hoặc bộ thực thi ASP.NET có thể sẽ cung cấp khả năng truy cập mức hệ thống cho những người khai thác chúng, bất kể hợp pháp hay trái phép. Chạy bộ thực thi ASP.NET sử dụng tài khoản ASPNET làm giảm đáng kể các mối nguy hiểm như một cuộc khai thác lỗ hổng chẳng hạn.

(Thiết lập này được điều khiển bởi thuộc tính username của phần tử <processModel> trong machine.config).

Trong hầu hết mọi trường hợp sử dụng thẩm định Windows, impersonation được dùng để cho phép bộ thực thi ASP.NET đáp ứng yêu cầu (có tính đến ngữ cảnh bảo mật) cho người dùng đã qua thẩm định. Trong ASP cổ điển, impersonation được dùng mặc định. Chúng ta có thể cho phép impersonation trong ASP.NET bằng cách thêm phần tử <identity> vào file web.config của ứng dụng, thuộc tính impersonate phải được thiết lập là True, như đoạn mã bên dưới:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.web>
      <authentication mode="Windows"/>
      <identity impersonate="true"/>
      <!--
         Other configuration elements
      -->
   </system.web>
</configuration>

Sau khi impersonation được cho phép, chúng ta có thể dùng NTFS ACL (danh sách điều khiển truy cập NTFS) để thẩm định tài khoản cho yêu cầu truy cập tài nguyên. 

9.1.2 Thẩm định Forms

Thẩm định Forms được đánh giá là phương thức hữu ích nhất trong ba phương thức ASP.NET cung cấp. Nó cung cấp một cơ sở hạ tầng rất linh hoạt cho các ngữ cảnh bảo mật tự người dùng định nghĩa. Khi một ứng dụng được cấu hình để dùng thẩm định Forms, các yêu cầu về tài nguyên được bảo vệ sẽ được chuyển tới một trang đăng nhập cụ thể, ngoại trừ yêu cầu có gắn kèm mã thông báo thẩm định nằm trong một cookie.

9.1.2.1. Đăng nhập (Log in)

Trong trang đăng nhập, trình phát triển website sẽ viết mã kiểm tra thông tin thẩm định do người dùng nhập vào xem có khớp với thông tin sao lưu ở vùng lưu trữ trên máy chủ hay không. Vùng lưu trữ này có thể là một cơ sở dữ liệu quan hệ như SQL Sever, một file XML, Microsoft Active Directory hoặc bất kỳ nơi lưu trữ nào khác do chúng ta chọn. Nếu thông tin người dùng gửi đi khớp với thông tin lưu trữ trên server, trình thực thi sẽ gọi phương thức RedirectFromLoginPage của lớp trợ giúp FormsAuthentication để gửi trở lại cho người dùng trang web họ yêu cầu kèm theo một cookie nhất thời hoặc một cookie lâu dài có chứa mã thông báo thẩm định trên máy người dùng. Khi người dùng đã được thẩm định, họ được quyền truy cập tới các vùng khác trên ứng dụng đó mà không cần đăng nhập lại.

Để minh hoạ rõ hơn cho tiến trình hoạt động của cơ chế thẩm định Form, chúng ta hãy xét một ví dụ.

Ví dụ sử dụng các file sau: 

web.config
File cấu hình, dùng để cho phép cơ chế thẩm định Forms và mô tả giới hạn truy cập mong muốn.

Login.aspx
Trang đăng nhập của ứng dụng, nhận thông tin thẩm định của người dùng và, nếu thông tin đó hợp lệ thì chuyển hướng người dùng tới đường dẫn URL được yêu cầu.

Register.aspx
Trang đăng ký của ứng dụng. Cho phép người dùng chưa đăng ký chọn thông tin thẩm định để truy cập ứng dụng.

Logout.aspx
Xoá sạch mọi cookie thẩm định Form, đưa người dùng thực sự ra ngoài vùng bảo mật của ứng dụng.

Users.xml
File XML, chứa thông tin thẩm định của người dùng đã đăng ký. Mật khẩu được lưu trữ dưới dạng các xâu ký tự hàm băm SHA1. 

Để sử dụng cơ chế thẩm định Form, ứng dụng phải được cấu hình với file web.config như trong Hình 9-1, được đặt ở phần gốc của ứng dụng. 

Ví dụ 9-1: File web.config cho thẩm định Form 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <location path="files">
      <system.web>
         <authorization>
            <deny users="?"/>
         </authorization>
      </system.web>
   </location>
   <system.web>
      <authentication mode="Forms">
         <forms name=".ASPNETIAN"
           loginUrl="Login.aspx"
            protection="All"
            timeout="60" />
      </authentication>
   </system.web>
</configuration>

Phần tử <authentication> ở trong ví dụ 9-1 cấu hình ứng dụng sử dụng thẩm định Forms. Con của nó, <forms>, cung cấp một số yếu tố bảo mật cơ sở: một tên cho cookie thẩm định Forms (.ASPNETIAN), kiểu bảo vệ (mã hoá, kiểm tra tính hợp lệ, tất cả hoặc không có gì) cho cookie thẩm định, vòng thời gian cho cookie (ví dụ ở đây là 60 giây, mặc định là 30 giây) và một trang đăng nhập cho người dùng không qua thẩm định. Chú ý là, trong ví dụ chúng ta có dùng file Login.aspx, nên mặc định chúng ta sẽ bỏ qua thuộc tính này. 

(Trong phiên bản v1.1 của .NET Framework có hai thuộc tính mới của phần tử <forms> được thêm vào là RequireSslvà SlidingExpiration).

Phần tử <authorization>, gắn chặt với thư mục con files qua sử dụng thẻ <location>, từ chối truy cập của bất kỳ người dùng nặc danh nào. 

Với cấu hình phù hợp, nếu người dùng chưa có một cookie thẩm định, yêu cầu tới bất kỳ file nào trong thư mục con files (được cho là do ASP.NET điều khiển) cũng sẽ đưa người dùng đến trang đăng nhập. Nhưng chuyện gì sẽ xảy ra khi kiểu file mà bạn muốn bảo vệ không phải do ASP.NET điều khiển mặc định? Khi đó, chúng ta có thể thực hiện các bước sau để thêm kiểu file vào cấu hình IIS cho ứng dụng: 

    Mở Internet Services Manager và xác định vị trí file bạn muốn cấu hình.
     
    Kích phải chuột lên biểu tượng của file và chọn Properties.
     
    Trong hộp thoại Properties, chọn thẻ Directory (hoặc Home Directory) và kích vào nút Configuration.
     
    Trên thẻ App Mappings, bấm nút Add.
     
    Trong hộp thoại Add/Edit Application Extension Mapping, bấm vào nút Browse và tạo đường dẫn tới vị trí thư mục aspnet_isapi.dll. Thông thường thì vị trí này có dạng %windir%\Microsoft.NET\Framework\%version%\, trong đó %version% là phiên bản .NET Framework. Có thể chúng ta sẽ cần thay đổi thuộc tính Files of type từ drop-down thành *.dll. Sau đó bấm chọn file và kích vào Open.
     
    Bây giờ nhập tên mở rộng cho file (chẳng hạn như .zip) hoặc nhập .* để gắn tất cả kiểu file hỗ trợ trong ASP.NET.
     
    Ấn OK để lưu lại các thay đổi và đóng từng hộp thoại.
     
    Lặp lại các bước nếu muốn thêm một kiểu file khác vào.

Chú ý: Sử dụng ký tự .* để ánh xạ tất cả các kiểu file có trong ASP.NET là cách dễ dàng và nhanh chóng để bảo vệ tất cả các kiểu file này trong ứng dụng sử dụng cơ chế thẩm định Forms. Tuy nhiên, chúng ta không nên dùng kỹ thuật này nếu ứng dụng có chứa nhiều file, như các trang ASP cổ điển điều khiển bởi một ứng dụng ISAPI khác. Bởi vì .* sẽ đưa ra quyền ưu tiên và khiến các kiểu file này không hoạt động đúng như mong đợi. 

Sau khi tất cả các các kiểu file đã được đưa vào trình điều khiển ASP.NET, bất kỳ yêu cầu nào đưa ra về một trong các kiểu file đó trong thư mục con files cũng sẽ khiến người dùng được chuyển đến file Login.aspx nếu họ chưa có một cookie thẩm định Forms cho ứng dụng này. Phần mã cho Login.aspx được minh hoạ ở ví dụ 9-2 bên dưới: 
Ví dụ 9-2. Login.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Web.Security" %>
<html>
<head>
<title>Login Page</title>
<script runat="server">
   Sub Login_Click(Sender As Object, e As EventArgs)
      Dim LoginDS as DataSet
      If Cache("LoginDS") Is Nothing Then
         LoginDS = New DataSet( )
         LoginDS.ReadXml(Server.MapPath("Users.xml"))
         Cache.Insert("LoginDS", LoginDS, _
            New CacheDependency(Server.MapPath("Users.xml")))
      Else
         LoginDS = Cache("LoginDS")
      End If
      If LoginDS.Tables(0).Select("Email='" & _
         Email.text & "'").Length > 0 Then
         Dim LoginRow( ) As DataRow = LoginDS.Tables(0).Select("Email='" _
            & Email.text & "'")
         If LoginRow(0).Item("Password").ToString = _
            FormsAuthentication.HashPasswordForStoringInConfigFile( _
            Password.Text, "SHA1") Then
            FormsAuthentication.RedirectFromLoginPage( _
            Email.Text, Persist.Checked)
         Else
            Message.Text = "Incorrect Password!"
         End If
      Else
         Message.Text = "Email not found. Have you " & _
            "<a href='register.aspx?page=" & _
            Server.UrlEncode(Request.RawUrl) & "'>registered[/url]?"
      End If
   End Sub
</script>
</head>
<body>
   <form runat="server">
      <table border="0">
         <tr>
            <td>Email: </td>
            <td><asp:textbox id="Email" runat="server"/></td>
         </tr>
         <tr>
            <td>Password: </td>
            <td><asp:textbox id="Password"
                   textmode="Password" runat="server"/></td>
         </tr>
         <tr>
            <td>Persist Authentication Cookie?</td>
            <td><asp:checkbox id="Persist"
                   checked="False" runat="server"/></td>
         </tr>
         <tr>
            <td><asp:button text="Submit"
                   onclick="Login_Click" runat="server"/></td>
            <td><input type="reset" value="Cancel" runat="server"/></td>
         </tr>
      </table>
      <asp:label id="Message" forecolor="Red" runat="server"/>
   </form>
</body>
</html>

Phần thẻ của Login.aspx khá dễ hiểu, gồm có các ô textbox để nhập địa chỉ e-mail (username và password). Ngoài ra còn có một hộp checkbox cho phép người dùng tiếp tục sử dụng cookie thẩm định (vì thế họ sẽ không cần đăng nhập lại từ máy của mình). 

Để đoạn mã dễ đọc hơn một chút, trong ví dụ có thêm chỉ thị @ Import cho cả hai namespace System.Data và System.Web.Security. Do đó, chúng ta có thể truy cập vào các thành viên bên trong chúng mà không cần dùng đến tiền tố namespace. 

Trong trình điều  khiển sự kiện Login_Click có khai báo một biến DataSet cục bộ và đưa nó vào cache của ASP.NET hoặc file Users.xml có chứa thông tin thẩm định của người dùng đã đăng ký. Nếu dataset được lấy ra từ file XML thì chúng ta có thể chèn nó vào cache để truy vân về sau (loại trừ việc phải đọc file nếu nó thay đổi gì). 

Lời gọi Cache.Insert thiết lập một phụ thuộc file trên file Users.xml. Nếu file đó thay đổi, dataset trên đang lưu trữ sẽ bị đưa ra ngoài và dữ liệu mới sẽ được đưa vào file trong yêu cầu log-in tiếp theo. Điều này cho phép chúng ta khai thác được tính năng nâng cao trong thực thi caching, song vẫn đảm bảo xử lý được với dữ liệu mới.

Sau khi đã có một dataset chứa tất cả người dùng hiện tại, chúng ta cần đảm bảo email do người dùng nhập vào nằm trong một bảng, sử dụng phương thức Select của DataTable:

If LoginDS.Tables(0).Select("Email='" & _
         Email.text & "'").Length > 0 Then

Nếu e-mail tồn tại, chúng ta có một DataRow chứa thông tin thẩm định gắn với người dùng đó. Sau đó có thể so sánh mật khẩu theo hàm băm trong dataset với một bản sao chép của nó do người dùng nhập vào, là kết quả trả ra của phương thức HashPasswordForStoringInConfigFile trong lớp FormsAuthentication (sử dụng phương thức HashPasswordForStoringInConfigFile tức là bạn chưa từng lưu trữ một mật khẩu thực nào, tạo điều kiện cho ứng dụng ít bị xâm phạm hơn). Nếu hai mật khẩu khớp nhau, chúng ta sẽ chuyển người dùng trở lại trang họ yêu cầu bằng cách gọi hàm RedirectFromLoginPage của lớp FormsAuthentication. RedirectFromLoginPage sẽ tự động đưa người dùng trở lại trang được mô tả bằng tham số xâu truy vấn ReturnUrl. Tham số này được tự động thêm vào đuôi khi người dùng được đưa trở về file Login.aspx. RedirectFromLoginPage cũng thiết lập cookie .ASPNETIAN chứa mã thông báo thẩm định Forms. Đoạn mã dưới đây minh hoạ cho quá trình này: 

Dim LoginRow( ) As DataRow = LoginDS.Tables(0).Select("Email='" _
   & Email.text & "'")
If LoginRow(0).Item("Password").ToString = _
   FormsAuthentication.HashPasswordForStoringInConfigFile( _
   Password.Text, "SHA1") Then
   FormsAuthentication.RedirectFromLoginPage(Email.Text, _
   Persist.Checked)
Else
   Message.Text = "Incorrect Password!"
End If

Nếu địa chỉ e-mail tồn tại nhưng mật khẩu không chính xác, chúng ta sẽ thiết lập thuộc tính Text của điều khiển Message Label để thông báo cho người dùng. Nếu địa chỉ e-mail không tồn tại, chúng ta sẽ tạo một thông báo có chứa liên kết tới trang đăng ký để người dùng tự đăng ký. Liên kết phải bao gồm một tham số xâu truy vấn có tên page mà Register.aspx dùng để chuyển người dùng trở lại Login.aspx với tham số xâu truy vấn ReturnUrl. Phần đăng ký được điều khiển bởi trang Register.aspx, như minh hoạ trong hình 9-3.
Ví dụ 9-3. Register.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Web.Security" %>
<html>
<head>
<title>Registration Page</title>
<script runat="server">
   Sub Register_Click(Sender As Object, e As EventArgs)
      If Page.IsValid Then
         Dim LoginDS as New DataSet( )
         LoginDS.ReadXml(Server.MapPath("Users.xml"))
         If LoginDS.Tables(0).Select("Email='" & _
            Email.text & "'").Length = 0 Then
            Dim NewUser As DataRow
            NewUser = LoginDS.Tables(0).NewRow( )
            NewUser("Email") = Email.Text
            NewUser("Password") = _
               FormsAuthentication.HashPasswordForStoringInConfigFile( _
               Password.Text, "SHA1")
            LoginDS.Tables(0).Rows.Add(NewUser)
            LoginDS.WriteXml(Server.MapPath("Users.xml"))
           Response.Redirect(Request.QueryString("Page"))
         Else
            Message.Text = "User with email: " & Email.Text & _
               "
already exists. Please choose another email address. "
         End If
      End If
   End Sub
</script>
</head>
<body>
   <form runat="server">
      <table border="0" cellspacing="10">
         <tr>
            <td>Email: </td>
            <td><asp:textbox id="Email" runat="server"/></td>
         </tr>
         <tr>
            <td>Desired Password: </td>
            <td><asp:textbox id="Password"
                   textmode="Password" runat="server"/></td>
         </tr>
         <tr>
            <td>Confirm Password: </td>
            <td><asp:textbox id="PasswordConfirm"
                   textmode="Password" runat="server"/></td>
         </tr>
         <tr>
            <td><asp:button text="Submit"
                   onclick="Register_Click" runat="server"/></td>
            <td><input type="reset" value="Cancel" runat="server"/></td>
         </tr>
      </table>
      <asp:comparevalidator id="comparePasswords"
         controltovalidate="Password"
         controltocompare="PasswordConfirm"
         display="dynamic"
         text="Passwords must match!"
         operator="Equal"
         runat="server"/>
      <asp:requiredfieldvalidator id="requireEmail"
         controltovalidate="Email"
         display="dynamic"
         text="Email address required!"
         runat="server"/>
      <asp:requiredfieldvalidator id="requirePassword"
        controltovalidate="Password"
         display="dynamic"
         text="Password required!"
         runat="server"/>
      <asp:label id="Message" runat="server"/>
   </form>
</body>
</html>

Phần thẻ của Register.aspx tương tự như Login.aspx, ngoại trừ một điểm là có thêm một ô textbox (để kiểm chứng mật khẩu) và ba điều khiển kiểm tra tính hợp lệ:

    Một điều khiển CompareValidator để xác định xem giá trị trong ô Password và PasswordConfirm có khớp với nhau hay không.
    Một điều khiển RequiredFieldValidator để xác nhận người dùng đã nhập địa chỉ e-mail, vì thế chúng ta không có giá trị e-mail null trong file XML.
    Một điều khiển RequiredFieldValidator để đảm bảo rằng người dùng đã nhập mật khẩu để không có giá trị mật khẩu null trong file XML.

Nếu muốn đảm bảo thêm cho e-mail nhập vào là hợp lệ, chúng ta có thể sử dụng  hàm RegularExpressionValidator.

Trong trình điều khiển sự kiện Register_Click, đầu tiên nó sẽ kiểm tra để đảm bảo trang web là hợp lệ nhằm giúp vi xử lý tránh phải lãng phí thời gian làm việc với dữ liệu không hợp lệ. Nếu trình duyệt của người dùng hỗ trợ DHTML, trang web thậm chí sẽ không được đưa lên cho đến khi các yêu cầu của điều khiển hợp lệ được đáp ứng. 

Nếu trang web hợp lệ, một biến DataSet cục bộ sẽ được khai báo và được cấp phát không gian bộ nhớ trên file Users.xml. Sau đó là kiểm tra xem địa chỉ e-mail người dùng nhập vào có tồn tại trên file không. Nếu không, thuộc tính Text của điều khiển Label ASP.NET sẽ được dùng để yêu cầu người dùng nhập một địa chỉ e-mail khác. 

Nếu e-mail đó không tồn tại, một DataRow mới sẽ được tạo, chứa địa chỉ e-mail đã chọn của người dùng cùng với bản băm của mật khẩu, thêm hàng mới vào dataset và ghi dataset trở lại file XML (như ví dụ bên dưới). Kỹ thuật này không kiểm soát trùng hợp, vì thế nếu ai đó thay đổi nội dung của file XML trong khi nó đang được đọc hoặc ghi dữ liệu vào thì các thay đổi sẽ bị ghi đè. 

Dim NewUser As DataRow
NewUser = LoginDS.Tables(0).NewRow( )
NewUser("Email") = Email.Text
NewUser("Password") = _
   FormsAuthentication.HashPasswordForStoringInConfigFile( _
   Password.Text, "SHA1")
LoginDS.Tables(0).Rows.Add(NewUser)
LoginDS.WriteXml(Server.MapPath("Users.xml"))

Chú ý: Để ghi file Users.xml thành công, tài khoản bên dưới bộ thực thi ASP.NET đang chạy phải truy cập được vào file. 

Sau khi ghi thông tin của người dùng mới vào Users.xml, chúng ta sẽ đưa người dùng tới trang mô tả trong tham số xâu truy vấn:

Response.Redirect(Request.QueryString("Page"))

9.1.2.2. Thoát (Log-out)

Nhiều khi chúng ta phải làm việc với thông tin nhạy cảm trong ứng dụng từ các máy công cộng. Trong những trường hợp như vậy, chúng ta cần cung cấp cho người dùng một số cách log-out nhằm ngăn người khác truy cập thông tin riêng tư hoặc truy cập tài nguyên ứng dụng thông qua tài khoản của họ. Trong thẩm định Forms điều này khá đơn giản. Chúng ta có thể gọi phương thức tĩnh SignOut của lớp FormsAuthentication như ở ví dụ 9-4. Khi đó người dùng sẽ được chuyển đến file Logout.aspx để hoàn chỉnh quá trình log-out. Chúng ta cũng có thể tạo một điều khiển người dùng chứa một nút mà khi kích vào nó sẽ gọi ra phương thức SignOut và thêm điều khiển người dùng cho tất cả các trang được bảo vệ của ứng dụng.
Ví dụ 9-4. Logout.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Security" %>
<html>
<head>
<title>Logout Page</title>
<script runat="server">
   Sub Page_Load(Sender As Object, e As EventArgs)
      FormsAuthentication.SignOut( )
      Message.Text = "You have been logged out."
   End Sub
</script>
</head>
<body>
   <asp:label id="Message" runat="server"/>
</body>
</html>

Ví dụ 9-5 thể hiện nội dung của file Users.xml.
Ví dụ 9-5. Users.xml

<?xml version="1.0" standalone="yes"?>
<Users>
  <User>
    <Email>andrew@aspnetian.com</Email>
    <Password>816010E041FA485C6E2383C649343D3A0CAD4D25</Password>
  </User>
</Users>

9.1.3. Thẩm định Passport

Thẩm định Passport cho phép một người dùng có một mật khẩu duy nhất trong khi có thể đăng nhập (địa chỉ e-mail được gắn với tài khoản Passport của họ) vào nhiều ứng dụng hay website. Điều  này giúp đơn giản quá trình đăng nhập của người dùng và giảm bớt công việc quản trị khi bảo trì tài khoản người dùng. 

Để sử dụng được thẩm định Passport trong ASP.NET chúng ta phải download và cài đặt Passport SDK. 

Sau khi cài đặt Passport SDK, chúng ta cần cấu hình theo cấu trúc tương ứng. Cuối cùng là cấu hình ứng dụng ASP.NET để sử dụng thẩm định Passport, như đoạn mã bên dưới: 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <system.web>
      <authentication mode="Passport">
         <passport redirectUrl="someLocalpage.aspx"/>
      </authentication>
      <!--
         Other configuration elements
      -->
   </system.web>
</configuration>

Phần tử <passport> và  thuộc tính redirectUrl là tuỳ ý và được dùng để mô tả một URL nôi bộ để chuyển hướng nếu người dùng đưa ra yêu cầu đăng nhập không sử dụng tài khoản các Passport của họ. Nếu <passport> được bỏ qua, người dùng đăng nhập không sử dụng tài khoản Passport sẽ được chuyển tới trang đăng nhập trên một server login Passport.

9.2. Cấp phép (Authorization)

Cấp phép là quá trình xác định xem liệu người dùng đã được nhận dạng trong quá trình thẩm định có được phép truy cập tài nguyên họ đang yêu cầu không hay phải thực hiện thêm hành động nào khác (ví dụ như update dữ liệu cho cơ sở dữ liệu rồi mới được truy cập). Quá trình thẩm định trả lời cho câu hỏi: “Bạn là ai?”, còn quá trình cấp phép trả lời cho câu hỏi: “Bạn có được phép làm điều đó hay không?”. 

Cấp phép trong ASP.NET có ba hình thức: cấp phép sử dụng Danh sách điều khiển truy cập (ACL), cấp phép sử dụng đưòng dẫn URL và cấp phép programmatic. 

9.2.1. Cấp phép ACL

Danh sách điều khiển truy cập (ACL) được dùng trong Windows NT, Windows 2000, Windows XP và Windows Sever 2003 để kiểm soát truy cập tài nguyên hệ thống như các tệp, thư mục trong hệ thống file NTFS. Bạn có thể gán một số tài nguyên nhất định vào ACL cho tài khoản người dùng hoặc một nhóm người dùng Windows để cho phép họ truy cập tài nguyên hoặc xác định kiểu truy cập (đọc, ghi, thay đổi…) được phép dùng. 

Thẩm định ACL chủ yếu được dùng với thẩm định Windows trong ASP.NET. IIS sử dụng nhân dạng người dùng đã qua thẩm định để thực hiện các kiểm tra ACL và cũng có thể đưa ra các yêu cầu về tài nguyên được bảo vệ bởi ACL. bằng cách dùng ngữ cảnh bảo mật của người dùng, nếu impersonation được cho phép. 

Để bảo vệ một file dùng ACL, kích phải chuột lên file trong Windows Explorer và chọn Properties. Tiếp theo, bấm chọn thẻ Security để xem người dùng, nhóm người dùng và đặc quyền hiện thời có trên file. Sử dụng các nút Add và Remove để thêm hoặc bớt tài khoản người dùng, nhóm người dùng và đánh dấu hoặc bỏ dấu ở các ô trong phần Permissions để thay đổi đặc quyền cho người dùng. 

(Trong Windows XP, thẻ Security có thể không xuất hiện trên hộp thoại Properties của file hay folder nếu chức năng Simple File Sharing được bật. Để xem liệu thành phần này có đang được bật hay không, vào  Tools > Folder Options trong Windows Explorer. Sau đó chọn thẻ View, vào phần Advanced Settings, bỏ dấu chọn trong ô "Use simple file sharing (recommended)" đi là được).   

Một trong những việc cần làm đầu tiên trong là loại bỏ nhóm Everyone ra khỏi thư mục, do nhóm này cho phép bất kỳ ai truy cập máy tính cũng có thể truy cập file này.

Khi loại bỏ một số tài khoản đặc biệt (như SYSTEM) khỏi các danh sách ACL chúng ta cần thận trọng. Một số file hệ điều hành đòi hỏi phải có tài khoản SYSTEM mới được phép truy cập để thực hiện các chức năng của hệ điều hành. Vì thế loại bỏ những đặc quyền này có thể là nguyên nhân gây ra nhiều vấn đề nghiêm trọng. thậm chí dẫn đến không khởi động được hệ điều hành.

9.2.2. Cấp phép URL

Chế độ cấp phép URL sử dụng các yếu tố <allow> và <deny> của phần tử cấu hình <authorization> để kiểm soát truy cập file, thư mục bên trong ứng dụng, giống như trong ví dụ ở thẩm định Forms. Truy cập có thể được cho phép hoặc bị từ chối dựa trên tên người dùng (username), vai trò (role) và phương thức HTTP dùng để yêu cầu tài nguyên. Do đó, lấy ví dụ, nếu cho phép người dùng Marcie truy cập tất cả tài nguyên trong ứng dụng theo tất cả phương thức yêu cầu của HTTP, nhưng cấm người dùng Charles thực hiện yêu cầu POST, chúng ta sẽ phải thêm phần <authentication>vào sau file web.config ở mức gốc của ứng dụng (hoặc có thể thêm phần <authentication>vào file web.config trong một thư mục con để ghi đè hoặc thêm các thiết lập):

 <authorization>
     <allow verb="GET" users="*" />
     <allow verb="POST" users="Marcie" />
     <deny verb="POST" users="Charles" />
     <deny users="?" />
</authorization>

Như trên hình 9-1, chúng ta có thể dùng thẻ <location> với thuộc tính path cho điều khiển truy cập của một file hay folder cụ thể:

<location path="filetoprotect.aspx">
   <system.web>
      <authorization>
         <deny users="?"/>
      </authorization>
   </system.web>
</location>

Do thẻ <location> trong file web.config đòi hỏi cặp thẻ <system.web> riêng của nó nên thẻ <location> luôn xuất hiện bên trong các thẻ <configuration> và </configuration> nhưng bên ngoài các thẻ <system.web>và </system.web>. Chúng ta có thể định nghĩa ít hay nhiều thẻ <location> khác nhau tuỳ ý. Mỗi thể có thể chứa những giới hạn cấp phép URL riêng. 

Để mô tả miền thay cho các tài khoản hay nhóm cục bộ, chúng ta có thể sử dụng định dạng domainname\ userorgroupname khi mô tả tên trong <allow>và <deny>. Có hai ký tự đặc biệt: “*” cho phép tất cả người dùng, “?” là chỉ những người dùng nặc danh (không qua thẩm định). Cuối cùng, có thể mô tả nhiều người dùng hoặc nhóm người dùng cùng một lúc trong <allow>và <deny> bằng dấu phẩy. 

9.2.3 Cấp phép Programmatic (programmatic authorization)

Chúng ta có thể thực hiện các kiểm tra programmatic tại thời gian chạy bằng cách xác định xem liệu người dùng có được phép thực hiện một hành động nào đó hay không. Công cụ chủ yếu để thực hiện điều này là phương thức IsInRole, được định nghĩa bởi giao diện IPrincipalvà có thể truy cập từ thuộc tính User của lớp Page. Cũng như với cấp phép ACL, phương thức này hữu ích nhất khi dùng với cơ chế thẩm định Windows và khi muốn kiểm tra xem liệu liệu người dùng đã qua thẩm định thuộc nhóm Windows nào, như nhóm manager (quản lý) chẳng hạn. Chúng ta có thể lấy ví dụ minh hoạ cho việc sử dụng IsInRole như bên dưới: 

If Page.User.IsInRole("Managers") Then
   'perform some action restricted to managers
Else
   Message.Text = "You must be a manager to perform this action"
End If

Bạn đọc thân mến, có thể thấy rõ bảo mật ứng dụng trong ASP.NET tập trung làm rõ hai vấn đề thẩm định (authentication) và cấp phép (authorization). Song ngoài hai khái niệm chính này chúng ta cũng cần biết đến một số yếu tố đáng quan tâm khác mà có dịp chúng tôi sẽ tiếp tục chuyển tới các bạn vào một ngày gần nhất. Hy vọng các bạn đã có được một tài liệu tham khảo hữu ích từ phần bài dịch này của tác giả. Trong quá trình dịch không thể tránh khỏi một số sai sót, mong các bạn góp ý để giúp tác giả sửa chữa nhằm phục vụ bạn đọc một tác phẩm hay hơn và chính xác hơn.
« Sửa lần cuối: Tháng Sáu 20, 2019, 05:06:21 PM gửi bởi NetworkEngineer »