Bisakah saya menghindari karakter khusus html di javascript?

201

Saya ingin menampilkan teks ke HTML dengan fungsi javascript. Bagaimana saya bisa menghindari karakter khusus html di JS? Apakah ada API?

fernando123
sumber
11
Ini bukan duplikat, karena pertanyaan ini tidak menanyakan tentang jQuery. Saya hanya tertarik pada yang ini, karena saya tidak menggunakan jQuery ...
lvella

Jawaban:

330
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
sumber
11
Mengapa "& # 039;" dan bukan "& apos;" ?
sereda
2
Saya pikir ungkapan reguler dalam replace()panggilan tidak perlu. String single-karakter lama yang biasa juga bisa digunakan.
jamix
22
@ jamix Anda tidak dapat melakukan penggantian global dengan string mentah, sementara mesin browser modern mengoptimalkan ekspresi reguler sederhana cukup bagus.
bjornd
5
apakah ada API standar atau ini satu-satunya cara?
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;'>

spiderlama
sumber
Bekerja di Sini tetapi Tidak berfungsi untuk saya offline di browser
48

Anda dapat menggunakan fungsi jQuery.text() .

Sebagai contoh:

http://jsfiddle.net/9H6Ch/

Dari dokumentasi jQuery tentang .text()fungsi:

Kita perlu menyadari bahwa metode ini lolos dari string yang disediakan sehingga perlu diurai dengan benar dalam HTML. Untuk melakukannya, ia memanggil metode DOM .createTextNode (), tidak menafsirkan string sebagai HTML.

Versi sebelumnya dari Dokumentasi jQuery mengatakannya seperti ini ( penekanan ditambahkan ):

Kita perlu menyadari bahwa metode ini lolos dari string yang disediakan sehingga perlu diurai dengan benar dalam HTML. Untuk melakukannya, ia memanggil metode DOM .createTextNode (), yang menggantikan karakter khusus dengan setara entitas HTML mereka (seperti & lt; untuk <).

jeremysawesome
sumber
3
Anda bahkan dapat menggunakannya pada elemen segar jika Anda hanya ingin mengonversi seperti ini: const str = "foo<>'\"&"; $('<div>').text(str).html()yieldsfoo&lt;&gt;'"&amp;
amoebe
28

Saya rasa saya menemukan cara yang tepat untuk melakukannya ...

// 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);
lvella
sumber
Saya belajar sesuatu yang baru tentang HTML hari ini. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio
1
Ketahuilah bahwa konten dari simpul teks tidak luput jika Anda mencoba mengaksesnya seperti ini:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler
Ini adalah cara yang benar jika semua yang Anda lakukan adalah mengatur teks. Itu juga textContent tetapi ternyata itu tidak didukung dengan baik. Namun ini tidak akan berhasil jika Anda membuat string dengan beberapa bagian teks html, maka Anda harus tetap melarikan diri.
jgmjgm
20

Sejauh ini, ini adalah cara tercepat yang pernah saya lakukan. Plus, itu melakukan semuanya tanpa menambahkan, menghapus, atau mengubah elemen pada halaman.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
arjunpat
sumber
7
Peringatan: tidak keluar dari tanda kutip sehingga Anda tidak dapat menggunakan output di dalam nilai atribut dalam kode HTML. Misalnya var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'akan menghasilkan HTML yang tidak valid!
izogfif
17

Sangat menarik untuk menemukan solusi yang lebih baik:

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

Saya tidak menguraikan >karena tidak merusak kode XML / HTML dalam hasilnya.

Berikut adalah tolok ukurnya: http://jsperf.com/regexpairs Juga, saya membuat escapefungsi universal : http://jsperf.com/regexpairs2

iegik
sumber
1
Sangat menarik untuk melihat bahwa menggunakan saklar secara signifikan lebih cepat daripada peta. Saya tidak mengharapkan ini! Terima kasih telah berbagi!
Peter T.
Ada banyak karakter unicode lebih banyak daripada yang Anda bisa kode & memperhitungkan. Saya tidak akan merekomendasikan metode manual ini sama sekali.
vsync
Mengapa Anda bisa keluar dari karakter multi-byte sama sekali? Cukup gunakan UTF-8 di mana-mana.
Neonit
4
Melewati> berpotensi memecahkan kode. Anda harus ingat bahwa di dalam <> juga html. Jika demikian, melompati> akan pecah. Jika Anda hanya melarikan diri dari tag, maka Anda mungkin hanya perlu melarikan diri <dan &.
jgmjgm
8

Cara paling ringkas dan performan untuk menampilkan teks yang tidak disandi adalah dengan menggunakan textContentproperti.

Lebih cepat daripada menggunakan innerHTML. Dan itu tanpa memperhitungkan keluar biaya overhead.

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

pengguna
sumber
@ZZZombo, benar-benar normal bahwa itu tidak berfungsi dengan tag gaya dan skrip. Ketika Anda menambahkan konten ke dalamnya, Anda menambahkan kode , bukan teks , gunakan innerHTML dalam hal ini. Selain itu, Anda tidak perlu menghindarinya, ini adalah dua tag khusus yang tidak diuraikan sebagai HTML. Saat parsing, kontennya diperlakukan sebagai teks hingga urutan penutupan </terpenuhi.
pengguna
6

DOM Elements mendukung konversi teks ke HTML dengan menetapkan ke innerText . innerText bukan fungsi tetapi menugaskannya berfungsi seolah-olah teks itu lolos.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
teknopaul
sumber
1
Paling tidak di Chrome yang menetapkan teks multiline menambahkan <br>elemen menggantikan baris baru, yang dapat merusak elemen tertentu, seperti gaya atau skrip. Tidak createTextNoderentan terhadap masalah ini.
ZzZombo
1
innerTextmemiliki beberapa masalah warisan / spesifikasi. Lebih baik digunakan textContent.
Roy Tinker
3

Anda dapat menyandikan setiap karakter di string Anda:

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

Atau hanya menargetkan karakter utama yang perlu dikhawatirkan (&, inebreaks, <,>, "dan ') seperti:

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>

Dave Brown
sumber
Menulis fungsi pelarian Anda sendiri umumnya merupakan ide yang buruk. Jawaban lain lebih baik dalam hal ini.
jannis
2

Satu kalimat (untuk ES6 +):

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

Untuk versi yang lebih lama:

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

Datang di masalah ini saat membangun struktur DOM. Pertanyaan ini membantu saya menyelesaikannya. Saya ingin menggunakan chevron ganda sebagai pemisah jalur, tetapi menambahkan simpul teks baru secara langsung menghasilkan kode karakter yang lolos, bukan karakter itu sendiri:

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 */
Silas
sumber
0

Jika Anda sudah menggunakan modul di aplikasi Anda, Anda bisa menggunakan modul escape-html .

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

Coba ini, menggunakan prototype.jsperpustakaan:

string.escapeHTML();

Coba demo

Beruntung
sumber
5
Ini membutuhkan pustaka "prototype.js", yang tidak segera terlihat dari demo. :(
audiodude
-4

Saya datang dengan solusi ini.

Mari kita asumsikan bahwa kita ingin menambahkan beberapa html ke elemen dengan data yang tidak aman dari pengguna atau database.

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

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

element.html(html);

Tidak aman terhadap serangan XSS. Sekarang tambahkan ini.

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

Begitulah

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);

Bagi saya ini jauh lebih mudah daripada menggunakan .replace()dan itu akan dihapus !!! semua kemungkinan tag html (saya harap).

Kostiantyn
sumber
ini adalah ide yang berbahaya, itu mem-parsing String HTML yang tidak aman sebagai HTML, jika elemen dilampirkan ke DOM itu akan exeute. gunakan .innerText sebagai gantinya.
teknopaul
Ini tidak aman. Itu dikonversi &lt;script&gt;menjadi <script>.
fgb