Как средствами PHP защититься от накрутки кол-ва загрузок файла?

При каждой загрузке файла поле downloads увеличивается на 1.
Статистика конечно ведется, но очень легко накрутить ее просто перейдя огромное кол-во раз по ссылке с загрузкой файла.

Как делают защиту от накруток в таких случаях?

Мои идеи такие:
1) Разрешить загружать файл не чаще чем раз в N секунд. (Ужасная идея)

2) Раздавать файл всегда, но увеличивать счетчик не чаще раза в N секунд. (Начинает теряться смысл счетчика)

3) Увеличивать счетчик только если с момента загрузки конкретного файла с этого IP прошло более N секунд. (Довольно большая нагрузка на бд, при каждом запросе файла: поиск по IP, ID файла и времени большего чем N сек. от loaddate. В cron каждые N минут чистить этот лог загрузок).
  • Вопрос задан
  • 3442 просмотра
Решения вопроса 1
@kaasius
А файло отдается как?
Исходя из предположения, что с одного ip нет большого смысла скачивать файл более одного раза, то ограничивающий фактор будет ip. Далее делаем так:
На фронт nginx, и делаем локейшн, в котором лежат файлы.
location ^~ /user_files { # Это где реально лежат файлы
        internal;
        root /path/to/folder;
}
location ^~ /userfiles { # Это то, куда указывают ссылки на сайте
        proxy_pass  http://127.0.0.1:80;
}


Обрабатываете локейшн /userfiles в php и отдаете заголовки X-Accel-Redirect, чтобы статику отдавал энджи.

Дальше, как считать.

Если стоит memcache - делаем add($fileid.$ip,1) - если ключ уже установлен, add вернет false, и счетчик увеличивать не надо, если не установлен - надо увеличить счетчик. Ключ при этом установится. Счетчик увеличиваем соответственно так: inc("counter/".$fileid,1)

Если стоит redis - все очень похоже. Делаем setnx($fileid.$ip,1) - если ключ установлен, вернет false. Если нет - ключ установится. Счетчик увеличиваем incr("counter/".$fileid,1). Но redis так же может помочь сильно сэкономить память. Для этого надо использовать не строки, а хеши. То есть стейт храним как hsetnx($fileid,$ip,1). А счетчик в этом случае храним как hincrby("counters",$fileid,1). Это даст перед мемкешем следующие преимущества:
1. Драматическая экономия памяти. Хеши c короткими ключами и значениями весьма эффективно расходуют память.
2. Сайд-эффект - очень просто посмотреть, с каких ip загружали файл - hgetall($fileid). Если еще немного модифицировать алгоритм так: hincrby($fileid,$ip,1) - будем получать на выходе целое значение - количество закачек с этого ip - так можно попалить накрутчиков и просто банить их по ip.
3. Сайд-эффект - очень просто получить таблицу всех счетчиков файлов - hgetall("counters").

Ну и все это, разумеется, очень быстро. Делать то же самое в sql базе, думаю, сложновато. Но если сильно хочется - может заморочиться кто-то еще, и расписать алгоритм для мускуля. А мы поржом.

Если ограничивать по пользователям (кукам), что на мой взгляд не очень, то все делается ровно так же, только вместо ip используем id, который записан в сессии. Тогда использовать хеши для хранения состояния не удачная мысль - надо хранить в строках, и ставить им expire - время жизни сессии, или, там, сутки - как угодно.
Ответ написан
Пригласить эксперта
Ответы на вопрос 6
Можете базу заменить на Redis (для хранения ip и данных по загрузкам), будет быстрей и меньше нагрузки.

Еще как вариант можете использовать Evercookie, чтобы пользователям было напряжней чистить куки, а для отсечения большей части ботов установить test_cookie для nginx. Большею часть накруток думаю можно будет скинуть. Матерые с ботами эмулирующими браузеры будет отсеить сложней, но если проявить смекалку, то тоже можно устроить им проблем.
Ответ написан
dvachek
@dvachek
Храните лог ip:state в memcache - нулевая нагрузка, 100% результат. Лог можно чистить каждые 24 ч.
Ответ написан
Комментировать
sergiks
@sergiks Куратор тега PHP
♬♬
  • раз в N минут анализируйте скриптом лог веб-сервера, подсчитывая записи о загрузке файла, которые увенчались успехом, а не оборвались – и только по ним увеличивайте счётчики
  • Limit IP connections для скачиваемых файлов — с одного IP смогут скачивать не чаще напр. 3 в минуту
Ответ написан
Комментировать
street
@street
Backend developer
Если статистика ведется в БД, можно проверять, было ли уже скачивание этого файла (если пользователь авторизован).
Если пользователь не авторизован, можно записывать в сессию статус загрузки по идентификатору файла (к примеру $_SESSION['file_x'] = 1) после загрузки, и увеличивать счетчик, если значение в сессии пустое.
Ответ написан
Комментировать
opium
@opium
Просто люблю качественно работать
вставьте защиту по смс.
Ответ написан
Комментировать
KOLANICH
@KOLANICH
Знаю JS, PHP, C++, C#
поставьте капчу
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы