Tôi có thể thoát các ký tự đặc biệt html trong javascript không?


201

Tôi muốn hiển thị văn bản sang HTML bằng chức năng javascript. Làm cách nào tôi có thể thoát được ký tự html đặc biệt trong JS? Có API không?


11
Đây không phải là một bản sao, vì câu hỏi này không hỏi về jQuery. Tôi chỉ quan tâm đến cái này, vì tôi không sử dụng jQuery ...
lvella

Câu trả lời:


330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

11
Tại sao "& # 039;" và không "& apos;" ?
sereda


2
Tôi nghĩ rằng các biểu thức thường xuyên trong replace()các cuộc gọi là không cần thiết. Các chuỗi ký tự đơn cũ sẽ làm tốt như vậy.
jamix

22
@jamix Bạn không thể thay thế toàn cầu bằng các chuỗi thô, trong khi các công cụ trình duyệt hiện đại tối ưu hóa biểu thức chính quy đơn giản khá tốt.
bjornd

5
Có API tiêu chuẩn nào không hay đây là cách duy nhất?
Sunil Garg

55

function escapeHtml(html){
  var text = document.createTextNode(html);
  var p = document.createElement('p');
  p.appendChild(text);
  return p.innerHTML;
}

// Escape while typing & print result
document.querySelector('input').addEventListener('input', e => {
  console.clear();
  console.log( escapeHtml(e.target.value) );
});
<input style='width:90%; padding:6px;' placeholder='&lt;b&gt;cool&lt;/b&gt;'>


Làm việc ở đây nhưng không hoạt động cho tôi ngoại tuyến trong trình duyệt

48

Bạn có thể sử dụng chức năng của jQuery.text() .

Ví dụ:

http://jsfiddle.net/9H6Ch/

Từ tài liệu jQuery liên quan đến .text()chức năng:

Chúng ta cần lưu ý rằng phương thức này thoát khỏi chuỗi được cung cấp khi cần thiết để nó sẽ hiển thị chính xác trong HTML. Để làm như vậy, nó gọi phương thức DOM .createTextNode (), không hiểu chuỗi là HTML.

Các phiên bản trước của Tài liệu jQuery đã diễn đạt theo cách này ( nhấn mạnh thêm ):

Chúng ta cần lưu ý rằng phương thức này thoát khỏi chuỗi được cung cấp khi cần thiết để nó sẽ hiển thị chính xác trong HTML. Để làm như vậy, nó gọi phương thức DOM .createTextNode (), thay thế các ký tự đặc biệt bằng các tương đương thực thể HTML của chúng (chẳng hạn như & lt; cho <).


3
Bạn thậm chí có thể sử dụng nó trên một yếu tố mới nếu bạn chỉ muốn chuyển đổi như thế này: const str = "foo<>'\"&"; $('<div>').text(str).html()sản lượngfoo&lt;&gt;'"&amp;
amoebe

28

Tôi nghĩ rằng tôi đã tìm thấy cách thích hợp để làm điều đó ...

// Create a DOM Text node:
var text_node = document.createTextNode(unescaped_text);

// Get the HTML element where you want to insert the text into:
var elem = document.getElementById('msg_span');

// Optional: clear its old contents
//elem.innerHTML = '';

// Append the text node into it:
elem.appendChild(text_node);

Tôi đã học được một cái gì đó mới về HTML ngày hôm nay. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio

1
Xin lưu ý rằng nội dung của nút văn bản không được thoát nếu bạn cố truy cập vào nó như thế này:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler

Đây là cách chính xác nếu tất cả những gì bạn đang làm là thiết lập văn bản. Đó cũng là textContent nhưng dường như nó không được hỗ trợ tốt. Điều này sẽ không hoạt động tuy nhiên nếu bạn đang xây dựng một chuỗi với một số phần văn bản một số html, thì bạn vẫn cần phải thoát.
jgmjgm


20

Đây là, cách nhanh nhất tôi đã thấy nó được thực hiện. Thêm vào đó, nó làm tất cả mà không cần thêm, xóa hoặc thay đổi các yếu tố trên trang.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}

7
Cảnh báo: nó không thoát dấu ngoặc kép nên bạn không thể sử dụng đầu ra bên trong các giá trị thuộc tính trong mã HTML. Ví dụ: var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'sẽ mang lại HTML không hợp lệ!
izogfif

17

Thật thú vị khi tìm một giải pháp tốt hơn:

var escapeHTML = function(unsafe) {
  return unsafe.replace(/[&<"']/g, function(m) {
    switch (m) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '"':
        return '&quot;';
      default:
        return '&#039;';
    }
  });
};

Tôi không phân tích cú pháp >vì nó không phá vỡ mã XML / HTML trong kết quả.

Dưới đây là các điểm chuẩn: http://jsperf.com/regExairs Ngoài ra, tôi đã tạo một escapechức năng phổ quát : http://jsperf.com/regapidairs2


1
Thật thú vị khi thấy rằng sử dụng công tắc nhanh hơn đáng kể so với bản đồ. Tôi không mong đợi điều này! Cám ơn vì đã chia sẻ!
Peter T.

