Tôi có nên tránh InternalHTML không?

Cheats ngăn chặn XSS thực hiện một công việc tuyệt vời để giải quyết XSS được phản ánh và lưu trữ. Cheats này giải quyết XSS dựa trên DOM (Mô hình đối tượng tài liệu) và là một phần mở rộng (và giả định hiểu) Cheats ngăn chặn XSS

Show

Để hiểu XSS dựa trên DOM, người ta cần thấy sự khác biệt cơ bản giữa XSS được phản ánh và XSS được lưu trữ khi so sánh với XSS dựa trên DOM. Sự khác biệt chính là nơi cuộc tấn công được đưa vào ứng dụng

XSS được phản ánh và được lưu trữ là sự cố tiêm nhiễm phía máy chủ trong khi XSS dựa trên DOM là sự cố tiêm nhiễm phía máy khách (trình duyệt)

Tất cả mã này bắt nguồn từ máy chủ, nghĩa là chủ sở hữu ứng dụng có trách nhiệm đảm bảo an toàn khỏi XSS, bất kể đó là loại lỗ hổng XSS nào. Ngoài ra, các cuộc tấn công XSS luôn thực thi trong trình duyệt

Sự khác biệt giữa Reflected/Stored XSS là nơi cuộc tấn công được thêm vào hoặc đưa vào ứng dụng. Với Reflected/Stored, cuộc tấn công được đưa vào ứng dụng trong quá trình xử lý yêu cầu phía máy chủ trong đó đầu vào không đáng tin cậy được thêm động vào HTML. Đối với DOM XSS, cuộc tấn công được đưa trực tiếp vào ứng dụng trong thời gian chạy ở máy khách

Khi trình duyệt hiển thị HTML và bất kỳ nội dung liên quan nào khác như CSS hoặc JavaScript, trình duyệt sẽ xác định các ngữ cảnh hiển thị khác nhau cho các loại đầu vào khác nhau và tuân theo các quy tắc khác nhau cho từng ngữ cảnh. Bối cảnh kết xuất được liên kết với việc phân tích cú pháp các thẻ HTML và các thuộc tính của chúng

  • Trình phân tích cú pháp HTML của ngữ cảnh hiển thị cho biết cách trình bày và trình bày dữ liệu trên trang và có thể được chia nhỏ hơn nữa thành các ngữ cảnh chuẩn của HTML, thuộc tính HTML, URL và CSS
  • Trình phân tích cú pháp JavaScript hoặc VBScript của ngữ cảnh thực thi được liên kết với quá trình phân tích cú pháp và thực thi mã tập lệnh. Mỗi trình phân tích cú pháp có ngữ nghĩa riêng biệt và riêng biệt theo cách chúng có thể thực thi mã tập lệnh, điều này khiến việc tạo quy tắc nhất quán để giảm thiểu lỗ hổng trong các ngữ cảnh khác nhau trở nên khó khăn. Sự phức tạp được kết hợp bởi các ý nghĩa khác nhau và cách xử lý các giá trị được mã hóa trong mỗi ngữ cảnh con (HTML, thuộc tính HTML, URL và CSS) trong ngữ cảnh thực thi

Đối với mục đích của bài viết này, chúng tôi đề cập đến ngữ cảnh HTML, thuộc tính HTML, URL và CSS dưới dạng ngữ cảnh con vì mỗi ngữ cảnh này có thể tiếp cận và đặt trong ngữ cảnh thực thi JavaScript

Trong mã JavaScript, ngữ cảnh chính là JavaScript nhưng với các thẻ và ký tự đóng ngữ cảnh phù hợp, kẻ tấn công có thể cố gắng tấn công 4 ngữ cảnh khác bằng các phương thức JavaScript DOM tương đương

Sau đây là một ví dụ về lỗ hổng xảy ra trong ngữ cảnh JavaScript và ngữ cảnh con HTML

 <script>
 var x = '<%= taintedVar %>';
 var d = document.createElement('div');
 d.innerHTML = x;
 document.body.appendChild(d);
 script>

Hãy lần lượt xem xét các ngữ cảnh con riêng lẻ của ngữ cảnh thực thi

QUY TẮC #1 - Thoát HTML rồi thoát JavaScript trước khi chèn dữ liệu không đáng tin cậy vào ngữ cảnh con HTML trong ngữ cảnh thực thi

Có một số phương thức và thuộc tính có thể được sử dụng để hiển thị trực tiếp nội dung HTML trong JavaScript. Các phương thức này cấu thành Ngữ cảnh con HTML trong Ngữ cảnh thực thi. Nếu các phương pháp này được cung cấp với đầu vào không đáng tin cậy thì có thể dẫn đến lỗ hổng XSS. Ví dụ

Ví dụ về các phương thức HTML nguy hiểm

Thuộc tính

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";

phương pháp

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");

Hướng dẫn

Để thực hiện cập nhật động cho HTML trong DOM an toàn, chúng tôi khuyên bạn nên

  1. mã hóa HTML, và sau đó
  2. Mã hóa JavaScript tất cả đầu vào không đáng tin cậy, như được hiển thị trong các ví dụ này

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");

QUY TẮC #2 - Thoát khỏi JavaScript trước khi chèn dữ liệu không đáng tin cậy vào văn bản con thuộc tính HTML trong ngữ cảnh thực thi

Văn bản con thuộc tính HTML trong ngữ cảnh thực thi khác với các quy tắc mã hóa tiêu chuẩn. Điều này là do quy tắc mã hóa thuộc tính HTML trong bối cảnh hiển thị thuộc tính HTML là cần thiết để giảm thiểu các cuộc tấn công cố gắng thoát khỏi thuộc tính HTML hoặc cố gắng thêm các thuộc tính bổ sung có thể dẫn đến XSS

Khi bạn ở trong ngữ cảnh thực thi DOM, bạn chỉ cần mã hóa JavaScript các thuộc tính HTML không thực thi mã (các thuộc tính khác với trình xử lý sự kiện, CSS và thuộc tính URL)

Ví dụ: quy tắc chung là Thuộc tính HTML mã hóa dữ liệu không đáng tin cậy (dữ liệu từ cơ sở dữ liệu, yêu cầu HTTP, người dùng, hệ thống phụ trợ, v.v. ) được đặt trong Thuộc tính HTML. Đây là bước thích hợp cần thực hiện khi xuất dữ liệu trong ngữ cảnh hiển thị, tuy nhiên, việc sử dụng mã hóa Thuộc tính HTML trong ngữ cảnh thực thi sẽ phá vỡ hiển thị dữ liệu của ứng dụng

Ví dụ AN TOÀN nhưng BỊ HỎNG

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);

Vấn đề là nếu tên công ty có giá trị "Johnson & Johnson". Nội dung sẽ được hiển thị trong trường văn bản đầu vào sẽ là "Johnson & Johnson". Mã hóa thích hợp để sử dụng trong trường hợp trên sẽ chỉ là mã hóa JavaScript để không cho phép kẻ tấn công đóng dấu ngoặc đơn và mã nội tuyến hoặc thoát sang HTML và mở thẻ tập lệnh mới

Ví dụ AN TOÀN và ĐÚNG CHỨC NĂNG

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
 var form1 = document.forms[0];
 form1.appendChild(x);

Điều quan trọng cần lưu ý là khi đặt thuộc tính HTML không thực thi mã, giá trị được đặt trực tiếp trong thuộc tính đối tượng của phần tử HTML, do đó không có vấn đề gì với việc đưa vào

QUY TẮC #3 - Hãy cẩn thận khi chèn Dữ liệu không đáng tin cậy vào Trình xử lý sự kiện và Ngữ cảnh con mã JavaScript trong Ngữ cảnh thực thi

Đặt dữ liệu động trong mã JavaScript đặc biệt nguy hiểm vì mã hóa JavaScript có ngữ nghĩa khác nhau đối với dữ liệu được mã hóa JavaScript khi so sánh với các mã hóa khác. Trong nhiều trường hợp, mã hóa JavaScript không dừng các cuộc tấn công trong ngữ cảnh thực thi. Ví dụ: một chuỗi mã hóa JavaScript sẽ thực thi ngay cả khi nó được mã hóa JavaScript

Do đó, khuyến nghị chính là tránh đưa dữ liệu không đáng tin cậy vào ngữ cảnh này. Nếu bạn phải, các ví dụ sau mô tả một số cách tiếp cận hiệu quả và không hiệu quả

var x = document.createElement("a");
x.href="#";
// In the line of code below, the encoded data on the right (the second argument to setAttribute)
// is an example of untrusted data that was properly JavaScript encoded but still executes.
x.setAttribute("onclick", "\u0061\u006c\u0065\u0072\u0074\u0028\u0032\u0032\u0029");
var y = document.createTextNode("Click To Test");
x.appendChild(y);
document.body.appendChild(x);

Phương thức

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
7 nguy hiểm vì nó hoàn toàn ép buộc value_string vào kiểu dữ liệu thuộc tính DOM của name_string

Trong trường hợp trên, tên thuộc tính là trình xử lý sự kiện JavaScript, vì vậy giá trị thuộc tính được chuyển đổi hoàn toàn thành mã JavaScript và được đánh giá. Trong trường hợp trên, mã hóa JavaScript không giảm thiểu đối với XSS dựa trên DOM

Các phương thức JavaScript khác lấy mã dưới dạng kiểu chuỗi sẽ gặp sự cố tương tự như phác thảo ở trên (

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
8,
 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
9, Hàm mới, v.v. ). Điều này hoàn toàn trái ngược với mã hóa JavaScript trong thuộc tính trình xử lý sự kiện của thẻ HTML (trình phân tích cú pháp HTML) trong đó mã hóa JavaScript giảm nhẹ chống lại XSS

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
1

Một cách khác để sử dụng

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
0 để đặt thuộc tính DOM là đặt thuộc tính trực tiếp. Đặt trực tiếp các thuộc tính trình xử lý sự kiện sẽ cho phép mã hóa JavaScript giảm thiểu XSS dựa trên DOM. Xin lưu ý, việc đặt trực tiếp dữ liệu không đáng tin cậy vào ngữ cảnh thực thi lệnh luôn là một thiết kế nguy hiểm

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
3

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
0

Có những nơi khác trong JavaScript nơi mã hóa JavaScript được chấp nhận là mã thực thi hợp lệ

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
1

hoặc

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
2

Vì JavaScript dựa trên tiêu chuẩn quốc tế (ECMAScript), mã hóa JavaScript cho phép hỗ trợ các ký tự quốc tế trong các cấu trúc và biến lập trình bên cạnh các biểu diễn chuỗi thay thế (chuỗi thoát)

Tuy nhiên, trường hợp ngược lại với mã hóa HTML. Các phần tử thẻ HTML được xác định rõ và không hỗ trợ các biểu diễn thay thế của cùng một thẻ. Vì vậy, không thể sử dụng mã hóa HTML để cho phép nhà phát triển có các biểu diễn thay thế của thẻ

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
1 chẳng hạn

Bản chất vô hiệu hóa của mã hóa HTML

Nói chung, mã hóa HTML dùng để loại bỏ các thẻ HTML được đặt trong ngữ cảnh thuộc tính HTML và HTML. Ví dụ hoạt động (không có mã hóa HTML)

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
3

Ví dụ được mã hóa thông thường (Không hoạt động – DNW)

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
4

Ví dụ mã hóa HTML để làm nổi bật sự khác biệt cơ bản với các giá trị mã hóa JavaScript (DNW)

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
5

Nếu mã hóa HTML tuân theo ngữ nghĩa giống như mã hóa JavaScript. Dòng trên có thể đã hoạt động để hiển thị một liên kết. Sự khác biệt này làm cho mã hóa JavaScript trở thành một vũ khí ít khả thi hơn trong cuộc chiến chống lại XSS của chúng tôi

QUY TẮC #4 - Thoát khỏi JavaScript trước khi chèn dữ liệu không đáng tin cậy vào ngữ cảnh con thuộc tính CSS trong ngữ cảnh thực thi

Thông thường, việc thực thi JavaScript từ ngữ cảnh CSS được yêu cầu hoặc chuyển

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
2 sang phương thức CSS
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
3 hoặc gọi phương thức CSS
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
4 chuyển mã JavaScript để được thực thi trực tiếp

Theo kinh nghiệm của tôi, việc gọi hàm

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
4 từ ngữ cảnh thực thi (JavaScript) đã bị tắt. Để giảm thiểu khả năng chống lại phương pháp CSS
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
3, hãy đảm bảo rằng bạn đang mã hóa URL dữ liệu được chuyển đến phương pháp CSS
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
3

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
6

QUY TẮC #5 - Thoát URL rồi thoát JavaScript trước khi chèn dữ liệu không đáng tin cậy vào văn bản con thuộc tính URL trong ngữ cảnh thực thi

Logic phân tích cú pháp URL trong cả bối cảnh thực thi và kết xuất có vẻ giống nhau. Do đó, có rất ít thay đổi trong quy tắc mã hóa cho các thuộc tính URL trong ngữ cảnh thực thi (DOM)

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
7

Nếu bạn sử dụng các URL đủ điều kiện thì điều này sẽ phá vỡ các liên kết vì dấu hai chấm trong mã định danh giao thức (

 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
8 hoặc
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
9) sẽ được mã hóa URL để ngăn không cho các giao thức
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
0 và
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
1 được gọi

QUY TẮC #6 - Điền vào DOM bằng các hàm hoặc thuộc tính JavaScript an toàn

Cách an toàn cơ bản nhất để đưa vào DOM dữ liệu không đáng tin cậy là sử dụng thuộc tính gán an toàn

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
2

Đây là một ví dụ về cách sử dụng an toàn

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
8

QUY TẮC #7 - Khắc phục lỗ hổng DOM Cross-site Scripting

Cách tốt nhất để khắc phục tập lệnh chéo trang dựa trên DOM là sử dụng phương thức xuất phù hợp (chìm). Ví dụ: nếu bạn muốn sử dụng đầu vào của người dùng để viết trong phần tử

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
3, đừng sử dụng
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
4, thay vào đó hãy sử dụng
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
5 hoặc
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
2. Điều này sẽ giải quyết vấn đề và đó là cách phù hợp để khắc phục lại các lỗ hổng XSS dựa trên DOM

Luôn luôn là một ý tưởng tồi khi sử dụng đầu vào do người dùng kiểm soát trong các nguồn nguy hiểm như eval. 99% thời gian đó là dấu hiệu của việc thực hành lập trình kém hoặc lười biếng, vì vậy đơn giản là đừng làm điều đó thay vì cố gắng làm sạch đầu vào

Cuối cùng, để khắc phục sự cố trong mã ban đầu của chúng tôi, thay vì cố gắng mã hóa đầu ra một cách chính xác, điều gây rắc rối và có thể dễ dàng sai, chúng tôi chỉ cần sử dụng

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
7 để viết nó trong một nội dung như thế này

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
9

Nó làm điều tương tự nhưng lần này nó không dễ bị tấn công bởi các lỗ hổng tập lệnh chéo trang dựa trên DOM

Nguyên tắc phát triển ứng dụng an toàn bằng JavaScript

XSS dựa trên DOM cực kỳ khó giảm thiểu do bề mặt tấn công lớn và thiếu tiêu chuẩn hóa trên các trình duyệt

Các nguyên tắc bên dưới là một nỗ lực nhằm cung cấp các nguyên tắc cho các nhà phát triển khi phát triển các ứng dụng JavaScript dựa trên Web (Web 2. 0) để họ có thể tránh được XSS

HƯỚNG DẪN #1 - Dữ liệu không đáng tin cậy chỉ nên được coi là văn bản có thể hiển thị

Tránh coi dữ liệu không đáng tin cậy là mã hoặc đánh dấu trong mã JavaScript

HƯỚNG DẪN #2 - Luôn mã hóa JavaScript và phân định dữ liệu không đáng tin cậy dưới dạng chuỗi được trích dẫn khi vào ứng dụng khi xây dựng JavaScript theo khuôn mẫu

Luôn mã hóa JavaScript và phân định dữ liệu không đáng tin cậy dưới dạng chuỗi được trích dẫn khi vào ứng dụng như minh họa trong ví dụ sau

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
0

HƯỚNG DẪN #3 - Sử dụng tài liệu. createElement(". "), yếu tố. setAttribute(". ","giá trị"), phần tử. appendChild(. ) và tương tự để xây dựng giao diện động

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
8,
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
9,
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
0 và tương tự là những cách an toàn để xây dựng giao diện động

Xin lưu ý,

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
1 chỉ an toàn cho một số thuộc tính hạn chế

Các thuộc tính nguy hiểm bao gồm bất kỳ thuộc tính nào là ngữ cảnh thực thi lệnh, chẳng hạn như

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
2 hoặc
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
3

Ví dụ về các thuộc tính an toàn bao gồm. _______64, _______65, _______66, _______67, _______68, _______69, _______70, _______72, _______3, _______74, _______75, _______76, _______77, _______78, _______79, _______110, _______111, _______112, _______113, _______114, _______115, _______116, _______117, _______118,

