Как я могу сделать мое приложение прослушивания TCP более безопасным? - PullRequest
0 голосов
/ 02 октября 2011

Я ищу совет по написанию очень безопасного приложения на C / C ++, которое будет слушать порт tcp. Я хотел бы взглянуть на то, что другие пытаются сделать с моей машиной, но я бы не стал устанавливать сложное приложение honeypot, если я могу делать то, что мне нужно, с очень короткой программой. Поскольку моя цель проста и безопасна, я хочу убедиться, что справляюсь по крайней мере со следующим: 1) Клиент не должен иметь возможность отправлять неограниченное количество данных,
2) Клиент (ы) не должен быть в состоянии перегрузить сервер слишком большим количеством соединений и
3) Клиент не должен иметь возможность держать соединение открытым бесконечно.
Поскольку моё текущее приложение маленькое и функциональное, сторонняя библиотека не кажется гарантированной для этого проекта. Однако небольшая библиотека, которая еще больше упростит приложение, будет интересной. Кроме того, я ожидаю, что стандартная библиотека C ++ может помочь в упрощении моего кода.

Ниже приведены некоторые ключевые функции из моей первоначальной попытки. Этот код компилируется в Windows, OSX и Linux.

Как сделать приложение безопаснее или проще?

void SafeClose(SOCKET s)
{
    if (s == INVALID_SOCKET)
        return;
    shutdown(s, SHUT_RDWR);
    closesocket(s);
}

void ProcessConnection(SOCKET sock, sockaddr_in *sockAddr)
{
    time_t time1;
    char szTime[TIME_BUF_SIZE];
    char readBuf[READ_BUF_SIZE];

    time(&time1);
    strftime(szTime, TIME_BUF_SIZE-1, "%Y/%m/%d %H:%M:%S", localtime(&time1)); 
    printf("%s - %s\n", szTime, inet_ntoa(sockAddr->sin_addr));
    usleep(1000000);       // Wait 1 second for client to send something
    int actualReadCount = recv(sock, readBuf, READ_BUF_SIZE-1, 0); 

    if (actualReadCount < 0 || actualReadCount >= READ_BUF_SIZE){
        actualReadCount = 0;
        strcpy(readBuf, "(Nothing)");
    } else {
        CleanString(readBuf, actualReadCount); // Replace non-printable characters
        readBuf[actualReadCount] = 0;
    }

    printf("%s\n\n", readBuf);
    SafeClose(sock);
}


int main(int argc, char* argv[])
{
    int             port            = 80;
    char            cmd[CMD_BUF_SIZE]   = {0};
    sockaddr_in     newSockAddr;
    sockaddr_in     localSockAddr;

    if(argc < 2){
        printf("Usage: safelisten PORT\n\n");
        return error_code;
    }

    error_code++;
    port = atoi(argv[1]); 
    BuildCleanAsciiMap(); // Used to replace non-printable characters

    localSockAddr.sin_family        = AF_INET;              
    localSockAddr.sin_addr.s_addr   = INADDR_ANY;           
    localSockAddr.sin_port          = htons(port);          
    sizeNewSockAddr                 = sizeof newSockAddr;

    CHK( listenSocket = socket(AF_INET, SOCK_STREAM, 0));
    CHK( setsockopt(listenSocket, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on)));
    CHK( bind(listenSocket, (sockaddr*)&localSockAddr, sizeof localSockAddr));
    CHK( listen(listenSocket, BACKLOG));
    CHK( SetNonBlocking(listenSocket));
    CHK( SetNonBlocking(0));        // Set STDIN to nonblocking for linux    
    printf ("Listening on port: %d\nEnter q to quit.\n\n", port);

    while(strcmp(cmd, "q")) // While the user has not entered q ...
    {
        newSocket = accept(listenSocket, (sockaddr*)&newSockAddr, &sizeNewSockAddr);
        ReadCmd(cmd, CMD_BUF_SIZE);

        if(newSocket == INVALID_SOCKET) { 
            // accept() would have blocked, thus we wait and try again
            usleep(10000);
            continue;   
        }

        // Set to nonblocking because we don't want the client to dictate how 
        // long we are connected.
        CHK( SetNonBlocking(newSocket)); 
        ProcessConnection(newSocket, &newSockAddr);
    }

    SafeClose(listenSocket);
    return 0;
}

1 Ответ

1 голос
/ 02 октября 2011

2) Клиент (ы) не должен быть в состоянии перегрузить сервер слишком большим количеством соединений ...

Ваш лучший вариант - разрешить маршрутизатору ограничивать количество подключений IPадрес означает, что к тому времени, когда ваша программа получает информацию о соединении, системные ресурсы уже распределены.

1) Клиент не должен иметь возможность отправлять неограниченное количество данных,

Наилучший вариант - иметь разумный максимум, который можно отправить, и просто отслеживать, сколько вы прочитали, и как только вы достигнете максимального предела, закройте соединение.

3) Клиент не должен иметь возможность держать соединение открытым бесконечно.

Для этого вы можете просто создать поток, который начнет обратный отсчет, поэтому, когда соединение было открыто для определенноговремя может истечь, и вы можете просто закрыть соединение.

Существуют и другие, более сложные решения, но я думаю, что это будет хорошей отправной точкой.

Если вы хотите что-то сделать с (2), сохраните хеш-карту в памяти и просто увеличьте количество выполненных соединений, но вы также можете отслеживать время.Вы хотите, чтобы структура данных была очень быстрой, поэтому вы можете решить, нужно ли вам отключить соединение раньше.

Например, если у вас есть два long в хэш-карте, вы можете указать время (в unixtime или тиках) первого соединения и увеличить его, и если вы получите 10 соединений менее чем за одну минуту,начать закрывать лишнее, пока не пройдет минута.Затем удалите этот элемент, если у него было достаточно продолжительное соединение, чтобы вы полагали, что он не атаковал вас.

Кроме того, убедитесь, что вы проверяете все передаваемые вам параметры и имеете разумные максимальные значения для любых строк.1025 *

...