Ataki XSS i formy obrony
Ataki XSS, polegają najczęściej na przekazaniu skryptu JavaScript, którego zadaniem jest zaszkodzić. Bronić się przed nimi można na wiele sposobów. W tym wpisie wykorzystuje ASP WebForms, ale wszystko co zostanie opisane można zastosować w aplikacjach ASP MVC.
Domyślnie strony ASP są chronione przed atakami XSS. Możemy się o tym przekonać budując prosty formularz z polem tekstowym w który można wpisać skrypt:
Przy próbie przesłania takiego formularza, serwer zwróci błąd:
Jest to spowodowane pewnym wpisem, lub jego brakiem (domyśla wartość true) w pliku web.config:
Niekiedy istnieje potrzeba wyłączenia tego mechanizmu (najczęściej na pojedynczych stronach w obrębie aplikacji), np. kiedy chcemy umożliwić użytkowniki formatowanie wpisów przy pomocy znacznik HTML.
Mam prosty formularz:
<form id="form1"> <div>Wpis</div> </form>
Jego obsługa:
protected void buttonSaveClick(Object sender, EventArgs e) { if(!string.IsNullOrEmpty(textBoxXss.Text)) { literalXss.Text = "Twój wpis to: " + textBoxXss.Text; } }
Całość po wpisaniu skryptu JavaScript wygląda tak:
Jak się bronić? Jest wiele sposobów. Jednym z nich jest użycie funkcji Server.HtmlEncode:
literalXss.Text = "Twój wpis to: " + Server.HtmlEncode(textBoxXss.Text);
Jak widać działa, ale co zrobić gdy chcemy formatować tekst np. przy pomocy znaczników „<b>” czy „<i>”? Można zrobić taki trik:
StringBuilder sb = new StringBuilder(HttpUtility.HtmlEncode(textBoxXss.Text)); sb.Replace("<b>", "<b>"); sb.Replace("</b>", "</b>"); sb.Replace("<i>", "<i>"); sb.Replace("</i>", "</i>"); literalXss.Text = "Twój wpis to: " + sb.ToString();
Wybiórcze dodawanie dozwolonych tagów, może być nieco kłopotliwe, w miarę zwiększania ich ilości. Żeby temu zaradzić można napisać metodę RemoveXss, która wykorzystuje wyrażenia regularne:
public string RemoveXss(string input) { string result = RemoveXssHtmlTags(input); result = RemoveOnXssAttribute(result); return result; } public string RemoveXssHtmlTags(string input) { string result = Regex.Replace( input, @"<!--?(?i:applet|body|embed|frame|script|frameset|html|iframe|img|style|layer|link|ilayer|meta|object)(.|\n|\s)*?-->", string.Empty, RegexOptions.Singleline | RegexOptions.IgnoreCase ); return result; } public string RemoveOnXssAttribute(string input) { string result = Regex.Replace( input, @"(<[\s\S]*?) on.*?\=(['""])[\s\S]*?\2([\s\S]*?>)", delegate(Match match) { return String.Concat(match.Groups[1].Value, match.Groups[3].Value); }, RegexOptions.Compiled | RegexOptions.IgnoreCase); return result; }
Jej użycie jest bardzo proste:
literalXss.Text = "Twój wpis to: " + RemoveXss(textBoxXss.Text);