HTML / PHP ile XSS nasıl önlenir?


256

Yalnızca HTML ve PHP kullanarak XSS'yi (siteler arası komut dosyası oluşturma) nasıl engelleyebilirim?

Bu konuda çok sayıda başka yayın gördüm, ancak XSS'yi gerçekten nasıl önleyeceğimizi açık ve kısaca ifade eden bir makale bulamadım.


3
Bunun, kullanıcı girişini HTML özelliği olarak kullanmak isteyebileceğiniz durumu çözmeyeceğini unutmayın. Örneğin, bir görüntünün kaynak URL'si. Yaygın bir durum değil, unutması kolay bir durum.
Michael Mior

@MichaelMior, XSS hrefveya srcHTML özelliğini önlemek için bir çözümdür : stackoverflow.com/questions/19047119/…
baptx

Burada XSS ve farklı dillerde nasıl önlenebileceğini anlatan güzel bir makale var (PHP dahil).
XCore

Yanıtlar:


297

Temel htmlspecialchars()olarak, kullanıcı girişinden gelen tarayıcıya bir şey çıkarmak istediğinizde işlevi kullanmanız gerekir .

Bu işlevi kullanmanın doğru yolu şudur:

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

Google Code Üniversitesi, Web Güvenliği hakkında şu eğitici videolara da sahiptir:


7
@TimTim: Çoğu durumda evet. Ancak, HTML girişinin biraz daha karmaşık olmasına izin vermeniz gerektiğinde ve bu durumda htmlpurifier.org
Alix Axel

@Alix Axel, peki cevabınız htmlspecialchars kullanmak mı yoksa htmlpurifier.org kullanmak ?
TimTim

3
HTML girişini kabul etmeniz gerekiyorsa, HTML Temizleyici kullanın htmlspecialchars().
Alix Axel

9
htmlsözel grafikler veya htmlentities? Buradan kontrol edin stackoverflow.com/questions/46483/…
kiranvj

4
Çoğu zaman doğrudur, ancak bu kadar basit değildir. Güvenilmeyen dizeyi HTML, Js, Css'e koymayı ve güvenilmeyen HTML'yi HTML'ye koymayı düşünmelisiniz. Şuna bak: owasp.org/index.php/…
bronz adam

41

En sevdiğim OWASP referanslarımdan biri de Siteler Arası Komut Dosyası açıklamasıdır, çünkü çok sayıda XSS saldırı vektörü varken, birkaç kuralın izlenmesi bunların çoğuna karşı büyük ölçüde savunabilir!

Bu PHP Güvenlik Hile Sayfası


7
Ben de .. Bu XSS Filtre Kaçırma

1
Tam olarak XSS değil, ama bence XSS ve CSRF yaygın olarak karışık ve her ikisi de gerçekten tehlikeli: owasp.org/index.php/…
Simon

2
Bu sayfa artık mevcut değil
Mazzy


15

En önemli adımlardan biri, herhangi bir kullanıcı girişini işlenmeden ve / veya tarayıcıya geri dönüştürülmeden önce sterilize etmektir. PHP'nin bir " filtresi var " işlevleri vardır.

XSS saldırılarının genellikle sahip olduğu form, kullanıcı için kötü niyetli amaç içeren bazı site dışı javascriptlere bir bağlantı eklemektir. Bununla ilgili daha fazla bilgi edinin buradan edinebilirsiniz .

Ayrıca sitenizi test etmek istersiniz - Firefox eklentisi XSS Me'yi önerebilirim .


Girişi tam olarak temizlediğimden emin olmak için neye ihtiyacım var. Dikkat etmem gereken belirli bir karakter / dize var mı?
TimTim

27
@TimTim - hayır. Tüm kullanıcı girdileri her zaman doğal olarak düşmanca kabul edilmelidir .
zombat

Ayrıca, iç veriler (çalışanlar, sistemad, vb.) Güvensiz olabilir. Yorumlama ile görüntülenen verileri (kayıt tarihi ve kullanıcı ile) tanımlamalı ve izlemelisiniz.
Samuel Dauzon

9

Tercih sırasına göre:

  1. Bir şablonlama motoru kullanıyorsanız (örn. Twig, Smarty, Blade), içeriğe duyarlı çıkış sağlayıp sağlamadığını kontrol edin. Twig'in deneyimlerinden biliyorum.{{ var|e('html_attr') }}
  2. HTML'ye izin vermek istiyorsanız, HTML Temizleyici'yi kullanın . Yalnızca Markdown veya ReStructuredText'i kabul ettiğinizi düşünseniz bile, yine de bu biçimlendirme dillerinin çıkardığı HTML'yi temizlemek istersiniz.
  3. Aksi takdirde, htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)belgenizin geri kalanıyla aynı karakter kümesini kullandığından emin olun $charset. Çoğu durumda, 'UTF-8'istenen karakter kümesidir.

Ayrıca, girişte değil çıkışta kaçtığınızdan emin olun .


7

Bunu çevrimdışı hale gelen SO Documentation beta konsolide bir referans olarak çapraz yayınlayın.

Sorun

Siteler arası komut dosyası oluşturma, bir web istemcisi tarafından uzaktan kodun istenmeden yürütülmesidir. Herhangi bir web uygulaması, bir kullanıcıdan girdi alıp doğrudan bir web sayfasında çıktı alırsa kendisini XSS'ye maruz bırakabilir. Giriş HTML veya JavaScript içeriyorsa, bu içerik web istemcisi tarafından oluşturulduğunda uzaktan kod yürütülebilir.

Örneğin, 3. taraf bir JavaScript dosyası içeriyorsa:

// http://example.com/runme.js
document.write("I'm running");

Ve bir PHP uygulaması doğrudan ona aktarılan bir dize çıkarır:

<?php
echo '<div>' . $_GET['input'] . '</div>';

Denetlenmeyen bir GET parametresi içeriyorsa <script src="http://example.com/runme.js"></script>, PHP betiğinin çıktısı şöyle olur:

<div><script src="http://example.com/runme.js"></script></div>

Üçüncü taraf JavaScript çalışır ve kullanıcı web sayfasında "Çalışıyorum" ifadesini görür.

Çözüm

Genel bir kural olarak, istemciden gelen girdilere asla güvenmeyin. Her GET, POST ve çerez değeri herhangi bir şey olabilir ve bu nedenle doğrulanmalıdır. Bu değerlerden herhangi birini verirken, beklenmedik bir şekilde değerlendirilmeyecek şekilde bu değerlerden çıkın.

En basit uygulamalarda bile verilerin hareket ettirilebileceğini ve tüm kaynakları takip etmenin zor olacağını unutmayın. Bu nedenle her zaman en iyi uygulama çıktıdan kaçmak .

PHP, bağlama bağlı olarak çıktıdan kaçmanın birkaç yolunu sunar.

Filtre İşlevleri

PHPs Filtre İşlevleri php komut dosyasına girdi veri izin arındırılmış veya valide içinde birçok yönden . İstemci girdisini kaydederken veya çıktısını alırken kullanışlıdırlar.

HTML Kodlaması

htmlspecialcharso zaman olur, yani kendi HTML kodlamaları içine herhangi bir "HTML özel karakterler" dönüştürür değil standart HTML olarak işlenebilir. Bu yöntemi kullanarak önceki örneğimizi düzeltmek için:

<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';

Çıktı:

<div>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

İçeride her şey <div>etiketi olacak değil ama bunun yerine basit bir metin düğümü olarak, tarayıcı tarafından bir JavaScript etiketi olarak yorumlanabilir. Kullanıcı güvenle görecektir:

<script src="http://example.com/runme.js"></script>

URL Kodlaması

Dinamik olarak oluşturulmuş bir URL çıktısı alırken, PHP urlencodegeçerli URL'leri güvenli bir şekilde çıktılamak için işlev sağlar . Örneğin, bir kullanıcı başka bir GET parametresinin parçası haline gelen verileri girebiliyorsa:

<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';

Kötü amaçlı girdiler kodlanmış bir URL parametresine dönüştürülür.

Özel harici kitaplıklar veya OWASP AntiSamy listelerini kullanma

Bazen HTML veya başka tür kod girişleri göndermek isteyebilirsiniz. Yetkili kelimelerin (beyaz liste) ve yetkisiz (kara liste) bir listesini tutmanız gerekir.

OWASP AntiSamy web sitesinde bulunan standart listeleri indirebilirsiniz . Her liste belirli bir etkileşim türüne uygundur (ebay api, tinyMCE, vb ...). Ve açık kaynak.

HTML'yi filtrelemek ve genel durum için XSS saldırılarını önlemek ve en az yanı sıra AntiSamy listelerini çok kolay bir şekilde kullanmak için kütüphaneler mevcuttur. Örneğin, HTML Temizleyiciniz var


5

Birçok çerçeve XSS'nin çeşitli şekillerde ele alınmasına yardımcı olur. Kendinizi yuvarlarken veya bazı XSS ​​endişeleri varsa, filter_input_array'den (PHP 5> = 5.2.0, PHP 7'de mevcuttur) yararlanabiliriz. verilerle etkileşime girer. Bu şekilde, tüm kullanıcı girdileri 1 merkezi konumda temizlenir. Bu, bir projenin başlangıcında veya veritabanınız zehirlenmeden önce yapılırsa, çıktı sırasında herhangi bir sorun yaşamamalısınız ... çöpü durdurur, çöpü dışarı çıkarır.

/* Prevent XSS input */
$_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;

Yukarıdaki TÜM HTML ve komut dosyası etiketlerini kaldıracaktır . Bir beyaz listeye dayalı olarak güvenli etiketlere izin veren bir çözüme ihtiyacınız varsa, HTML Temizleyiciye göz atın .


Veritabanınız zaten zehirliyse veya çıkış sırasında XSS ile uğraşmak istiyorsanız, OWASPecho , kullanıcı tarafından sağlanan değerleri HER YERDE kullanmanız için özel bir sarma işlevi oluşturmanızı önerir :

//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
   return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
   echo xssafe($data);
}

2

Ayrıca, XSS ile ilgili bazı HTTP yanıt başlıklarını header(...)

X-XSS Koruması "1; mod = blok"

emin olmak için tarayıcı XSS ​​koruma modu etkindir.

İçerik-Güvenlik-İlkesi "default-src 'self'; ..."

tarayıcı tarafı içerik güvenliğini etkinleştirmek için. İçerik Güvenliği İlkesi (CSP) ayrıntıları için buna bakın: http://content-security-policy.com/ Özellikle CSP'yi satır içi komut dosyalarını ve harici komut dosyası kaynaklarını engelleyecek şekilde ayarlamak XSS için yararlıdır.

web uygulamanızın güvenliğiyle ilgili genel HTTP yanıt üstbilgileri için OWASP'a bakın: https://www.owasp.org/index.php/List_of_useful_HTTP_headers


1
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Remove javascript: and vbscript: protocols
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do
{
    // Remove really unwanted tags
    $old_data = $data;
    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

// we are done...
return $data;
}

5
Girişinizde kullandığı preg_replaceşekilde kullanmamalısınız eval. owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_Injection
CrabLab

0

htmlspecialcharsÜzerinde kullanın PHP. HTML'de aşağıdakileri kullanmaktan kaçının:

element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);

burada varbir kullanıcı tarafından kontrol .

Ayrıca açıkça kaçınmaya çalışın eval(var), eğer bunlardan herhangi birini kullanmak zorunda sonra JS kaçan deneyin , HTML kaçmak ve biraz daha yapmak gerekebilir ama temelleri için bu yeterli olmalıdır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.