如何在Symfony2中创建IP黑名单?

时间:2011-11-21 20:40:35

标签: php symfony

是的,我知道有Voter tutorial in cookbook。但我正在寻找一些略有不同的东西。我需要两个不同的黑名单层:

  1. 拒绝某些IP访问整个网站
  2. 拒绝某些IP登录
  3. 我写了Voter,检查用户的IP是否在数据库中。对于第一个场景,我编写了一个内核侦听器,它检查每个请求并在遇到被禁用户时抛出403:

    if (VoterInterface::ACCESS_DENIED === $this->voter->vote($token, $this, array())) {
        throw new AccessDeniedHttpException('Blacklisted, punk!');
    }
    

    第一个问题在于VoterInterface本身,这迫使我使用TokenInterface $token,在这种情况下我并不需要dev。但我觉得这并不重要。接下来就是我实际上不得不使用AccessDeniedHttpException因为AccessDeniedException总是试图将我重定向到登录页面并导致无限重定向循环。我会使用它,因为它在prod环境中运行得很好,但是当我切换到\Exception时,我会继续在生成日志中获得503:

      

    [2011-11-21 20:54:04] security.INFO:用一个填充的SecurityContext   匿名令牌[] []

         

    [2011-11-21 20:54:04] request.ERROR:   Symfony的\分量\ HttpKernel \异常\ AccessDeniedHttpException:   黑名单,朋克! (未捕获的例外)在xxx第28行[] []

         

    [2011-11-21 20:54:04] request.ERROR:处理时抛出异常   例外   (Symfony的\元器件\ HttpKernel \异常\ AccessDeniedHttpException:   黑名单,朋克!)[] []

    从我读过的内容来看,xdebug可能存在问题,但即使我将其关闭也会发生。我也尝试了香草{{1}},它做了同样的事情。任何人都知道为什么会这样?或者对于这种黑名单案例可能有其他一些解决方案。

    另外,我不知道如何解决第二种情况,因为我不知道如何在获得令牌之前停止用户。我当前的解决方案是处理InteractiveLoginEvent,检查用户是否被列入黑名单,如果是,则删除他的令牌。它似乎并不安全,我对此并不满意。那么,任何想法如何解决这个问题?我想我只是错过了一些明显的“登录前事件”。

6 个答案:

答案 0 :(得分:4)

要拒绝访问整个网站,您可以调整用于保护开发环境的白名单代码。在app.php中粘贴这样的东西:

if (in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '1.2.3.4',))) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this site.');
}

答案 1 :(得分:4)

对于站点范围的IP限制,最好在apache级别处理它们,因此您的应用程序甚至不会受到请求的影响。如果您试图阻止垃圾邮件发送者,这样您就不会在有时自动化的请求上浪费任何资源。在您的情况下,将拒绝规则写入.htaccess文件是合适的。在较大的设置中,您还可以配置防火墙以阻止特定的IP,以便这些请求甚至根本不会访问您的服务器。

答案 2 :(得分:4)

对于第一个问题 - 有filters in EventDispatcher,因此您可以在Controller启动进程请求之前抛出AccessDeniedHttpException

要解决第二个问题 - 如果您使用custom User Provider,则可以在UserRepository中检查禁止的IP地址。

namespace Acme\SecurityBundle\Entity;
//… some namespaces
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * UserRepository
 */
class UserRepository extends … implements …
{

    public function loadUserByUsername($username)
    {
        if ( $this->isBanned() ) {
            throw new AccessDeniedHttpException("You're banned!");
        }
        //… load user from DB
    }

    //… some other methods

    private function isBanned()
    {
        $q = $this->getEntityManager()->createQuery('SELECT b FROM AcmeSecurityBundle:BlackList b WHERE b.ip = :ip')
            ->setParameter('ip', @$_SERVER['REMOTE_ADDR'])
            ->setMaxResults(1)
        ;
        $blackList = $q->getOneOrNullResult();

        //… check if is banned
    }

}

答案 3 :(得分:1)

您也可以在服务器上使用防火墙,例如:http://www.shorewall.net/blacklisting_support.htm 它完全阻止服务器的给定ips。

自动生成这样的黑名单文件,请看下面的例子: http://www.justin.my/2010/08/generate-shorewall-blacklist-from-spamhaus-and-dshield/

答案 4 :(得分:1)

您可以使用我的bundle =>轻松阻止IP和IP范围https://github.com/Spomky-Labs/SpomkyIpFilterBundle

答案 5 :(得分:0)

这不是最佳做法。 Insight(由Sensio分析)返回:“不鼓励使用PHP响应函数(如此处的header()),因为它绕过了Symfony事件系统。请改用HttpFoundationResponse类。”并且“不应该使用$ _SERVER超级全局。”

<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$loader = require_once __DIR__.'/../app/bootstrap.php.cache';

require_once __DIR__.'/../app/AppKernel.php';


$request = Request::createFromGlobals();

$client_ip = $request->getClientIp();
$authorized_hosts = ['127.0.0.1', 'fe80::1', '::1', 'localhost', 'yourIpAddress'];

// Securisation
if (!in_array($client_ip, $authorized_hosts)) {
    $response = new Response(
        "Forbidden",
        Response::HTTP_FORBIDDEN,
        array('content-type' => 'text/html')
    );
    $response->send();
    exit();
}

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

适用于SensioInsight