19 смертных грехов, угрожающих безопасности программ
Шрифт:
2) при выводе данных применяйте HTML–кодирование.
Необходимо принимать обе эти меры предосторожности в своих программах. В приведенных ниже примерах показано, как это делается на практике.
Искупление греха в ISAPI–расширениях и фильтрах на C/C++
Во фрагменте ниже приведен код для HTML–кодирования информации, отправляемой браузеру.
/////////////////////////////////////////////////////////////////
// HtmlEncode
// Кодирует поток HTML-данных
// Аргументы
// strRaw: указатель на необработанные HTML-данные
// result: ссылка на результат, хранящийся в std::string
// Возвращаемое значение:
// false: не удалось закодировать HTML-данные
// true: все HTML-данные закодированы
bool HtmlEncode(char *strRaw, std::string &result) {
size_t iLen = 0;
size_t i = 0;
if (strRaw && (iLen = strlen(strRaw))) {
for (i = 0; i < iLen; i++)
switch(strRaw[i]) {
case \'\0\' : break;
case \'<\' : result.append("<"); break;
case \'>\' : result.append(">"); break;
case \'(\' : result.append("("); break;
case \')\' : result.append(")"); break;
case \'#\' : result.append("#"); break;
case \'&\' : result.append("&"); break;
case \'"\' : result.append("""); break;
default : result.append(1,strRaw[i]); break;
}
}
return i == iLen ? true : false;
}
Если
Искупление греха в ASP
Применяйте сочетание регулярных выражений (в данном случает объект RegExp в сценарии на VBScript) и HTML–кодирования для проверки входных данных:
<%
name = Request.QueryString("Name")
Set r = new ReqExp
r.Pattern = "^\w{5,25}$"
r.IgnoreCase = True
Set m = r.Execute(name)
If (len(m(0)) > 0) Then
Response.Write(Server.HTMLEncode(name))
End If
%>
Искупление греха в ASP. NET
Приведенный ниже код аналогичен предыдущему примеру, но для сопоставления с регулярным выражением и HTML–кодирования используется язык С# и библиотеки, входящие в каркас .NET Framework.
using System.Web; // Необходимо добавить ссылку на сборку System.Web.dll
private void btnSubmit_Click(object sender, System.EventArgs e)
{
Regex r = new Regex(@"^\w{5,25}");
if (r.Match(txtValue.Text).Success) {
Application.Lock;
Application.txtName.Text = txtValue.Text;
Application.UnLock;
lblName.Text = "Hello, " +
HttpUtility.HtmlEncode(txtName.Text);
} else {
lblName.Text = "Кто вы?";
}
}
Искупление греха в JSP
В JSP имеет смысл использовать нестандартный тег. Вот код тега, осуществляющего HTML–кодирование:
import java.IO.Exception;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class HtmlEncoderTag extends BodyTagSupport {
public HtmlEncoderTag {
super;
}
public int doAfterBody throws JspException {
if (bodyContent != null) {
System.out.println(bodyContent.getString);
String contents = bodyContent.getString;
String regExp = new String("^\\w{5,25}$");
// Сопоставить с регулярным выражением
if (contents.matches(regExp)) {
try {
bodyContent.getEnclosingWriter.write(contents);
} catch (IOException e) {
System.out.println("Ошибка ввода/вывода");
}
return EVAL_BODY_INCLUDE;
} else {
try {
bodyContent.getEnclosingWriter.write(encode(contents));
} catch (IOException e) {
System.out.println("Ошибка ввода/вывода");
}
System.out.println("Содержимое: " + contents.toString);
return EVAL_BODY_INCLUDE;
}
} else {
return EVAL_BODY_INCLUDE;
}
}
// В JSP нет функции для HTML-кодирования
public static String encode(String str) {
if (str == null)
return null;
StringBuffer s = new StringBuffer;
for (short i = 0; i < str.length; i++) {
char c = str.CharAt(i);
switch (c) {
case \'<\':
s.append("<");
break;
case \'>\':
s.append(">");
break;
case \'(\':
s.append("(");
break;
case \')\':
s.append(")");
break;
case \'#\':
s.append("#");
break;
case \'&\':
s.append("&");
break;
case \'"\':
s.append(""");
break;
default:
s.append(c);
}
}
return s.toString;
}
}
Ну
и наконец пример JSP)страницы, из которой вызывается определенный выше тег:<%@ taglib uri="/tags/htmlencoder" prefix="htmlencoder" %>
<head>
<title>Покайся, грешник...</title>
</head>
<html>
<body bgcolor="white">
<htmlencoder:htmlencode><script
type="javascript">BadStuff</script></htmlencoder:htmlencode>
<htmlencoder:htmlencode>testing</htmlencoder:htmlencode>
<script type="badStuffNotWrapped"></script>
</body>
</html>
Искупление греха в PHP
Как и в остальных примерах, мы применяем оба лекарства: проверяем входные данные, а затем HTML)кодируем выводимую информацию с помощью функции htmlentities:
<?php
$name = $_GET[\'name\'];
if (isset($name)) {
if (preg_match(\'\^w{5,25}$/\',$name)) {
echo "Hello, " . htmlentities($name);
} else {
echo "Вон отсюда!";
}
}
?>
Искупление греха в Perl/CGI
Идея та же, что в предыдущих примерах: проверить входные данные, сопоставив их с регулярным выражением, а затем HTML–кодировать выводимую информацию.
#!/usr/bin/perl
use CGI;
use HTML::Entities;
use strict;
my $cgi = new CGI;
print CGI::header;
my $name = $cgi->param(\'name\');
if ($name =~ /^\w{5,25}$/) {
print "Hello, " . HTML::Entities::encode($name);
} else {
print "Вон отсюда!";
}
Если вы не хотите или не можете загрузить модуль HTML::Entities, то вот эк)
вивалентный код для решения той же задачи:
sub html_encode
{
my $in = shift;
$in =~ s/&/&/g;
$in =~ s/</</g;
$in =~ s/>/>/g;
$in =~ s/\»/"/g;
$in =~ s/#/#/g;
$in =~ s/\(/(/g;
$in =~ s/\)/)/g;
return $in;
}
Искупление греха в mod–perl
Как и выше, мы проверяем корректность входных данных и HTML–кодируем выходные.
#!/usr/bin/perl
use Apache::Util;
use Apache::Request;
use strict;
my $apr = Apache::Request->new(Apache->request);
my $name = $apr->param(\'name\');
$apr->content_type(\'text/html\');
$apr->send_http_header;
if ($name =~/^\w{5,25}$/) {
$apr->print("Hello, " . Apache::Util::html_encode($name);
} else {
$apr->print "Вон отсюда!";
}
Замечание по поводу HTML–кодирования
Прямолинейное HTML–кодирование всей выводимой информации для некоторых Web–сайтов представляется драконовской мерой, поскольку такие теги, как <1> или <В> безвредны. Чтобы несколько ослабить путы, подумайте, не стоит ли «декодировать» заведомо безопасные конструкции. Следующий фрагмент кода на С# иллюстрирует, что автор называет «HTML–декодированием» тегов, описывающих курсив, полужирный шрифт, начало абзаца, выделение и заголовки:
Regex.Replace(s,
@"<(/?)(i|b|p|em|h\d{1})>",
"<$1$2>",
RegexOptions.IgnoreCase);
Дополнительные защитные меры
В Web–приложение можно включить много дополнительных механизмов защиты на случай, если вы пропустили XSS–ошибку, а именно:
□ добавить в кук атрибут httponly. Это спасет пользователей Internet Explorer версии (6.0) (и последующих), поскольку помеченный таким образом кук невозможно прочитать с помощью свойства document.cookie. Подробнее см. ссылки в разделе «Другие ресурсы». В ASP.NET 2.0 добавлено свойство HttpCookie.HttpOnly, упрощающее решение этой задачи;