* XSRF – данни от чужд източник към форма
Публикувано на 06 декември 2008 в раздел ПТСК.
“Cross Site Request Forgery” е подход, който често използва XSS уязвимост в приложението, чрез която да се достигане компрометиране на самото приложение. Обикновено се използва потребител, на който приложението има “доверие” (например такъв с административни права). Обикновено атакуващият, като обикновен потребител, не би могъл сам да предизвика желания резултат и поради тази причина използва XSS уязвимост за изпълнение на заявка чрез друг потребител (с по-високи права). Следното видео демонстрира това:
xsrf демонстрация – изпълнение на скриптове чрез различни форми на дадено приложение.
Като един от най-големите осъществени пробиви ще споменем, че почти 18 милиона потребители са загубили лична информация през февруари 2008 от пробив в корейският eBay (информация от webappsec.org).
Остава въпросът – дали ако се защитим от всички XSS атаки, то ще бъдем защитени и от XRSF атаки? Не бихме се обвързали с потвърдителен отговор на този въпрос. Сега обаче ще демонстрираме един метод за защита на форми, чрез който можем ефективно да предотвратяваме XSRF атаки. Нека разгледаме следната примерна форма:
<html>
<head>
<title>WorldBank.dom XSRF vulnerable page</title>
</head>
<body>
<?php
if( isset($_REQUEST['submit'])){
echo 'Form is submitted';
}
else {
echo '<form action="xsrf.php" method="POST">';
echo '<input type="submit" name="submit">';
echo '</form><br><br><br>';
}
?>
</body>
</html>
Предполагаме, че този пример няма нужда от разяснения. Нека приемем, че той е качен на адрес worldbank.dom/xss.php. Когато отворите адреса в браузера и натиснете бутона, то ще се изпълни кода показващ “Form is submitted” на екрана.
HTML формите обаче имат едно свойство, че не проверяват източника на подаване на информацията. Направете следния опит – напишете следния html файл и го изпълнете от собствения си компютър:
<html> <head> <title>XSS attacker</title> </head> <body> <form action="http://worldbank.dom/xsrf.php" method="POST"> <input type="submit" name="submit"> </form><br><br><br> </body> </html>
Пуснете файла на личния си компютър и натиснете бутона. Ще изпратите POST информацията към worldbank.dom сървъра и ще попълните формата. Това очевидно не би трябвало да се случва – проверката на формата на сървъра би трябвало да очаква информацията към нея да бъде попълнена от сигурен източник. Как може да се уверим, че информацията е изпратена от самата форма?
Може би най-ефективният вариант е чрез използване на потребителска сесия. Като скрито поле вътре във формата трябва да запишем произволно генерирано число. Това число се записва и в потребителската сесия . Когато скрипта получи заявка, той трябва да сравни числото предадено чрез $_POST и да го сравни с това, записано в $_SESSION. Ето как бихме реализирали това с горния скрипт:
<?php
function security_start_session($ssl, $timeout, $maxtime, $ip){
// ... security checks
session_start();
session_regenerate_id(true);
return 1;
}
if (security_start_session(0, 6*60, 20*60, 1) != 1){
echo "<br>session destroyed!";
return;
}
?>
<html>
<head>
<title>WorldBank.dom XSRF protected page</title>
</head>
<body>
<?php
if( isset($_REQUEST['submit'])){
if ($_SESSION['token']!=$_POST['token'] || !isset($_SESSION['token']) || !isset($_POST['token'])){
session_unset();
session_destroy();
echo "Invalid session</body></html>";
return;
}
else{
echo 'Form is submitted';
}
}
else{
echo '<form action="xsrf.php" method="POST">';
$_SESSION['token'] = uniqid(rand(), true);
echo '<input type="hidden" name="token" value="'.$_SESSION['token'].'">';
echo '<input type="submit" name="submit">';
echo '</form><br><br><br>';
}
?>
</body></html>
Тук обезателно се налага стартирането на потребителска сесия (което тъй или иначе се прави в повечето случаи). Обърнете внимание на удебелените линии, където се генерира случайният token. Чрез него сме сигурни, че формата е попълнена именно от нашият сървър.
Другият често използван подход е проверката на “HTTP referer”. За PHP това става чрез environment променливата, записана като “$_SERVER['HTTP_REFERER']“. В нея се записва информацията откъде е дошла заявката. Вече споменахме, че тези HTTP header променливи не са надежден носител на данни (може да се направи spoof над тях). Въпреки това не можем да пуснем една такава допълнителна защита:
<?php
function security_start_session($ssl, $timeout, $maxtime, $ip){
// ... security checks
session_start();
session_regenerate_id(true);
return 1;
}
if (security_start_session(0, 6*60, 20*60, 1) != 1){
echo "<br>session destroyed!";
return;
}
?>
<html>
<head>
<title>WorldBank.dom XSRF protected page</title>
</head>
<body>
<?php
if( isset($_REQUEST['submit'])){
if ($_SESSION['token']!=$_POST['token'] || !isset($_SESSION['token']) || !isset($_POST['token'])){
session_unset();
session_destroy();
echo "Invalid session</body></html>";
return;
}
else{
if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER']!="http://worldbank.dom/xsrf.php"){
echo 'You are redirected by third party form - probably you are a XSRF attack victim!';
return;
}
else{
echo 'Form is submitted';
}
}
}
else{
echo '<form action="xsrf.php" method="POST">';
$_SESSION['token'] = uniqid(rand(), true);
echo '<input type="hidden" name="token" value="'.$_SESSION['token'].'">';
echo '<input type="submit" name="submit">';
echo '</form><br><br><br>';
}
?>
</body></html>
Имайте обаче в предвид, че сравнението по HTTP_REFERER header може да пропадне при някои proxy сървъри или ако клиента има строги настройки на своята защитна стена или антивирусна програма. Поради тази причина би трябвало да използвате тази допълнителна защита само при системи със конфиденциална информация (където едва ли очакваме анонимни потребители).
XSRF е проблем често срещан в приложения, които позволяват на потребителите си да “вмъкват” външни ресурси в системата. Това е често срещано при форуми, където потребителите могат да избират avatar от външен адрес, да вкарват снимки или видео клипове в своите posts. Проблемът с XSS там се решава лесно, като се забранят HTML символите, а вместо това се разреши единствено BBCode. За XSRF обаче решението не е толкова лесно.
Задача: Помислете как можете да реализирате ефективен филтър, който да разпознава дали URL, който трябва да сочи към картинка, не е всъщност връзка към скрипт.
2 коментара за “XSRF – данни от чужд източник към форма”
Trackback URI | RSS за коментарите
Пусни коментар
Категории
- Бази от Данни (52)
- Вероятности (31)
- История (15)
- Кучета (69)
- Лада Нива (96)
- Математика (166)
- Методика (53)
- Общи работи (110)
- ПИК-3 Java (38)
- Политика (41)
- Програмни Среди (1)
- ПТСК (41)
- С/C++ (45)
- Семейни (16)
- Физика (35)
- ХHTML/JS (25)
- Храна (11)
Нови
- Извеждане на няколко произволни реда
- Full-Text търсене с InnoDB в MySQL
- Късметче от кафе
- Пред блока…
- Бушонно табло на Лада Нива
28 януари 2011 на 15:56
Относно задачата:
Ще разгледам 2 варианта.
- Проверка на Mime Type на дадения файл. Предполагам, че може да се излъжe обаче.
- Ако снимката, ще се качва, предполагам, че ще има и умален размер. Ако не е валидна снимка, със сигурност ще даде грешка при оразмеряване и другите необходими функции за направа на thumb, и съответно няма да има качена снимка на сървъра в thumb размер. Съответно след проверка ще изпише, че снимката не е валидна. Това точи доста ресурс за съжаление. Някакви варианти да предложиш ти?
28 януари 2011 на 18:14
Мисля, че най-подходяща е функцията “getimagesize()”. А mime type се проверява задължително при всички положения!