Làm cách nào để giải mã các thực thể HTML bằng jQuery?


334

Làm cách nào để sử dụng jQuery để giải mã các thực thể HTML trong một chuỗi?


Sự lựa chọn sớm của công nghệ (jQuery) mời các câu trả lời với các vấn đề bảo mật. Điều này có thể tốt hơn là đóng lại như một bản sao của stackoverflow.com/questions/1912501/ ,.
Wladimir Palant

Câu trả lời:


437

Lưu ý bảo mật: sử dụng câu trả lời này (được giữ nguyên ở dạng ban đầu bên dưới) có thể đưa lỗ hổng XSS vào ứng dụng của bạn. Bạn không nên sử dụng câu trả lời này. Đọc câu trả lời của lucascaro để biết giải thích về các lỗ hổng trong câu trả lời này và sử dụng cách tiếp cận từ câu trả lời đó hoặc câu trả lời của Mark Amery .

Thật ra, hãy thử

var decoded = $("<div/>").html(encodedStr).text();

175
Đừng không làm điều này với đầu vào không tin cậy. Nhiều trình duyệt tải hình ảnh và kích hoạt các sự kiện liên quan ngay cả khi nút không được gắn vào DOM. Hãy thử chạy $("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>'). Trong Firefox hoặc Safari, nó kích hoạt cảnh báo.
Mike Samuel

@Mike, vậy bạn khuyên gì thay? câu trả lời của bạn về .replace () sẽ không tốt nếu bạn không biết bạn đang thay thế cái gì ...
ekkis

7
@ekkis, bạn cần tước thẻ trước khi cố gắng giải mã các thực thể. str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")hoặc một cái gì đó tương tự.
Mike Samuel

2
Việc triển khai tốt hơn (theo ý kiến ​​của tôi) loại bỏ hầu hết các thẻ HTML (lịch sự của Mike) khỏi đầu vào nằm trong câu trả lời của tôi cho một câu hỏi tương tự . Nó cũng không có chi phí hoạt động của jQuery nên khá phù hợp với các môi trường khác.
Robert K

6
@MichaelStum chỉnh sửa của bạn ở đây đã vô hiệu hóa cả nhận xét của Mike Samuel và câu trả lời được bình chọn cao nhất tiếp theo, và đã làm như vậy mà không thực sự sửa lỗ hổng XSS cho tất cả các phiên bản jQuery (như được giải thích trong câu trả lời bên dưới). Thêm một cảnh báo bảo mật cho câu trả lời này sẽ hợp lý (và tôi sẽ làm như vậy); kết xuất cuộc thảo luận khác trên trang này vô nghĩa trong khi không thực sự sửa lỗ hổng bảo mật chắc chắn là không!
Đánh dấu Amery

211

Không có bất kỳ jQuery nào:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

Điều này hoạt động tương tự như câu trả lời được chấp nhận , nhưng an toàn để sử dụng với đầu vào của người dùng không tin cậy.


Vấn đề bảo mật trong cách tiếp cận tương tự

Như Mike Samuel đã lưu ý , thực hiện việc này <div>thay vì <textarea>đầu vào của người dùng không đáng tin cậy là một lỗ hổng XSS, ngay cả khi <div>không bao giờ được thêm vào DOM:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')

Tuy nhiên, cuộc tấn công này là không thể đối với a <textarea>vì không có yếu tố HTML nào được cho phép nội dung của a <textarea>. Do đó, mọi thẻ HTML vẫn có trong chuỗi 'được mã hóa' sẽ được trình duyệt tự động mã hóa bằng thực thể.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))

Cảnh báo : Thực hiện việc này bằng cách sử dụng jQuery .html().val()các phương thức thay vì sử dụng .innerHTML.valuecũng không an toàn * đối với một số phiên bản của jQuery, ngay cả khi sử dụng atextarea . Điều này là do các phiên bản cũ hơn của jQuery sẽ đánh giá một cáchchủ ý và rõ ràng các tập lệnh có trong chuỗi được truyền tới .html(). Do đó mã như thế này hiển thị cảnh báo trong jQuery 1.8:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* Cảm ơn Eru Penkman vì đã nắm bắt được lỗ hổng này.


6
Có thể là một ý tưởng tốt để phá hủy vùng văn bản sau khi trích xuất giá trị của nó:decodedString = textArea.value; textArea.remove(); return decodedString;
Werner

2
Hoặc chỉ khi phiên bản javascript thực sự hỗ trợ remove ():if ('remove' in Element.prototype) textArea.remove();
Werner

6
@Werner Ngay sau khi chức năng đã thoát, sẽ không còn biến nào chứa tham chiếu đến nó để nó sẽ tự động bị xóa bởi trình thu gom rác .
dùng2428118

Tôi đang sử dụng kết hợp với .NET từ mã phía sau một lần bấm nút và vì một số lý do, câu trả lời được chấp nhận đã gây ra hậu quả. Câu trả lời này không có, vì vậy đây là câu trả lời tốt nhất cho tôi. Cảm ơn!
Snailer

@Snailer $("<div />").html(string).text() sẽ thực thi bất kỳ javascript nào trong chuỗi được cung cấp , mà tôi nghi ngờ là nguyên nhân gây ra vấn đề của bạn. Câu trả lời được chấp nhận nên được cập nhật cho câu hỏi này.
jbowman

80

Giống như Mike Samuel đã nói, đừng sử dụng jQuery.html (). Text () để giải mã các thực thể html vì nó không an toàn.

Thay vào đó, hãy sử dụng trình kết xuất mẫu như Mustache.js hoặc decodeEntities từ nhận xét của @ VyvIT.

Thư viện vành đai tiện ích Underscore.js đi kèm escapeunescapecác phương thức, nhưng chúng không an toàn cho đầu vào của người dùng:

_.escape (chuỗi)

_.unescape (chuỗi)


2
Điều này thực sự xứng đáng cách upvote nhiều hơn! Chắc chắn là giải pháp ưa thích của tôi. Chúng bao gồm unescapetrong các tài liệu bây giờ, btw.
lethal-guitar

5
_.unescape("&#39;")kết quả chỉ trong "& # 39;" thay vì một trích dẫn Có thứ gì đó tôi thiếu hoặc không gạch dưới không thoát khỏi mã thực thể HTML như được hiển thị trên: w3schools.com/tags/ref_entities.asp
Jason Axelson

6
Lỗi trên github đã bị đóng là "Không sửa"; điều đó có nghĩa là giải pháp này không hoạt động và sẽ không hoạt động.
Igor Chubin

3
Bạn nói rằng " escapeunescapephương thức ... của Underscore không an toàn cho đầu vào của người dùng" . Bạn có ý nghĩa gì bởi điều này? Nghe có vẻ vô nghĩa với tôi, nhưng có lẽ tôi đang thiếu một cái gì đó - bạn có thể làm rõ không?
Đánh dấu Amery

2
@VyvIT Đã thử _.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(trong Chrome / FF / IE). Nhưng nó đã không hiển thị bất kỳ cảnh báo. Đã thử nó trong giao diện điều khiển cũng như đặt nó trong tệp JS của tôi. Cùng một kết quả.
Vivek Athalye

28

Tôi nghĩ bạn đang nhầm lẫn giữa các phương thức văn bản và HTML. Nhìn vào ví dụ này, nếu bạn sử dụng HTML bên trong của một thành phần làm văn bản, bạn sẽ nhận được các thẻ HTML được giải mã (nút thứ hai). Nhưng nếu bạn sử dụng chúng dưới dạng HTML, bạn sẽ có chế độ xem được định dạng HTML (nút đầu tiên).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>

Nút đầu tiên ghi: đây là một nội dung HTML .

Nút thứ hai ghi: đây là nội dung <B> HTML </ B>.

Nhân tiện, bạn có thể thấy một trình cắm mà tôi tìm thấy trong plugin jQuery - giải mã HTML và mã hóa mã hóa và giải mã chuỗi HTML.


26

Câu hỏi bị giới hạn bởi 'với jQuery' nhưng nó có thể giúp một số người biết rằng mã jQuery được đưa ra trong câu trả lời hay nhất ở đây thực hiện như sau bên dưới ... điều này hoạt động có hoặc không có jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}

20

Bạn có thể sử dụng thư viện anh ấy , có sẵn từ https://github.com/mathiasbynens/he

Thí dụ:

console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"

Tôi đã thách thức tác giả của thư viện về câu hỏi liệu có lý do nào để sử dụng thư viện này trong mã máy khách để ủng hộ vụ <textarea>hack được cung cấp trong các câu trả lời khác ở đây và ở nơi khác không. Ông cung cấp một vài lời biện minh có thể:

  • Nếu bạn đang sử dụng máy chủ node.js, sử dụng thư viện để mã hóa / giải mã HTML cung cấp cho bạn một giải pháp duy nhất hoạt động cả máy khách và máy chủ.

  • Các thuật toán giải mã thực thể của một số trình duyệt có lỗi hoặc thiếu hỗ trợ cho một số tham chiếu ký tự được đặt tên . Ví dụ: Internet Explorer sẽ giải mã và kết xuất không gian không phá vỡ ( &nbsp;) một cách chính xác nhưng báo cáo chúng là không gian thông thường thay vì không phá vỡ thông qua thuộc innerTexttính của phần tử DOM , phá vỡ <textarea>hack (dù chỉ là một cách nhỏ). Ngoài ra, IE 8 và 9 đơn giản là không hỗ trợ bất kỳ tham chiếu ký tự có tên mới nào được thêm vào HTML 5. Tác giả của anh ta cũng tổ chức một thử nghiệm hỗ trợ tham chiếu ký tự có tên tại http://mathias.html5.org/tests/html / tên-ký tự-tài liệu tham khảo / . Trong IE 8, nó báo cáo hơn một nghìn lỗi.

    Nếu bạn muốn được cách ly khỏi các lỗi trình duyệt liên quan đến giải mã thực thể và / hoặc có thể xử lý toàn bộ các tham chiếu ký tự được đặt tên, bạn không thể thoát khỏi vụ <textarea>hack; bạn sẽ cần một thư viện như ông .

  • Anh ta chỉ cảm thấy như làm mọi thứ theo cách này là ít hack hơn.


4
+1 jQuery không phải là giải pháp cho mọi thứ. Sử dụng các công cụ thích hợp cho công việc.
Mathias Bynens

Đây là cách tốt nhất để giải mã các thực thể HTML. Tất cả các câu trả lời khác (về câu hỏi này và các câu hỏi tương tự) đều sử dụng InternalHTML (tạo phần tử HTML mới, xử lý mã HTML và sau đó lấy phần bên trong của phần tử đó, điều này có thể dễ bị tấn công XSS nếu bạn không RẤT cẩn thận, xem thêm ) hoặc chúng đề xuất sử dụng các phương thức unescape.js unescape hoặc Lodash unescape không hoàn chỉnh (chỉ hoạt động đối với một vài thực thể HTML). Thư viện ông là lựa chọn đầy đủ và an toàn nhất!
ands

18

mã hóa:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

giải mã:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'

3
đã có một câu trả lời hoạt động, và nó gần như giống hệt với điều này. Chúng tôi không cần câu trả lời trùng lặp
markasoftware

4
Đây là câu trả lời hợp lệ. Câu trả lời của tom sử dụng phần tử DIV, khiến câu trả lời đó dễ bị tổn thương với XSS.
Francisco Hodge

2
Đây là câu trả lời tốt nhất cho sự rõ ràng.
Dan Randolph

4

Sử dụng

myString = myString.replace( /\&amp;/g, '&' );

Dễ dàng nhất để làm điều đó ở phía máy chủ vì rõ ràng JavaScript không có thư viện riêng để xử lý các thực thể, tôi cũng không tìm thấy bất kỳ kết quả tìm kiếm nào ở gần đầu của các khung công tác mở rộng JavaScript.

Tìm kiếm "các thực thể HTML JavaScript" và bạn có thể tìm thấy một vài thư viện cho mục đích đó, nhưng tất cả chúng có thể được xây dựng xung quanh logic trên - thay thế, thực thể theo thực thể.


0

Tôi chỉ cần có một charater thực thể HTML () làm giá trị cho nút HTML. Mã HTML có vẻ tốt ngay từ đầu trong trình duyệt:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

Bây giờ tôi đã thêm một nút chuyển đổi cũng sẽ hiển thị bảng xếp hạng. Đây là giải pháp của tôi

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

Điều này sẽ hiển thị ⇓ một lần nữa trong nút. Tôi hy vọng điều này có thể giúp một ai đó.


Đơn giản hơn sẽ là sử dụng chuỗi thoát unicode (nghĩa là "Embed & Share \u21d1") hoặc tốt hơn là chỉ "Embed & Share ⇑"khi bạn có thể phục vụ tập lệnh của mình trong UTF-8 (hoặc UTF-16 hoặc bất kỳ mã hóa nào khác hỗ trợ ký tự). Sử dụng một phần tử DOM để phân tích một thực thể HTML chỉ để nướng một ký tự unicode tùy ý vào một chuỗi JavaScript là một cách tiếp cận sáng tạo và khôn ngoan sẽ khiến Rube Goldberg tự hào, nhưng không phải là cách thực hành tốt; thoát unicode là trong ngôn ngữ đặc biệt để xử lý trường hợp sử dụng này.
Đánh dấu Amery

0

Bạn phải tạo chức năng tùy chỉnh cho các thực thể html:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}

Tôi không biết, nó đã giúp tôi rất nhiều l-)
Szymon Toda

có thể nó đã được bỏ phiếu vì nó chỉ xử lý một số thực thể.
Jasen

Câu hỏi ban đầu là làm thế nào để giải mã các thực thể - điều này trái ngược với những gì mong muốn; nó mã hóa một tập hợp các ký tự cực kỳ giới hạn thành các thực thể. Như tooltip bỏ phiếu nói, "Câu trả lời này không hữu ích". Tôi ngạc nhiên rằng sau 4 năm nó vẫn có điểm số dương.
Stephen P

0

Giả sử bạn có chuỗi bên dưới.

Cabin Deluxe của chúng tôi ấm áp, ấm cúng & amp; Thoải mái

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str và gán lại cho

nhãn.

đó là nó.


0

Đối với người dùng ExtJS, nếu bạn đã có chuỗi được mã hóa, ví dụ: khi giá trị được trả về của hàm thư viện là nội dung bên trongHTML, hãy xem xét hàm ExtJS này:

Ext.util.Format.htmlDecode(innerHtmlContent)

Điều này sẽ chỉ hoạt động cho 5 thực thể HTML. Bạn có thể thấy điều này trong tài liệumã nguồn .
ands

0

Mở rộng một lớp String:

String::decode = ->
  $('<textarea />').html(this).text()

và sử dụng như phương pháp:

"&lt;img src='myimage.jpg'&gt;".decode()

0

Thử cái này :

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

phân tích là một Hàm trong thư viện Jquery và nó sẽ trả về một mảng bao gồm một số chi tiết về Chuỗi đã cho ..

trong một số trường hợp, Chuỗi đang lớn, do đó, hàm sẽ phân tách nội dung thành nhiều chỉ mục ..

và để có được tất cả các dữ liệu chỉ mục, bạn nên truy cập vào bất kỳ chỉ mục nào, sau đó truy cập vào chỉ mục có tên là "WholeText".

Tôi đã chọn chỉ số 0 vì nó sẽ hoạt động trong mọi trường hợp (Chuỗi nhỏ hoặc chuỗi lớn).


Mặc dù đoạn mã này có thể là giải pháp, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
Johan

Lời giải thích được thêm vào ... Cảm ơn bạn :)
Fawaz Al Romy

-1

Đây vẫn là một vấn đề: Chuỗi thoát không thể đọc được khi được gán cho giá trị đầu vào

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

Exapmle: https://jsfiddle.net/kjpdwmqa/3/


Đây không phải là một câu trả lời cho câu hỏi. OP yêu cầu giải mã thực thể HTML (unescape), nhưng trong câu trả lời này, bạn đang sử dụng escapephương thức Underscore.js. Ngoài ra, không có lời giải thích làm thế nào mẫu mã của bạn sẽ giải quyết vấn đề của OP.
ands

-1

Ngoài ra, cũng có một thư viện cho nó ..

tại đây, https://cdnjs.com/lologists/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

Cách sử dụng như sau ...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

chúc mừng


Đã có câu trả lời về thư viện anh ta đã hoàn tất, với ví dụ mã đơn giản và giải thích tốt tại sao và khi nào bạn nên sử dụng thư viện anh ta .
ands

-3

Để giải mã các thực thể HTML bằng jQuery, chỉ cần sử dụng chức năng này:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

Cách sử dụng:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />

-3

Cách dễ nhất là đặt bộ chọn lớp cho các thành phần của bạn và sau đó sử dụng mã sau:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

Không còn gì cần thiết nữa!

Tôi đã có vấn đề này và tìm thấy giải pháp rõ ràng này và nó hoạt động tốt.


Đây không phải là một câu trả lời cho câu hỏi của OP. OP yêu cầu giải mã các thực thể HTML trong CHUINGI, không chỉ điều này không giải quyết được vấn đề của OP mà còn thay thế các thực thể HTML đã thoát trong phần tử HTML bằng các phần tử không được thực hiện.
ands

-3

Tôi nghĩ đó là điều hoàn toàn ngược lại với giải pháp được chọn.

var decoded = $("<div/>").text(encodedStr).html();
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.