Có rất nhiều ký tự unicode nhiều hơn mức bạn có thể mã & đưa vào tài khoản. Tôi sẽ không đề nghị phương pháp thủ công này cả.
vsync

Tại sao bạn lại thoát các ký tự nhiều byte? Chỉ cần sử dụng UTF-8 ở mọi nơi.
Sơ khai

4
Bỏ qua> có khả năng phá vỡ mã. Bạn phải nhớ rằng bên trong <> cũng là html. Trong trường hợp đó bỏ qua> sẽ phá vỡ. Nếu bạn chỉ thoát giữa các thẻ thì có lẽ bạn chỉ cần thoát <và &.
jgmjgm

8

Cách ngắn gọn và hiệu quả nhất để hiển thị văn bản chưa được mã hóa là sử dụng thuộc textContenttính.

Nhanh hơn sử dụng innerHTML. Và đó là không có tài khoản thoát trên đầu.

document.body.textContent = 'a <b> c </b>';


@ZzZombo, điều hoàn toàn bình thường là nó không hoạt động với các thẻ kiểu và tập lệnh. Khi bạn thêm nội dung vào chúng, bạn thêm , không phải văn bản , sử dụng InternalHTML trong trường hợp này. Hơn nữa, bạn không cần phải thoát nó, đây là hai thẻ đặc biệt không được phân tích cú pháp dưới dạng HTML. Khi phân tích cú pháp, nội dung của chúng được coi là văn bản cho đến khi chuỗi kết thúc </được đáp ứng.
người dùng

6

Hỗ trợ DOM Elements chuyển đổi văn bản sang HTML bằng cách gán cho innerText . InternalText không phải là một chức năng nhưng việc gán cho nó hoạt động như thể văn bản đã được thoát.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';

1
Ít nhất trong Chrome, việc gán văn bản nhiều dòng sẽ thêm <br>các yếu tố thay cho dòng mới, có thể phá vỡ các yếu tố nhất định, như kiểu hoặc tập lệnh. Điều createTextNodenày không dễ xảy ra vấn đề này.
ZzZombo

1
innerTextcó một số vấn đề di sản / spec. Tốt hơn để sử dụng textContent.
Roy Tinker

3

Bạn có thể mã hóa mọi ký tự trong chuỗi của mình:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

Hoặc chỉ nhắm mục tiêu các nhân vật chính để lo lắng về (&, inebreaks, <,>, "và ') như:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55">&#119;&#119;&#119;&#46;&#87;&#72;&#65;&#75;&#46;&#99;&#111;&#109;</textarea>


Viết chức năng thoát của riêng bạn nói chung là một ý tưởng tồi. Các câu trả lời khác là tốt hơn trong vấn đề này.
jannis

2

Một lớp lót (cho ES6 +):

var escapeHtml = s => (s + '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;',
    '"': '&quot;', "'": '&#39;'
})[m]);

Đối với phiên bản cũ hơn:

function escapeHtml(s) {
    return (s + '').replace(/[&<>"']/g, function (m) {
        return ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;',
            '"': '&quot;', "'": '&#39;'
        })[m];
    });
}

0

Đã giải quyết vấn đề này khi xây dựng cấu trúc DOM. Câu hỏi này đã giúp tôi giải quyết nó. Tôi muốn sử dụng một chevron kép làm dấu tách đường dẫn, nhưng nối thêm một nút văn bản mới trực tiếp dẫn đến mã ký tự thoát được hiển thị, thay vì chính ký tự:

var _div = document.createElement('div');
var _separator = document.createTextNode('&raquo;');
//_div.appendChild(_separator); /* this resulted in '&raquo;' being displayed */
_div.innerHTML = _separator.textContent; /* this was key */

0

Nếu bạn đã sử dụng các mô-đun trong ứng dụng của mình, bạn có thể sử dụng mô-đun esc-html .

import escapeHtml from 'escape-html';
const unsafeString = '<script>alert("XSS");</script>';
const safeString = escapeHtml(unsafeString);


-4

Tôi đã đưa ra giải pháp này.

Giả sử rằng chúng tôi muốn thêm một số html vào phần tử có dữ liệu không an toàn từ người dùng hoặc cơ sở dữ liệu.

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + unsafe + '</p>';
html += '</div>';

element.html(html);

Nó không an toàn trước các cuộc tấn công XSS. Bây giờ thêm điều này.

$(document.createElement('div')).html(unsafe).text();

Nên nó là

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + $(document.createElement('div')).html(unsafe).text(); + '</p>';
html += '</div>';

element.html(html);

Đối với tôi điều này dễ hơn nhiều so với việc sử dụng .replace()và nó sẽ loại bỏ !!! tất cả các thẻ html có thể (tôi hy vọng).


Đây là ý tưởng nguy hiểm, nó phân tích chuỗi HTML không an toàn dưới dạng HTML, nếu phần tử được gắn vào DOM thì nó sẽ hoạt động. sử dụng .innerText thay thế.
teknopaul

Điều này không an toàn. Nó chuyển đổi &lt;script&gt;thành <script>.
fgb
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.