HƯỚNG DẪN #4 - Tránh gửi dữ liệu không đáng tin cậy vào các phương thức hiển thị HTML

Tránh phổ biến các phương pháp sau với dữ liệu không đáng tin cậy

  1.  element.innerHTML = " Tags and markup";
     element.outerHTML = " Tags and markup";
    
    06
  2.  element.innerHTML = " Tags and markup";
     element.outerHTML = " Tags and markup";
    
    07
  3.  element.innerHTML = " Tags and markup";
     element.outerHTML = " Tags and markup";
    
    08
  4.  element.innerHTML = " Tags and markup";
     element.outerHTML = " Tags and markup";
    
    09

HƯỚNG DẪN #5 - Tránh nhiều phương thức truyền dữ liệu eval() ngầm định cho nó

Có rất nhiều phương pháp ngầm truyền dữ liệu

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
10 cho nó mà phải tránh

Đảm bảo rằng mọi dữ liệu không đáng tin cậy được chuyển đến các phương thức này đều được

  1. Được phân cách bằng dấu phân cách chuỗi
  2. Được đính kèm trong phần đóng hoặc JavaScript được mã hóa thành cấp độ N dựa trên mức độ sử dụng
  3. Gói trong một chức năng tùy chỉnh

Đảm bảo làm theo bước 3 ở trên để đảm bảo rằng dữ liệu không đáng tin cậy không được gửi đến các phương thức nguy hiểm trong chức năng tùy chỉnh hoặc xử lý dữ liệu đó bằng cách thêm một lớp mã hóa bổ sung

Sử dụng Enclosure (theo đề xuất của Gaz)

Ví dụ sau minh họa việc sử dụng bao đóng để tránh mã hóa JavaScript kép

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
1

Cách thay thế khác là sử dụng N cấp độ mã hóa

Cấp độ mã hóa N

Nếu mã của bạn giống như sau, bạn chỉ cần tăng gấp đôi dữ liệu đầu vào mã hóa JavaScript

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
2

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
11 có lớp mã hóa JavaScript đầu tiên bị đảo ngược (khi thực thi) trong dấu nháy đơn

Sau đó,

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
12 ngầm định của
 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
8 đảo ngược một lớp mã hóa JavaScript khác để chuyển giá trị chính xác cho
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
14

Lý do tại sao bạn chỉ cần tăng gấp đôi mã hóa JavaScript là vì hàm

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
14 không tự chuyển đầu vào sang một phương thức khác được gọi ngầm hoặc rõ ràng là
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
12 Nếu firstName được chuyển sang một phương thức JavaScript khác được gọi ngầm hoặc rõ ràng là
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
10 thì
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
18 ở trên sẽ cần phải

Một lưu ý triển khai quan trọng là nếu mã JavaScript cố gắng sử dụng dữ liệu được mã hóa kép hoặc ba trong so sánh chuỗi, giá trị có thể được hiểu là các giá trị khác nhau dựa trên số lượng

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
20 mà dữ liệu đã đi qua trước khi được chuyển đến so sánh if và

Nếu A được mã hóa JavaScript kép thì kiểm tra if sau đây sẽ trả về false

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
3

Điều này mang đến một điểm thiết kế thú vị. Lý tưởng nhất là cách chính xác để áp dụng mã hóa và tránh sự cố đã nêu ở trên là mã hóa phía máy chủ cho ngữ cảnh đầu ra nơi dữ liệu được đưa vào ứng dụng

Sau đó, mã hóa phía máy khách (sử dụng thư viện mã hóa JavaScript chẳng hạn như nút-esapi) cho ngữ cảnh con riêng lẻ (phương thức DOM) mà dữ liệu không đáng tin cậy được chuyển đến

Dưới đây là một số ví dụ về cách chúng được sử dụng

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
4

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
5

Một tùy chọn là sử dụng các thuộc tính không thay đổi của ECMAScript 5 trong thư viện JavaScript. Một tùy chọn khác do Gaz (Gareth) cung cấp là sử dụng cấu trúc mã cụ thể để hạn chế khả năng thay đổi với các lần đóng ẩn danh

Một ví dụ sau

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
6

HƯỚNG DẪN #6 - Chỉ sử dụng dữ liệu không đáng tin cậy ở phía bên phải của biểu thức

Chỉ sử dụng dữ liệu không đáng tin cậy ở phía bên phải của một biểu thức, đặc biệt là dữ liệu trông giống như mã và có thể được chuyển đến ứng dụng (e. g. ,

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
21 và
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
10)

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
7

Sử dụng dữ liệu người dùng không đáng tin cậy ở phía bên trái của biểu thức cho phép kẻ tấn công phá vỡ các thuộc tính bên trong và bên ngoài của đối tượng cửa sổ, trong khi sử dụng đầu vào của người dùng ở phía bên phải của biểu thức không cho phép thao tác trực tiếp

HƯỚNG DẪN #7 - Khi mã hóa URL trong DOM, hãy lưu ý các vấn đề về bộ ký tự

Khi mã hóa URL trong DOM, hãy lưu ý các vấn đề về bộ ký tự vì bộ ký tự trong JavaScript DOM không được xác định rõ ràng (Mike Samuel)

HƯỚNG DẪN #8 - Giới hạn quyền truy cập vào các thuộc tính đối tượng khi sử dụng trình truy cập object[x]

Giới hạn quyền truy cập vào các thuộc tính đối tượng khi sử dụng bộ truy cập

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
23 (Mike Samuel). Nói cách khác, thêm một mức độ gián tiếp giữa đầu vào không đáng tin cậy và các thuộc tính đối tượng được chỉ định

Đây là một ví dụ về sự cố khi sử dụng các loại bản đồ

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
8

Nhà phát triển viết mã ở trên đang cố gắng thêm các phần tử có khóa bổ sung vào đối tượng

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
24. Tuy nhiên, kẻ tấn công có thể sử dụng điều này để phá hoại các thuộc tính bên trong và bên ngoài của đối tượng
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
24

Một cách tiếp cận tốt hơn sẽ là sử dụng như sau

 document.write(" Tags and markup");
 document.writeln(" Tags and markup");
9

HƯỚNG DẪN #9 - Chạy JavaScript của bạn trong hộp cát hoặc hộp cát ECMAScript 5

Chạy JavaScript của bạn trong hộp cát hoặc hộp cát ECMAScript 5 để khiến API JavaScript của bạn khó bị xâm phạm hơn (Gareth Heyes và John Stevens)

Ví dụ về một số hộp cát / chất khử trùng JavaScript

  • js-xss
  • vệ sinh-html
  • DOMPurify
  • MDN - API làm sạch HTML
  • Hội nghị thượng đỉnh OWASP 2011 - Hộp cát DOM

HƯỚNG DẪN #10 - Không eval() JSON để chuyển đổi nó thành các đối tượng JavaScript gốc

Đừng

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
10 JSON để chuyển đổi nó thành các đối tượng JavaScript gốc. Thay vào đó hãy sử dụng
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
27 và
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
28 (Chris Schmidt)

Các vấn đề thường gặp liên quan đến việc giảm thiểu XSS dựa trên DOM

bối cảnh phức tạp

Trong nhiều trường hợp, bối cảnh không phải lúc nào cũng đơn giản để phân biệt

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
0

Trong ví dụ trên, dữ liệu không đáng tin cậy bắt đầu trong ngữ cảnh URL hiển thị (thuộc tính

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
29 của thẻ
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
30) sau đó được thay đổi thành ngữ cảnh thực thi JavaScript (trình xử lý giao thức
 var ESAPI = require('node-esapi');
 document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
 document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
9) chuyển dữ liệu không đáng tin cậy sang ngữ cảnh con URL thực thi (
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
32 của
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
33)

Vì dữ liệu được đưa vào bằng mã JavaScript và được chuyển đến ngữ cảnh con URL nên mã hóa phía máy chủ thích hợp sẽ như sau

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
1

Hoặc nếu bạn đang sử dụng ECMAScript 5 với thư viện mã hóa phía máy khách JavaScript bất biến, bạn có thể thực hiện các thao tác sau

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
2

Sự không nhất quán của thư viện mã hóa

Có một số thư viện mã hóa mã nguồn mở hiện có

  1. OWASP ESAPI
  2. Bộ mã hóa Java OWASP
  3. Apache Commons Text StringEscapeUtils, thay thế một từ Apache Commons Lang3
  4. ngăn nắp
  5. Triển khai tùy chỉnh của công ty bạn

Some work on a block list while others ignore important characters like "<" and ">".

Java Encoder là một dự án đang hoạt động cung cấp hỗ trợ mã hóa HTML, CSS và JavaScript

ESAPI là một trong số ít hoạt động trên danh sách cho phép và mã hóa tất cả các ký tự không phải chữ và số. Điều quan trọng là sử dụng một thư viện mã hóa để hiểu những ký tự nào có thể được sử dụng để khai thác lỗ hổng trong ngữ cảnh tương ứng của chúng. Có rất nhiều quan niệm sai lầm liên quan đến mã hóa phù hợp được yêu cầu

Mã hóa những quan niệm sai lầm

Nhiều tài liệu và giáo trình đào tạo bảo mật ủng hộ việc sử dụng mù quáng mã hóa HTML để giải quyết XSS

Về mặt logic, đây có vẻ là lời khuyên thận trọng vì trình phân tích cú pháp JavaScript không hiểu mã hóa HTML

Tuy nhiên, nếu các trang được trả về từ ứng dụng web của bạn sử dụng loại nội dung

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
34 hoặc phần mở rộng loại tệp là
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
35 thì mã hóa HTML có thể không hoạt động để giảm thiểu XSS

Ví dụ

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
3

Giá trị được mã hóa HTML ở trên vẫn có thể thực thi được. Nếu điều đó vẫn chưa đủ để ghi nhớ, bạn phải nhớ rằng mã hóa sẽ bị mất khi bạn truy xuất chúng bằng thuộc tính giá trị của phần tử DOM

Hãy xem trang mẫu và kịch bản

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
4

Cuối cùng, có một vấn đề là một số phương thức trong JavaScript thường an toàn có thể không an toàn trong một số ngữ cảnh nhất định

Phương pháp thường an toàn

Một ví dụ về thuộc tính được cho là an toàn là

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
5

Một số bài báo hoặc hướng dẫn ủng hộ việc sử dụng nó như một giải pháp thay thế cho

 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
37 để giảm thiểu XSS trong
 element.innerHTML = " Tags and markup";
 element.outerHTML = " Tags and markup";
37. Tuy nhiên, tùy thuộc vào thẻ mà
 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
5 được áp dụng, mã có thể được thực thi

 var ESAPI = require('node-esapi');
 element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
 element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
5

Tính năng

 var ESAPI = require('node-esapi');
 var x = document.createElement("input");
 x.setAttribute("name", "company_name");
 // In the following line of code, companyName represents untrusted user input
 // The ESAPI.encoder().encodeForHTMLAttribute() is unnecessary and causes double-encoding
 x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTMLAttribute(companyName))%>');
 var form1 = document.forms[0];
 form1.appendChild(x);
5 ban đầu được giới thiệu bởi Internet Explorer và được chỉ định chính thức trong tiêu chuẩn HTML vào năm 2016 sau khi được tất cả các nhà cung cấp trình duyệt lớn áp dụng

Tại sao chúng ta không nên sử dụng InternalHTML?

InnerHTML không cung cấp xác thực hợp lệ , do đó, bất kỳ mã HTML hợp lệ nào cũng có thể được sử dụng. Điều này có khả năng phá vỡ tài liệu JavaScript. Ngay cả HTML bị hỏng cũng có thể được sử dụng, điều này có thể gây ra các sự cố không mong muốn.

Khi nào bạn nên sử dụng InternalHTML?

innerHTML hữu ích tại bất kỳ lúc nào để chèn thẻ/nội dung HTML mới dưới dạng chuỗi và có thể dễ dàng chuyển hướng đến các thành phần cụ thể trong .

Tôi nên sử dụng InternalText hay InternalHTML?

innerText trả về tất cả văn bản chứa trong một phần tử và tất cả các phần tử con của nó. innerHtml trả về tất cả văn bản, bao gồm các thẻ html, được chứa bởi một phần tử .

Điều gì tốt hơn InternalHTML?

Phần tử này rất mạnh và có một số mã siêu thú vị. Ghi chú. Không giống như InternalHTML, textContent có hiệu suất tốt hơn vì giá trị của nó không được phân tích cú pháp dưới dạng HTML. Vì lý do đó, sử dụng textContent cũng có thể ngăn chặn các cuộc tấn công Cross-Site Scripting (XSS).