Tetapkan input yang tidak dipercayai dengan selamat kepada sifat tersuai CSS tanpa JavaScript: Panduan
P粉356361722
P粉356361722 2023-09-06 22:32:52
0
1
714

Andaikan saya mempunyai objek kunci rentetan dan nilai rentetan, dan saya mahu menulisnya sebagai sifat tersuai CSS ke dalam beberapa HTML yang dijana pelayan. Bagaimanakah saya boleh melakukan ini dengan selamat?

Apa yang saya maksudkan dengan keselamatan

  • Jika boleh, pengisytiharan sifat tersuai seharusnya tidak menyebabkan ralat sintaks CSS, menghalang penyemak imbas daripada menghuraikan dengan betul pengisytiharan gaya lain atau bahagian dokumen HTML. Jika atas sebab tertentu ini tidak boleh dilakukan, pasangan nilai kunci harus diabaikan.
  • Lebih penting lagi, ini sepatutnya menjadikan skrip merentas tapak menjadi mustahil.

Untuk memudahkan, saya akan mengehadkan kekunci untuk membenarkan aksara sahaja dalam kelas [a-zA-Z0-9_-].

Daripada membaca spesifikasi CSS dan beberapa ujian peribadi, saya rasa anda boleh membuat banyak kemajuan mendapatkan nilai dengan mengikuti langkah berikut:

  • Cari rentetan
  • Pastikan setiap petikan diikuti oleh petikan lain (tidak terlepas) daripada jenis yang sama (" atau '). Jika ini tidak berlaku, buang pasangan kunci/nilai ini.
  • Pastikan setiap pendakap bukaan {([字符串外部的 di luar rentetan mempunyai pendakap penutup yang sepadan. Jika tidak, buang pasangan nilai kunci ini.
  • Gunakan semua contoh 3C 转义 < 的所有实例,以及使用 3E 转义 >.
  • Gunakan semua contoh 3B; untuk melarikan diri.

Saya membuat langkah di atas berdasarkan spesifikasi sintaks CSS ini

Untuk konteks, sifat ini boleh digunakan oleh gaya yang ditentukan pengguna yang kami sisipkan di tempat lain, tetapi objek yang sama juga digunakan sebagai data templat dalam templat, jadi ia mungkin mengandungi campuran rentetan yang dimaksudkan sebagai kandungan dan rentetan yang dijangkakan sebagai pembolehubah CSS . Saya rasa algoritma di atas mencapai keseimbangan yang baik kerana menjadi sangat mudah tanpa menghadapi risiko membuang terlalu banyak pasangan nilai kunci yang mungkin berguna dalam CSS (malah membenarkan penambahan CSS pada masa hadapan, tetapi saya ingin memastikan saya tidak 't Rindu sesuatu


Berikut ialah beberapa kod JS yang menunjukkan perkara yang saya ingin capai. obj 是有问题的对象,而 preprocessPairs ialah fungsi yang mengambil objek dan memprosesnya terlebih dahulu, mengalih keluar/memformat semula nilai seperti yang diterangkan dalam langkah di atas.

function generateThemePropertiesTag(obj) {
  obj = preprocessPairs(obj);
  return `<style>
:root {
${Object.entries(obj).map(([key, value]) => {
  return `--theme-${key}: ${value};`
}).join("\n")}
}
</style>`
}

Jadi bila diberi objek seperti ini

{
  "color": "#D3A",
  "title": "The quick brown fox"
}

Saya mahu CSS kelihatan seperti ini:

:root {
--theme-color: #D3A;
--theme-title: The quick brown fox;
}

Walaupun --theme-title ialah pembolehubah tersuai yang tidak berguna apabila digunakan dalam CSS, ia sebenarnya tidak memecahkan lembaran gaya kerana CSS mengabaikan sifat yang tidak difahaminya.

P粉356361722
P粉356361722

membalas semua(1)
P粉898107874

Kami sebenarnya mungkin hanya menggunakan ungkapan biasa dan beberapa algoritma lain tanpa perlu bergantung pada bahasa tertentu, mudah-mudahan itulah yang anda perlukan.

Dengan mengisytiharkan bahawa kunci objek berada di dalam [a-zA-Z0-9_-] kita perlu menghuraikan nilai entah bagaimana.

Model Nilai

Jadi kita boleh memecahkannya ke dalam kategori dan melihat perkara yang kita temui (ia mungkin dipermudahkan sedikit untuk kejelasan):

  1. '.*' (rentetan yang dikelilingi oleh tanda kutip; tamak)
  2. ".*" (Rentetan yang disertakan dalam petikan berganda; tamak)
  3. [+-]?d+(.d+)?(%|[A-z]+)? (integer dan perpuluhan, peratusan pilihan atau dengan unit)
  4. #[0-9A-f]{3,6}(warna)
  5. [A-z0-9_-]+ (Kata kunci, menamakan warna, "mudah masuk", dll.)
  6. ([w-]+)([^)]+) (类似 url()calc() fungsi > dsb.)

Penapis pertama

Saya boleh bayangkan anda boleh melakukan beberapa penapisan sebelum cuba mengenal pasti corak ini. Mungkin kita memangkas rentetan nilai dahulu. Seperti yang anda nyatakan, > 可以在 preprocessPairs() terlepas pada permulaan fungsi kerana ia tidak akan muncul seperti mana-mana corak yang kami ada di atas. Jika anda tidak mahu koma bertitik yang tidak dilepaskan muncul di mana-mana, anda juga boleh melarikan diri daripadanya.

Corak pengecaman

Kita kemudian boleh cuba mengenal pasti corak ini dalam nilai, dan untuk setiap corak kita mungkin perlu menjalankan penapisan sekali lagi. Kami menjangkakan corak ini akan dipisahkan oleh beberapa (atau dua) aksara ruang putih.

Tidak mengapa untuk menyertakan sokongan untuk rentetan berbilang baris, yang merupakan baris baharu yang terlepas.

Tempatan

Kita perlu sedar bahawa kita mempunyai sekurang-kurangnya dua konteks untuk ditapis - HTML dan CSS. Apabila kita berada dalam atribut 元素中包含样式时,输入必须是安全的,同时它必须是有效的 CSS。幸运的是,您没有将 CSS 包含在元素的 style, jadi ini lebih mudah sedikit.

Penapisan berasaskan corak nilai

  1. Rentetan yang dikelilingi oleh apostrof - kami tidak mempedulikan apa-apa kecuali apostrof dan koma bertitik, jadi kami perlu mencari unescapedcontoh watak ini dalam rentetan dan melarikan diri darinya
  2. Sama seperti di atas, hanya gunakan petikan berganda
  3. Sepatutnya tiada masalah
  4. Sepatutnya tiada masalah
  5. Pada asasnya tiada masalah
  6. Ini bahagian yang menyeronokkan

Jadi mata 1-5 akan menjadi sangat mudah dan kebanyakan nilai akan dilindungi oleh penapisan dan pemangkasan mudah dari hadapan. Dengan beberapa penambahan (tidak tahu apa impak pada prestasi) ia mungkin melakukan semakan tambahan untuk unit, kata kunci, dsb.

Tetapi berbanding mata lain, saya rasa cabaran yang agak besar ialah mata 6. Anda mungkin memutuskan untuk melumpuhkan sahaja url() ,让您检查函数的输入,因此例如您可能想要转义分号,甚至可能通过微小的调整再次检查函数内的模式例如对于calc() dalam gaya tersuai ini.

Kesimpulan

Secara keseluruhan, ini adalah pendapat saya. Dengan beberapa tweak pada ungkapan biasa ini, ia sepatutnya melengkapkan perkara yang anda sudah lakukan dan memberikan anda sebanyak mungkin fleksibiliti dalam menaip CSS sambil menyelamatkan anda daripada perlu mengubah suai kod anda setiap kali anda mengubah suai ciri CSS.

Contoh

function preprocessPairs(obj) {
  // Catch-all regular expression
  // Explanation:
  // (                                   Start of alternatives
  //   \w+\(.+?\)|                       1st alternative - function
  //   ".+?(?<!\)"|                     2nd alternative - string with double quotes
  //   '.+?(?<!\)'|                     3rd alternative - string with apostrophes
  //   [+-]?\d+(?:\.\d+)?(?:%|[A-z]+)?|  4th alternative - integer/decimal number, optionally per cent or with a unit
  //   #[0-9A-f]{3,6}|                   5th alternative - colour
  //   [A-z0-9_-]+|                      6th alternative - keyword
  //   ''|                               7th alternative - empty string
  //   ""                                8th alternative - empty string
  // )
  // [\s,]*
  const regexA = /(\w+\(.+?\)|".+?(?<!\)"|'.+?(?<!\)'|[+-]?\d+(?:\.\d+)?(?:%|[A-z]+)?|#[0-9A-f]{3,6}|[A-z0-9_-]+|''|"")[\s,]*/g;

  // newObj contains filtered testObject
  const newObj = {};

  // Loop through all object properties
  Object.entries(obj).forEach(([key, value]) => {
    // Replace <>;
    value = value.trim().replace('<', '\00003C').replace('>', '\00003E').replace(';', '\00003B');

    // Use catch-all regex to split value into specific elements
    const matches = [...value.matchAll(regexA)];

    // Now try to build back the original value string from regex matches.
    // If these strings are equal, the value is what we expected.
    // Otherwise it contained some unexpected markup or elements and should
    // be therefore discarded.
    // We specifically set to ignore all occurences of url() and @import
    let buildBack = '';
    matches.forEach((match) => {
      if (Array.isArray(match) && match.length >= 2 && match[0].match(/url\(.+?\)/gi) === null && match[0].match(/@import/gi) === null) {
        buildBack += match[0];
      }
    });

    console.log('Compare\n');
    console.log(value);
    console.log(buildBack);
    console.log(value === buildBack);

    if (value === buildBack) {
      newObj[key] = value;
    }
  });

  return newObj;
}

Sila ulas, bincang, kritik dan beritahu saya jika saya terlupa menyentuh topik yang menarik minat anda.

Sumber

Penafian: Saya bukan pengarang, pemilik, pelabur atau penyumbang sumber yang dinyatakan di bawah. Saya kebetulan menggunakannya untuk mendapatkan beberapa maklumat.

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan